]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
Fail to generate random bytes instead of falling back to rand()
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Thu, 14 May 2015 11:23:09 +0000 (12:23 +0100)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Thu, 14 May 2015 13:30:30 +0000 (14:30 +0100)
This is more robust against broken setups where we run out
of memory or cannot read /dev/urandom.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=90414
Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
[smcv: document @error]
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
12 files changed:
bus/activation.c
dbus/dbus-auth.c
dbus/dbus-file-unix.c
dbus/dbus-file-win.c
dbus/dbus-internals.c
dbus/dbus-keyring.c
dbus/dbus-nonce.c
dbus/dbus-server-unix.c
dbus/dbus-sysdeps-unix.c
dbus/dbus-sysdeps-win.c
dbus/dbus-sysdeps.c
dbus/dbus-sysdeps.h

index 390b8362cd3110dd8806301a7614248241b8e290..679a40eb9e126612a9ddf959b2bd937f6918e482 100644 (file)
@@ -2608,7 +2608,7 @@ bus_activation_service_reload_test (const DBusString *test_data_dir)
     return FALSE;
 
   if (!_dbus_string_append (&directory, "/dbus-reload-test-") ||
-      !_dbus_generate_random_ascii (&directory, 6))
+      !_dbus_generate_random_ascii (&directory, 6, NULL))
      {
        return FALSE;
      }
index 1503d5f1f74fc8af3cf168fcc8650a4784ce6679..f2227875a4c28c8f04806271fcee9b4f6c01cccc 100644 (file)
@@ -524,10 +524,8 @@ sha1_handle_first_client_response (DBusAuth         *auth,
    */
   DBusString tmp;
   DBusString tmp2;
-  dbus_bool_t retval;
-  DBusError error;
-  
-  retval = FALSE;
+  dbus_bool_t retval = FALSE;
+  DBusError error = DBUS_ERROR_INIT;
 
   _dbus_string_set_length (&auth->challenge, 0);
   
@@ -578,7 +576,6 @@ sha1_handle_first_client_response (DBusAuth         *auth,
   
   if (auth->keyring == NULL)
     {
-      dbus_error_init (&error);
       auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity,
                                                          &auth->context,
                                                          &error);
@@ -610,7 +607,6 @@ sha1_handle_first_client_response (DBusAuth         *auth,
 
   _dbus_assert (auth->keyring != NULL);
 
-  dbus_error_init (&error);
   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
   if (auth->cookie_id < 0)
     {
@@ -640,8 +636,25 @@ sha1_handle_first_client_response (DBusAuth         *auth,
   if (!_dbus_string_append (&tmp2, " "))
     goto out;  
   
-  if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
-    goto out;
+  if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error))
+    {
+      if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+        {
+          dbus_error_free (&error);
+          goto out;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (&error);
+          _dbus_verbose ("%s: Error generating challenge: %s\n",
+                         DBUS_AUTH_NAME (auth), error.message);
+          if (send_rejected (auth))
+            retval = TRUE; /* retval is only about mem */
+
+          dbus_error_free (&error);
+          goto out;
+        }
+    }
 
   _dbus_string_set_length (&auth->challenge, 0);
   if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
@@ -826,7 +839,7 @@ handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
    * name, the cookie ID, and the server challenge, separated by
    * spaces. We send back our challenge string and the correct hash.
    */
-  dbus_bool_t retval;
+  dbus_bool_t retval = FALSE;
   DBusString context;
   DBusString cookie_id_str;
   DBusString server_challenge;
@@ -835,9 +848,8 @@ handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
   DBusString tmp;
   int i, j;
   long val;
-  
-  retval = FALSE;                 
-  
+  DBusError error = DBUS_ERROR_INIT;
+
   if (!_dbus_string_find_blank (data, 0, &i))
     {
       if (send_error (auth,
@@ -903,9 +915,6 @@ handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
 
   if (auth->keyring == NULL)
     {
-      DBusError error;
-
-      dbus_error_init (&error);
       auth->keyring = _dbus_keyring_new_for_credentials (NULL,
                                                          &context,
                                                          &error);
@@ -942,9 +951,28 @@ handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
   
   if (!_dbus_string_init (&tmp))
     goto out_3;
-  
-  if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
-    goto out_4;
+
+  if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error))
+    {
+      if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+        {
+          dbus_error_free (&error);
+          goto out_4;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (&error);
+
+          _dbus_verbose ("%s: Failed to generate challenge: %s\n",
+                         DBUS_AUTH_NAME (auth), error.message);
+
+          if (send_error (auth, "Failed to generate challenge"))
+            retval = TRUE; /* retval is only about mem */
+
+          dbus_error_free (&error);
+          goto out_4;
+        }
+    }
 
   if (!_dbus_string_init (&client_challenge))
     goto out_4;
index 197593362b7c6d3556889fac4801d92ef066ed36..830d3fe408894dcac7887b0022b255f8bc69a056 100644 (file)
@@ -202,9 +202,9 @@ _dbus_string_save_to_file (const DBusString *str,
     }
 
 #define N_TMP_FILENAME_RANDOM_BYTES 8
-  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
+  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES,
+                                    error))
     {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       _dbus_string_free (&tmp_filename);
       return FALSE;
     }
index 06a8ea1ced4a74d103d495c3679a2b46968442d4..0dbe11eca3899789fc6ad8a801576366d6761d4c 100644 (file)
@@ -251,9 +251,9 @@ _dbus_string_save_to_file (const DBusString *str,
     }
 
 #define N_TMP_FILENAME_RANDOM_BYTES 8
-  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
+  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES,
+                                    error))
     {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       _dbus_string_free (&tmp_filename);
       return FALSE;
     }
index 24e070d1126b06eefcec3b9fb709dd8ad6c5ae71..30a5fa73bc91d091f8b8aa2493dada8631b2b67c 100644 (file)
@@ -653,8 +653,11 @@ dbus_bool_t
 _dbus_generate_uuid (DBusGUID  *uuid,
                      DBusError *error)
 {
+  DBusError rand_error;
   long now;
 
+  dbus_error_init (&rand_error);
+
   /* don't use monotonic time because the UUID may be saved to disk, e.g.
    * it may persist across reboots
    */
@@ -662,7 +665,16 @@ _dbus_generate_uuid (DBusGUID  *uuid,
 
   uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
   
-  _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4);
+  if (!_dbus_generate_random_bytes_buffer (uuid->as_bytes,
+                                           DBUS_UUID_LENGTH_BYTES - 4,
+                                           &rand_error))
+    {
+      dbus_set_error (error, rand_error.name,
+                      "Failed to generate UUID: %s", rand_error.message);
+      dbus_error_free (&rand_error);
+      return FALSE;
+    }
+
   return TRUE;
 }
 
index f0c64de3ebc50d20ff71b27c29f942b4deddc171..bb7e4f8d04f495abc4a633f315c14ff6a3bab5de 100644 (file)
@@ -304,11 +304,8 @@ add_new_key (DBusKey  **keys_p,
   /* Generate an integer ID and then the actual key. */
  retry:
       
-  if (!_dbus_generate_random_bytes (&bytes, 4))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      goto out;
-    }
+  if (!_dbus_generate_random_bytes (&bytes, 4, error))
+    goto out;
 
   s = (const unsigned char*) _dbus_string_get_const_data (&bytes);
       
@@ -329,9 +326,8 @@ add_new_key (DBusKey  **keys_p,
       
 #define KEY_LENGTH_BYTES 24
   _dbus_string_set_length (&bytes, 0);
-  if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES))
+  if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES, error))
     {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       goto out;
     }
 
index e5685e168d8b7c21108e9023cb7461acdfecd082..3c0f6f374a865bb39bbbeac1a9ee5a873501aed0 100644 (file)
@@ -186,9 +186,8 @@ generate_and_write_nonce (const DBusString *filename, DBusError *error)
       return FALSE;
     }
 
-  if (!_dbus_generate_random_bytes (&nonce, 16))
+  if (!_dbus_generate_random_bytes (&nonce, 16, error))
     {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       _dbus_string_free (&nonce);
       return FALSE;
     }
@@ -272,9 +271,8 @@ do_noncefile_create (DBusNonceFile *noncefile,
         goto on_error;
       }
 
-    if (!_dbus_generate_random_ascii (&randomStr, 8))
+    if (!_dbus_generate_random_ascii (&randomStr, 8, error))
       {
-        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
         goto on_error;
       }
 
index 5474177a6353940706603ebe510e13766002df75..92664a8dc199ec490e340c1088101a3eaffc8185 100644 (file)
@@ -152,10 +152,22 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
             }
 
-          if (!_dbus_string_append (&filename,
-                                    "dbus-") ||
-              !_dbus_generate_random_ascii (&filename, 10) ||
-              !_dbus_string_append (&full_path, tmpdir) ||
+          if (!_dbus_string_append (&filename, "dbus-"))
+            {
+              _dbus_string_free (&full_path);
+              _dbus_string_free (&filename);
+              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+            }
+
+          if (!_dbus_generate_random_ascii (&filename, 10, error))
+            {
+              _dbus_string_free (&full_path);
+              _dbus_string_free (&filename);
+              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+            }
+
+          if (!_dbus_string_append (&full_path, tmpdir) ||
               !_dbus_concat_dir_and_file (&full_path, &filename))
             {
               _dbus_string_free (&full_path);
index c9dbe7ba2804678ecda149af137ba65aa52d2e1b..dc0418cb136d9f49e4b59463a0decfab1bf4f76e 100644 (file)
@@ -3003,61 +3003,55 @@ _dbus_sleep_milliseconds (int milliseconds)
 #endif
 }
 
-static dbus_bool_t
-_dbus_generate_pseudorandom_bytes (DBusString *str,
-                                   int         n_bytes)
-{
-  int old_len;
-  char *p;
-
-  old_len = _dbus_string_get_length (str);
-
-  if (!_dbus_string_lengthen (str, n_bytes))
-    return FALSE;
-
-  p = _dbus_string_get_data_len (str, old_len, n_bytes);
-
-  _dbus_generate_pseudorandom_bytes_buffer (p, n_bytes);
-
-  return TRUE;
-}
-
 /**
- * Generates the given number of random bytes,
+ * Generates the given number of securely random bytes,
  * using the best mechanism we can come up with.
  *
  * @param str the string
  * @param n_bytes the number of random bytes to append to string
- * @returns #TRUE on success, #FALSE if no memory
+ * @param error location to store reason for failure
+ * @returns #TRUE on success, #FALSE on error
  */
 dbus_bool_t
 _dbus_generate_random_bytes (DBusString *str,
-                             int         n_bytes)
+                             int         n_bytes,
+                             DBusError  *error)
 {
   int old_len;
   int fd;
-
-  /* FALSE return means "no memory", if it could
-   * mean something else then we'd need to return
-   * a DBusError. So we always fall back to pseudorandom
-   * if the I/O fails.
-   */
+  int result;
 
   old_len = _dbus_string_get_length (str);
   fd = -1;
 
   /* note, urandom on linux will fall back to pseudorandom */
   fd = open ("/dev/urandom", O_RDONLY);
+
   if (fd < 0)
-    return _dbus_generate_pseudorandom_bytes (str, n_bytes);
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "Could not open /dev/urandom: %s",
+                      _dbus_strerror (errno));
+      return FALSE;
+    }
 
   _dbus_verbose ("/dev/urandom fd %d opened\n", fd);
 
-  if (_dbus_read (fd, str, n_bytes) != n_bytes)
+  result = _dbus_read (fd, str, n_bytes);
+
+  if (result != n_bytes)
     {
+      if (result < 0)
+        dbus_set_error (error, _dbus_error_from_errno (errno),
+                        "Could not read /dev/urandom: %s",
+                        _dbus_strerror (errno));
+      else
+        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
+                        "Short read from /dev/urandom");
+
       _dbus_close (fd, NULL);
       _dbus_string_set_length (str, old_len);
-      return _dbus_generate_pseudorandom_bytes (str, n_bytes);
+      return FALSE;
     }
 
   _dbus_verbose ("Read %d bytes from /dev/urandom\n",
index 143470abf425c35a54558b0d3cffd3feb2b5e602..b3b459f81a8258bf83ec10779408266d87cee93e 100644 (file)
@@ -2253,11 +2253,13 @@ _dbus_create_directory (const DBusString *filename,
  *
  * @param str the string
  * @param n_bytes the number of random bytes to append to string
- * @returns #TRUE on success, #FALSE if no memory
+ * @param error location to store reason for failure
+ * @returns #TRUE on success
  */
 dbus_bool_t
 _dbus_generate_random_bytes (DBusString *str,
-                             int         n_bytes)
+                             int         n_bytes,
+                             DBusError  *error)
 {
   int old_len;
   char *p;
@@ -2266,15 +2268,22 @@ _dbus_generate_random_bytes (DBusString *str,
   old_len = _dbus_string_get_length (str);
 
   if (!_dbus_string_lengthen (str, n_bytes))
-    return FALSE;
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
 
   p = _dbus_string_get_data_len (str, old_len, n_bytes);
 
   if (!CryptAcquireContext (&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
-    return FALSE;
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
 
   if (!CryptGenRandom (hprov, n_bytes, p))
     {
+      _DBUS_SET_OOM (error);
       CryptReleaseContext (hprov, 0);
       return FALSE;
     }
index 997921008482ce9c76347f2af1a3fd7baa401d16..8b986d58a16fc8095935a76d18a614abd1e4119c 100644 (file)
@@ -504,63 +504,37 @@ _dbus_string_parse_uint (const DBusString *str,
  * @{
  */
 
-void
-_dbus_generate_pseudorandom_bytes_buffer (char *buffer,
-                                          int   n_bytes)
-{
-  long tv_usec;
-  int i;
-  
-  /* fall back to pseudorandom */
-  _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
-                 n_bytes);
-  
-  _dbus_get_real_time (NULL, &tv_usec);
-  srand (tv_usec);
-  
-  i = 0;
-  while (i < n_bytes)
-    {
-      double r;
-      unsigned int b;
-          
-      r = rand ();
-      b = (r / (double) RAND_MAX) * 255.0;
-
-      buffer[i] = b;
-
-      ++i;
-    }
-}
-
 /**
  * Fills n_bytes of the given buffer with random bytes.
  *
  * @param buffer an allocated buffer
  * @param n_bytes the number of bytes in buffer to write to
+ * @param error location to store reason for failure
+ * @returns #TRUE on success
  */
-void
-_dbus_generate_random_bytes_buffer (char *buffer,
-                                    int   n_bytes)
+dbus_bool_t
+_dbus_generate_random_bytes_buffer (char      *buffer,
+                                    int        n_bytes,
+                                    DBusError *error)
 {
   DBusString str;
 
   if (!_dbus_string_init (&str))
     {
-      _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
-      return;
+      _DBUS_SET_OOM (error);
+      return FALSE;
     }
 
-  if (!_dbus_generate_random_bytes (&str, n_bytes))
+  if (!_dbus_generate_random_bytes (&str, n_bytes, error))
     {
       _dbus_string_free (&str);
-      _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
-      return;
+      return FALSE;
     }
 
   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
 
   _dbus_string_free (&str);
+  return TRUE;
 }
 
 /**
@@ -569,18 +543,20 @@ _dbus_generate_random_bytes_buffer (char *buffer,
  *
  * @param str the string
  * @param n_bytes the number of random ASCII bytes to append to string
+ * @param error location to store reason for failure
  * @returns #TRUE on success, #FALSE if no memory or other failure
  */
 dbus_bool_t
 _dbus_generate_random_ascii (DBusString *str,
-                             int         n_bytes)
+                             int         n_bytes,
+                             DBusError  *error)
 {
   static const char letters[] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
   int i;
   int len;
   
-  if (!_dbus_generate_random_bytes (str, n_bytes))
+  if (!_dbus_generate_random_bytes (str, n_bytes, error))
     return FALSE;
   
   len = _dbus_string_get_length (str);
index f6a2948ec19ddb745b9b19d17a8443d65d478643..7043a452b0c5d7d6736f354746d012def5cf1cc9 100644 (file)
@@ -476,15 +476,17 @@ const char* _dbus_get_tmpdir      (void);
 /**
  * Random numbers 
  */
-void        _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
-                                                      int   n_bytes);
-void        _dbus_generate_random_bytes_buffer (char       *buffer,
-                                                int         n_bytes);
+_DBUS_GNUC_WARN_UNUSED_RESULT
+dbus_bool_t _dbus_generate_random_bytes_buffer (char       *buffer,
+                                                int         n_bytes,
+                                                DBusError  *error);
 dbus_bool_t _dbus_generate_random_bytes        (DBusString *str,
-                                                int         n_bytes);
+                                                int         n_bytes,
+                                                DBusError  *error);
 DBUS_PRIVATE_EXPORT
 dbus_bool_t _dbus_generate_random_ascii        (DBusString *str,
-                                                int         n_bytes);
+                                                int         n_bytes,
+                                                DBusError  *error);
 
 DBUS_PRIVATE_EXPORT
 const char* _dbus_error_from_errno (int error_number);