From fe1e7672efdf22eeb5cbe30d6adc485bc55fa021 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Thu, 23 Jul 2026 09:44:31 +0200 Subject: [PATCH] utils: Replace GRand with cryptographically secure random generator (CVE-2026-16615) The GRand is not supposed to be used for cryptography, replace it with a cryptographically secure random generator and require it to be available during the setup phase. The library will abort in case the runtime cannot create a random number (only for rare cases where the very last fallback to /dev/urandom fails to read from the device, which is used on some old platforms). Fixes https://gitlab.gnome.org/GNOME/librest/-/issues/25 --- meson.build | 29 ++++++++++++++++++++ rest/meson.build | 2 +- rest/rest-utils.c | 70 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 4e2a272..2919fb6 100644 --- a/meson.build +++ b/meson.build @@ -60,6 +60,8 @@ libsoup_dep = dependency(libsoup_name, version: libsoup_req_version) libjson_glib_dep = dependency('json-glib-1.0') libxml_dep = dependency('libxml-2.0') +cc = meson.get_compiler('c') + # config.h conf = configuration_data() conf.set_quoted('PACKAGE_NAME', meson.project_name()) @@ -68,6 +70,33 @@ conf.set_quoted('PACKAGE_VERSION', meson.project_version()) if get_option('ca_certificates') conf.set_quoted('REST_SYSTEM_CA_FILE', ca_certificates_path) endif + +# CSPRNG detection for secure random string generation (required) +have_csprng = false +if cc.has_function('arc4random_buf', prefix: '#include ') + conf.set('HAVE_ARC4RANDOM_BUF', 1) + have_csprng = true +endif +if cc.has_function('getrandom', prefix: '#include ') + conf.set('HAVE_GETRANDOM', 1) + have_csprng = true +endif + +csprng_deps = [] +if host_machine.system() == 'windows' + bcrypt_lib = cc.find_library('bcrypt', required: false) + if bcrypt_lib.found() + csprng_deps += bcrypt_lib + conf.set('HAVE_BCRYPTGENRANDOM', 1) + have_csprng = true + endif +endif + +if not have_csprng + error('No cryptographically secure random source found. ' + + 'librest requires arc4random_buf(), getrandom(), or BCryptGenRandom().') +endif + config_h = configure_file(output: 'config.h', configuration: conf) root_inc = include_directories('.') config_dep = declare_dependency( diff --git a/rest/meson.build b/rest/meson.build index bfecb9f..1c1cbd5 100644 --- a/rest/meson.build +++ b/rest/meson.build @@ -62,7 +62,7 @@ librest_deps = [ libjson_glib_dep, libxml_dep, config_dep, -] +] + csprng_deps librest_c_args = [ '-DG_LOG_DOMAIN="Rest"', diff --git a/rest/rest-utils.c b/rest/rest-utils.c index df283e0..346c83b 100644 --- a/rest/rest-utils.c +++ b/rest/rest-utils.c @@ -16,29 +16,89 @@ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" #include "rest-utils.h" +#ifdef HAVE_ARC4RANDOM_BUF +#include +#endif + +#ifdef HAVE_GETRANDOM +#include +#include +#endif + +#ifdef HAVE_BCRYPTGENRANDOM +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +#if defined(HAVE_ARC4RANDOM_BUF) + +static void +crypto_random_bytes (guchar *buffer, + gsize length) +{ + arc4random_buf (buffer, length); +} + +#elif defined(HAVE_BCRYPTGENRANDOM) + +static void +crypto_random_bytes (guchar *buffer, + gsize length) +{ + BCryptGenRandom (NULL, buffer, (ULONG) length, + BCRYPT_USE_SYSTEM_PREFERRED_RNG); +} + +#elif defined(HAVE_GETRANDOM) + +static void +crypto_random_bytes (guchar *buffer, + gsize length) +{ + gsize pos = 0; + + while (pos < length) + { + gssize ret = getrandom (buffer + pos, length - pos, 0); + if (ret < 0) + { + if (errno == EINTR) + continue; + g_error ("getrandom() failed: %s", g_strerror (errno)); + } + pos += (gsize) ret; + } +} + +#endif /* platform selection */ + /** * random_string: * @length: the length of the random string * - * Creates a random string from a given alphabeth with length @length + * Creates a random string from a given alphabet with length @length. * * Returns: (transfer full): a random string */ gchar * random_string (guint length) { - g_autoptr(GRand) rand = g_rand_new (); gchar *buffer = g_malloc0 (sizeof (gchar) * length + 1); - gchar alphabeth[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"; + gchar alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"; + guint alphabet_len = sizeof (alphabet) - 1; + g_autofree guchar *rand_bytes = g_malloc (length); + + crypto_random_bytes (rand_bytes, length); for (guint i = 0; i < length; i++) { - buffer[i] = alphabeth[g_rand_int (rand) % (sizeof (alphabeth) - 1)]; + buffer[i] = alphabet[rand_bytes[i] % alphabet_len]; } buffer[length] = '\0'; return buffer; } - -- GitLab