summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2015-05-14 12:23:09 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2015-05-14 14:30:30 +0100
commitbcdead0fd4642a5e8985981c1583d40ff779299a (patch)
tree2285d47c351a1a07bb22f060293f641b711d5785
parentf385324d8b03eab13f3e618ce9a0018977c9a7cb (diff)
downloaddbus-bcdead0fd4642a5e8985981c1583d40ff779299a.tar.gz
Fail to generate random bytes instead of falling back to rand()
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>
-rw-r--r--bus/activation.c2
-rw-r--r--dbus/dbus-auth.c64
-rw-r--r--dbus/dbus-file-unix.c4
-rw-r--r--dbus/dbus-file-win.c4
-rw-r--r--dbus/dbus-internals.c14
-rw-r--r--dbus/dbus-keyring.c10
-rw-r--r--dbus/dbus-nonce.c6
-rw-r--r--dbus/dbus-server-unix.c20
-rw-r--r--dbus/dbus-sysdeps-unix.c56
-rw-r--r--dbus/dbus-sysdeps-win.c17
-rw-r--r--dbus/dbus-sysdeps.c54
-rw-r--r--dbus/dbus-sysdeps.h14
12 files changed, 146 insertions, 119 deletions
diff --git a/bus/activation.c b/bus/activation.c
index 390b8362..679a40eb 100644
--- a/bus/activation.c
+++ b/bus/activation.c
@@ -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;
}
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index 1503d5f1..f2227875 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -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;
diff --git a/dbus/dbus-file-unix.c b/dbus/dbus-file-unix.c
index 19759336..830d3fe4 100644
--- a/dbus/dbus-file-unix.c
+++ b/dbus/dbus-file-unix.c
@@ -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;
}
diff --git a/dbus/dbus-file-win.c b/dbus/dbus-file-win.c
index 06a8ea1c..0dbe11ec 100644
--- a/dbus/dbus-file-win.c
+++ b/dbus/dbus-file-win.c
@@ -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;
}
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index 24e070d1..30a5fa73 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -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;
}
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index f0c64de3..bb7e4f8d 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -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;
}
diff --git a/dbus/dbus-nonce.c b/dbus/dbus-nonce.c
index e5685e16..3c0f6f37 100644
--- a/dbus/dbus-nonce.c
+++ b/dbus/dbus-nonce.c
@@ -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;
}
diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c
index 5474177a..92664a8d 100644
--- a/dbus/dbus-server-unix.c
+++ b/dbus/dbus-server-unix.c
@@ -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);
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index c9dbe7ba..dc0418cb 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -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",
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index 143470ab..b3b459f8 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -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;
}
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 99792100..8b986d58 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -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);
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index f6a2948e..7043a452 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -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);