]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libuuid: check quality of random bytes
authorSamanta Navarro <ferivoz@riseup.net>
Sun, 8 Nov 2020 11:47:18 +0000 (11:47 +0000)
committerSamanta Navarro <ferivoz@riseup.net>
Sun, 8 Nov 2020 11:48:23 +0000 (11:48 +0000)
If a libuuid application is unable to access /dev/random or /dev/urandom
then uuid generation by uuid_generate falls back to uuid_generate_time.
This could happen in chroot or container environments.

The function ul_random_get_bytes from lib/randutils.c uses getrandom if
it is available. This could either mean that the libuuid application
skips good random bytes because the character special files do not exist
or the application trusts in good random bytes just because these files
are accessible but not necessarily usable, e.g. limit of open file
descriptors reached, lack of data, kernel without getrandom, etc.

This commit modifies ul_random_get_bytes to return an integer which
indicates if random bytes are of good quality (0) or not (1). Callers
can decide based on this information if they want to discard the random
bytes. Only libuuid checks the return value. I decided to return 1
instead of -1 because -1 feels more like an error, but weak random bytes
can be totally fine.

Another issue is that getrandom sets errno to specific values only in
case of an error, i.e. with return value -1. Set errno to 0 explicitly
if getrandom succeeds so we do not enter the fallback routine for
ENOSYS by mistake. I do not think that this is likely to happen, but it
really depends on possible wrapper function supplied by a C library.

Signed-off-by: Samanta Navarro <ferivoz@riseup.net>
include/randutils.h
lib/randutils.c
libuuid/man/uuid_generate.3
libuuid/src/gen_uuid.c
libuuid/src/uuidd.h

index 5b863d04ca6c060bed83cad8d5eb95d66854765e..690bf5e545b65c66e8b8e330f91aed4dfad76b5d 100644 (file)
@@ -11,7 +11,7 @@ extern int rand_get_number(int low_n, int high_n);
 
 /* /dev/urandom based with fallback to rand() */
 extern int random_get_fd(void);
-extern void ul_random_get_bytes(void *buf, size_t nbytes);
+extern int ul_random_get_bytes(void *buf, size_t nbytes);
 extern const char *random_tell_source(void);
 
 #endif
index b473577af597159683d96d279b444f3beeca7dbe..39edf4e78935cc395f260e47f4c5898c43088b81 100644 (file)
@@ -102,7 +102,12 @@ int random_get_fd(void)
 #define UL_RAND_READ_ATTEMPTS  8
 #define UL_RAND_READ_DELAY     125000  /* microseconds */
 
-void ul_random_get_bytes(void *buf, size_t nbytes)
+/*
+ * Write @nbytes random bytes into @buf.
+ *
+ * Returns 0 for good quality of random bytes or 1 for weak quality.
+ */
+int ul_random_get_bytes(void *buf, size_t nbytes)
 {
        unsigned char *cp = (unsigned char *)buf;
        size_t i, n = nbytes;
@@ -118,7 +123,7 @@ void ul_random_get_bytes(void *buf, size_t nbytes)
                       n -= x;
                       cp += x;
                       lose_counter = 0;
-
+                      errno = 0;
                } else if (errno == ENOSYS) {   /* kernel without getrandom() */
                        break;
 
@@ -177,6 +182,8 @@ void ul_random_get_bytes(void *buf, size_t nbytes)
                       sizeof(ul_jrand_seed)-sizeof(unsigned short));
        }
 #endif
+
+       return n != 0;
 }
 
 
index 0043c625f64565589b004d0648c68b1969ae1399..dccecd658947518cb34008b676909bc7530ea46a 100644 (file)
@@ -49,7 +49,10 @@ The
 .B uuid_generate
 function creates a new universally unique identifier (UUID).  The uuid will
 be generated based on high-quality randomness from
+.IR getrandom(2) ,
 .IR /dev/urandom ,
+or
+.IR /dev/random
 if available.  If it is not available, then
 .B uuid_generate
 will use an alternative algorithm which uses the current time, the
@@ -59,8 +62,7 @@ using a pseudo-random generator.
 The
 .B uuid_generate_random
 function forces the use of the all-random UUID format, even if
-a high-quality random number generator (i.e.,
-.IR /dev/urandom )
+a high-quality random number generator
 is not available, in which case a pseudo-random
 generator will be substituted.  Note that the use of a pseudo-random
 generator may compromise the uniqueness of UUIDs
index 50039fc2e6141a2e92b7205aa0552a217fabc519..d353fa1a0082eea248c5ba6dcf266f8d154a4762 100644 (file)
@@ -499,11 +499,11 @@ int uuid_generate_time_safe(uuid_t out)
 }
 
 
-void __uuid_generate_random(uuid_t out, int *num)
+int __uuid_generate_random(uuid_t out, int *num)
 {
        uuid_t  buf;
        struct uuid uu;
-       int i, n;
+       int i, n, r = 0;
 
        if (!num || !*num)
                n = 1;
@@ -511,7 +511,8 @@ void __uuid_generate_random(uuid_t out, int *num)
                n = *num;
 
        for (i = 0; i < n; i++) {
-               ul_random_get_bytes(buf, sizeof(buf));
+               if (ul_random_get_bytes(buf, sizeof(buf)))
+                       r = -1;
                uuid_unpack(buf, &uu);
 
                uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
@@ -520,6 +521,8 @@ void __uuid_generate_random(uuid_t out, int *num)
                uuid_pack(&uu, out);
                out += sizeof(uuid_t);
        }
+
+       return r;
 }
 
 void uuid_generate_random(uuid_t out)
@@ -531,27 +534,15 @@ void uuid_generate_random(uuid_t out)
 }
 
 /*
- * Check whether good random source (/dev/random or /dev/urandom)
- * is available.
- */
-static int have_random_source(void)
-{
-       return (access("/dev/random", R_OK) == 0 ||
-               access("/dev/urandom", R_OK) == 0);
-}
-
-
-/*
- * This is the generic front-end to uuid_generate_random and
- * uuid_generate_time.  It uses uuid_generate_random only if
- * /dev/urandom is available, since otherwise we won't have
- * high-quality randomness.
+ * This is the generic front-end to __uuid_generate_random and
+ * uuid_generate_time.  It uses __uuid_generate_random output
+ * only if high-quality randomness is available.
  */
 void uuid_generate(uuid_t out)
 {
-       if (have_random_source())
-               uuid_generate_random(out);
-       else
+       int num = 1;
+
+       if (__uuid_generate_random(out, &num))
                uuid_generate_time(out);
 }
 
index e55c86f2f314460a177e661739fa2da6a0c30b75..fbe821ff3fcd62023697a9886fc59a43769201d7 100644 (file)
@@ -49,6 +49,6 @@
 #define UUIDD_MAX_OP                   UUIDD_OP_BULK_RANDOM_UUID
 
 extern int __uuid_generate_time(uuid_t out, int *num);
-extern void __uuid_generate_random(uuid_t out, int *num);
+extern int __uuid_generate_random(uuid_t out, int *num);
 
 #endif /* _UUID_UUID_H */