random(4): use arc4random_ctx_buf() for large device reads

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

random(4): use arc4random_ctx_buf() for large device reads

Christian Weisgerber
(This is in a different part of the file from Theo's current efforts.)

For large reads from /dev/random, use the arc4random_ctx_*() functions
instead of hand-rolling the same code to set up a temporary ChaCha
instance.

ok?


Index: rnd.c
===================================================================
RCS file: /cvs/src/sys/dev/rnd.c,v
retrieving revision 1.213
diff -u -p -r1.213 rnd.c
--- rnd.c 18 May 2020 15:00:16 -0000 1.213
+++ rnd.c 24 May 2020 15:54:00 -0000
@@ -589,6 +589,9 @@ arc4random_ctx_free(struct arc4random_ct
 void
 arc4random_ctx_buf(struct arc4random_ctx *ctx, void *buf, size_t n)
 {
+#ifndef KEYSTREAM_ONLY
+ memset(buf, 0, n);
+#endif
  chacha_encrypt_bytes((chacha_ctx *)ctx, buf, buf, n);
 }
 
@@ -701,8 +704,7 @@ randomclose(dev_t dev, int flag, int mod
 int
 randomread(dev_t dev, struct uio *uio, int ioflag)
 {
- u_char lbuf[KEYSZ+IVSZ];
- chacha_ctx lctx;
+ struct arc4random_ctx *lctx;
  size_t total = uio->uio_resid;
  u_char *buf;
  int myctx = 0, ret = 0;
@@ -712,29 +714,23 @@ randomread(dev_t dev, struct uio *uio, i
 
  buf = malloc(POOLBYTES, M_TEMP, M_WAITOK);
  if (total > RND_MAIN_MAX_BYTES) {
- arc4random_buf(lbuf, sizeof(lbuf));
- chacha_keysetup(&lctx, lbuf, KEYSZ * 8);
- chacha_ivsetup(&lctx, lbuf + KEYSZ, NULL);
- explicit_bzero(lbuf, sizeof(lbuf));
+ lctx = arc4random_ctx_new();
  myctx = 1;
  }
 
  while (ret == 0 && uio->uio_resid > 0) {
  size_t n = ulmin(POOLBYTES, uio->uio_resid);
 
- if (myctx) {
-#ifndef KEYSTREAM_ONLY
- memset(buf, 0, n);
-#endif
- chacha_encrypt_bytes(&lctx, buf, buf, n);
- } else
+ if (myctx)
+ arc4random_ctx_buf(lctx, buf, n);
+ else
  arc4random_buf(buf, n);
  ret = uiomove(buf, n, uio);
  if (ret == 0 && uio->uio_resid > 0)
  yield();
  }
  if (myctx)
- explicit_bzero(&lctx, sizeof(lctx));
+ arc4random_ctx_free(lctx);
  explicit_bzero(buf, POOLBYTES);
  free(buf, M_TEMP, POOLBYTES);
  return ret;
--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: random(4): use arc4random_ctx_buf() for large device reads

Theo de Raadt-2
Makes sense to me.


Christian Weisgerber <[hidden email]> wrote:

> (This is in a different part of the file from Theo's current efforts.)
>
> For large reads from /dev/random, use the arc4random_ctx_*() functions
> instead of hand-rolling the same code to set up a temporary ChaCha
> instance.
>
> ok?
>
>
> Index: rnd.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/rnd.c,v
> retrieving revision 1.213
> diff -u -p -r1.213 rnd.c
> --- rnd.c 18 May 2020 15:00:16 -0000 1.213
> +++ rnd.c 24 May 2020 15:54:00 -0000
> @@ -589,6 +589,9 @@ arc4random_ctx_free(struct arc4random_ct
>  void
>  arc4random_ctx_buf(struct arc4random_ctx *ctx, void *buf, size_t n)
>  {
> +#ifndef KEYSTREAM_ONLY
> + memset(buf, 0, n);
> +#endif
>   chacha_encrypt_bytes((chacha_ctx *)ctx, buf, buf, n);
>  }
>  
> @@ -701,8 +704,7 @@ randomclose(dev_t dev, int flag, int mod
>  int
>  randomread(dev_t dev, struct uio *uio, int ioflag)
>  {
> - u_char lbuf[KEYSZ+IVSZ];
> - chacha_ctx lctx;
> + struct arc4random_ctx *lctx;
>   size_t total = uio->uio_resid;
>   u_char *buf;
>   int myctx = 0, ret = 0;
> @@ -712,29 +714,23 @@ randomread(dev_t dev, struct uio *uio, i
>  
>   buf = malloc(POOLBYTES, M_TEMP, M_WAITOK);
>   if (total > RND_MAIN_MAX_BYTES) {
> - arc4random_buf(lbuf, sizeof(lbuf));
> - chacha_keysetup(&lctx, lbuf, KEYSZ * 8);
> - chacha_ivsetup(&lctx, lbuf + KEYSZ, NULL);
> - explicit_bzero(lbuf, sizeof(lbuf));
> + lctx = arc4random_ctx_new();
>   myctx = 1;
>   }
>  
>   while (ret == 0 && uio->uio_resid > 0) {
>   size_t n = ulmin(POOLBYTES, uio->uio_resid);
>  
> - if (myctx) {
> -#ifndef KEYSTREAM_ONLY
> - memset(buf, 0, n);
> -#endif
> - chacha_encrypt_bytes(&lctx, buf, buf, n);
> - } else
> + if (myctx)
> + arc4random_ctx_buf(lctx, buf, n);
> + else
>   arc4random_buf(buf, n);
>   ret = uiomove(buf, n, uio);
>   if (ret == 0 && uio->uio_resid > 0)
>   yield();
>   }
>   if (myctx)
> - explicit_bzero(&lctx, sizeof(lctx));
> + arc4random_ctx_free(lctx);
>   explicit_bzero(buf, POOLBYTES);
>   free(buf, M_TEMP, POOLBYTES);
>   return ret;
> --
> Christian "naddy" Weisgerber                          [hidden email]
>

Reply | Threaded
Open this post in threaded view
|

Re: random(4): use arc4random_ctx_buf() for large device reads

Sebastien Marie-3
In reply to this post by Christian Weisgerber
On Sun, May 24, 2020 at 09:33:27PM +0200, Christian Weisgerber wrote:
> (This is in a different part of the file from Theo's current efforts.)
>
> For large reads from /dev/random, use the arc4random_ctx_*() functions
> instead of hand-rolling the same code to set up a temporary ChaCha
> instance.
>
> ok?

ok semarie@

Eventually, I would get ride of myctx, initialize lctx to NULL, and use
(lctx == NULL) to replace (myctx == 0). But feel free to discard my remark.

>
> Index: rnd.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/rnd.c,v
> retrieving revision 1.213
> diff -u -p -r1.213 rnd.c
> --- rnd.c 18 May 2020 15:00:16 -0000 1.213
> +++ rnd.c 24 May 2020 15:54:00 -0000
> @@ -589,6 +589,9 @@ arc4random_ctx_free(struct arc4random_ct
>  void
>  arc4random_ctx_buf(struct arc4random_ctx *ctx, void *buf, size_t n)
>  {
> +#ifndef KEYSTREAM_ONLY
> + memset(buf, 0, n);
> +#endif
>   chacha_encrypt_bytes((chacha_ctx *)ctx, buf, buf, n);
>  }
>  
> @@ -701,8 +704,7 @@ randomclose(dev_t dev, int flag, int mod
>  int
>  randomread(dev_t dev, struct uio *uio, int ioflag)
>  {
> - u_char lbuf[KEYSZ+IVSZ];
> - chacha_ctx lctx;
> + struct arc4random_ctx *lctx;
>   size_t total = uio->uio_resid;
>   u_char *buf;
>   int myctx = 0, ret = 0;
> @@ -712,29 +714,23 @@ randomread(dev_t dev, struct uio *uio, i
>  
>   buf = malloc(POOLBYTES, M_TEMP, M_WAITOK);
>   if (total > RND_MAIN_MAX_BYTES) {
> - arc4random_buf(lbuf, sizeof(lbuf));
> - chacha_keysetup(&lctx, lbuf, KEYSZ * 8);
> - chacha_ivsetup(&lctx, lbuf + KEYSZ, NULL);
> - explicit_bzero(lbuf, sizeof(lbuf));
> + lctx = arc4random_ctx_new();
>   myctx = 1;
>   }
>  
>   while (ret == 0 && uio->uio_resid > 0) {
>   size_t n = ulmin(POOLBYTES, uio->uio_resid);
>  
> - if (myctx) {
> -#ifndef KEYSTREAM_ONLY
> - memset(buf, 0, n);
> -#endif
> - chacha_encrypt_bytes(&lctx, buf, buf, n);
> - } else
> + if (myctx)
> + arc4random_ctx_buf(lctx, buf, n);
> + else
>   arc4random_buf(buf, n);
>   ret = uiomove(buf, n, uio);
>   if (ret == 0 && uio->uio_resid > 0)
>   yield();
>   }
>   if (myctx)
> - explicit_bzero(&lctx, sizeof(lctx));
> + arc4random_ctx_free(lctx);
>   explicit_bzero(buf, POOLBYTES);
>   free(buf, M_TEMP, POOLBYTES);
>   return ret;
> --
> Christian "naddy" Weisgerber                          [hidden email]
>

--
Sebastien Marie

Reply | Threaded
Open this post in threaded view
|

Re: random(4): use arc4random_ctx_buf() for large device reads

Christian Weisgerber
Sebastien Marie:

> > For large reads from /dev/random, use the arc4random_ctx_*() functions
> > instead of hand-rolling the same code to set up a temporary ChaCha
> > instance.
>
> Eventually, I would get ride of myctx, initialize lctx to NULL, and use
> (lctx == NULL) to replace (myctx == 0).

Right.  Here we go:

Index: rnd.c
===================================================================
RCS file: /cvs/src/sys/dev/rnd.c,v
retrieving revision 1.213
diff -u -p -r1.213 rnd.c
--- rnd.c 18 May 2020 15:00:16 -0000 1.213
+++ rnd.c 25 May 2020 14:58:43 -0000
@@ -589,6 +589,9 @@ arc4random_ctx_free(struct arc4random_ct
 void
 arc4random_ctx_buf(struct arc4random_ctx *ctx, void *buf, size_t n)
 {
+#ifndef KEYSTREAM_ONLY
+ memset(buf, 0, n);
+#endif
  chacha_encrypt_bytes((chacha_ctx *)ctx, buf, buf, n);
 }
 
@@ -701,40 +704,31 @@ randomclose(dev_t dev, int flag, int mod
 int
 randomread(dev_t dev, struct uio *uio, int ioflag)
 {
- u_char lbuf[KEYSZ+IVSZ];
- chacha_ctx lctx;
+ struct arc4random_ctx *lctx = NULL;
  size_t total = uio->uio_resid;
  u_char *buf;
- int myctx = 0, ret = 0;
+ int ret = 0;
 
  if (uio->uio_resid == 0)
  return 0;
 
  buf = malloc(POOLBYTES, M_TEMP, M_WAITOK);
- if (total > RND_MAIN_MAX_BYTES) {
- arc4random_buf(lbuf, sizeof(lbuf));
- chacha_keysetup(&lctx, lbuf, KEYSZ * 8);
- chacha_ivsetup(&lctx, lbuf + KEYSZ, NULL);
- explicit_bzero(lbuf, sizeof(lbuf));
- myctx = 1;
- }
+ if (total > RND_MAIN_MAX_BYTES)
+ lctx = arc4random_ctx_new();
 
  while (ret == 0 && uio->uio_resid > 0) {
  size_t n = ulmin(POOLBYTES, uio->uio_resid);
 
- if (myctx) {
-#ifndef KEYSTREAM_ONLY
- memset(buf, 0, n);
-#endif
- chacha_encrypt_bytes(&lctx, buf, buf, n);
- } else
+ if (lctx != NULL)
+ arc4random_ctx_buf(lctx, buf, n);
+ else
  arc4random_buf(buf, n);
  ret = uiomove(buf, n, uio);
  if (ret == 0 && uio->uio_resid > 0)
  yield();
  }
- if (myctx)
- explicit_bzero(&lctx, sizeof(lctx));
+ if (lctx != NULL)
+ arc4random_ctx_free(lctx);
  explicit_bzero(buf, POOLBYTES);
  free(buf, M_TEMP, POOLBYTES);
  return ret;
--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: random(4): use arc4random_ctx_buf() for large device reads

Sebastien Marie-3
On Mon, May 25, 2020 at 05:27:37PM +0200, Christian Weisgerber wrote:

> Sebastien Marie:
>
> > > For large reads from /dev/random, use the arc4random_ctx_*() functions
> > > instead of hand-rolling the same code to set up a temporary ChaCha
> > > instance.
> >
> > Eventually, I would get ride of myctx, initialize lctx to NULL, and use
> > (lctx == NULL) to replace (myctx == 0).
>
> Right.  Here we go:

Thanks. ok semarie@
 

> Index: rnd.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/rnd.c,v
> retrieving revision 1.213
> diff -u -p -r1.213 rnd.c
> --- rnd.c 18 May 2020 15:00:16 -0000 1.213
> +++ rnd.c 25 May 2020 14:58:43 -0000
> @@ -589,6 +589,9 @@ arc4random_ctx_free(struct arc4random_ct
>  void
>  arc4random_ctx_buf(struct arc4random_ctx *ctx, void *buf, size_t n)
>  {
> +#ifndef KEYSTREAM_ONLY
> + memset(buf, 0, n);
> +#endif
>   chacha_encrypt_bytes((chacha_ctx *)ctx, buf, buf, n);
>  }
>  
> @@ -701,40 +704,31 @@ randomclose(dev_t dev, int flag, int mod
>  int
>  randomread(dev_t dev, struct uio *uio, int ioflag)
>  {
> - u_char lbuf[KEYSZ+IVSZ];
> - chacha_ctx lctx;
> + struct arc4random_ctx *lctx = NULL;
>   size_t total = uio->uio_resid;
>   u_char *buf;
> - int myctx = 0, ret = 0;
> + int ret = 0;
>  
>   if (uio->uio_resid == 0)
>   return 0;
>  
>   buf = malloc(POOLBYTES, M_TEMP, M_WAITOK);
> - if (total > RND_MAIN_MAX_BYTES) {
> - arc4random_buf(lbuf, sizeof(lbuf));
> - chacha_keysetup(&lctx, lbuf, KEYSZ * 8);
> - chacha_ivsetup(&lctx, lbuf + KEYSZ, NULL);
> - explicit_bzero(lbuf, sizeof(lbuf));
> - myctx = 1;
> - }
> + if (total > RND_MAIN_MAX_BYTES)
> + lctx = arc4random_ctx_new();
>  
>   while (ret == 0 && uio->uio_resid > 0) {
>   size_t n = ulmin(POOLBYTES, uio->uio_resid);
>  
> - if (myctx) {
> -#ifndef KEYSTREAM_ONLY
> - memset(buf, 0, n);
> -#endif
> - chacha_encrypt_bytes(&lctx, buf, buf, n);
> - } else
> + if (lctx != NULL)
> + arc4random_ctx_buf(lctx, buf, n);
> + else
>   arc4random_buf(buf, n);
>   ret = uiomove(buf, n, uio);
>   if (ret == 0 && uio->uio_resid > 0)
>   yield();
>   }
> - if (myctx)
> - explicit_bzero(&lctx, sizeof(lctx));
> + if (lctx != NULL)
> + arc4random_ctx_free(lctx);
>   explicit_bzero(buf, POOLBYTES);
>   free(buf, M_TEMP, POOLBYTES);
>   return ret;
> --
> Christian "naddy" Weisgerber                          [hidden email]

--
Sebastien Marie