From 4e298f2fe77be4c9268c29450dfc68e842a2720d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 Feb 2023 15:21:24 +0100 Subject: [PATCH] pipewire: add pw_random() Make pw_getrandom() more usable by handling the EINTR case and returning < 0 when there was an error or not enough random data was available. Make a new pw_random() function that uses pw_getrandom() but falls back to a pseudo random number generator otherwise. This pseudo random number generator is seeded with either data from the urandom source or from the current time when pipewire is initialized. In most cases where crytographic security is not required pw_random() should be easier to use. --- src/modules/module-avb/maap.c | 6 +-- src/pipewire/impl-core.c | 12 +----- src/pipewire/pipewire.c | 2 + src/pipewire/private.h | 2 + src/pipewire/utils.c | 69 ++++++++++++++++++++++++++++++----- src/pipewire/utils.h | 4 ++ 6 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/modules/module-avb/maap.c b/src/modules/module-avb/maap.c index c57477e41..2a78b30ba 100644 --- a/src/modules/module-avb/maap.c +++ b/src/modules/module-avb/maap.c @@ -400,10 +400,8 @@ struct avb_maap *avb_maap_register(struct server *server) maap->server = server; pw_log_info("0x%"PRIx64" %d", server->entity_id, server->ifindex); - if (pw_getrandom(maap->xsubi, sizeof(maap->xsubi), 0) != sizeof(maap->xsubi)) { - res = -errno; - goto error_free; - } + pw_random(maap->xsubi, sizeof(maap->xsubi)); + load_state(maap); maap->source = pw_loop_add_io(server->impl->loop, fd, SPA_IO_IN, true, on_socket_data, maap); diff --git a/src/pipewire/impl-core.c b/src/pipewire/impl-core.c index d3689c110..71cc8ed62 100644 --- a/src/pipewire/impl-core.c +++ b/src/pipewire/impl-core.c @@ -413,17 +413,7 @@ struct pw_impl_core *pw_context_create_core(struct pw_context *context, this->info.user_name = pw_get_user_name(); this->info.host_name = pw_get_host_name(); this->info.version = pw_get_library_version(); - do { - res = pw_getrandom(&this->info.cookie, - sizeof(this->info.cookie), 0); - } while ((res == -1) && (errno == EINTR)); - if (res == -1) { - res = -errno; - goto error_exit; - } else if (res != sizeof(this->info.cookie)) { - res = -ENODATA; - goto error_exit; - } + this->info.cookie = pw_rand32(); this->info.name = name; spa_hook_list_init(&this->listener_list); diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index 9d5c8eb77..e13c8a461 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -569,6 +569,8 @@ void pw_init(int *argc, char **argv[]) if (support->init_count > 0) goto done; + pw_random_init(); + pthread_mutex_lock(&support_lock); support->in_valgrind = RUNNING_ON_VALGRIND; diff --git a/src/pipewire/private.h b/src/pipewire/private.h index b9ce1870d..1aa02611d 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -1276,6 +1276,8 @@ bool pw_log_is_default(void); void pw_log_init(void); void pw_log_deinit(void); +void pw_random_init(); + void pw_settings_init(struct pw_context *context); int pw_settings_expose(struct pw_context *context); void pw_settings_clean(struct pw_context *context); diff --git a/src/pipewire/utils.c b/src/pipewire/utils.c index 9462158f9..7af984ee8 100644 --- a/src/pipewire/utils.c +++ b/src/pipewire/utils.c @@ -11,6 +11,7 @@ #include #endif #include +#include #include #include @@ -153,16 +154,7 @@ char *pw_strip(char *str, const char *whitespace) return str; } -/** Fill a buffer with random data - * \param buf a buffer to fill - * \param buflen the number of bytes to fill - * \param flags optional flags - * \return the number of bytes filled - * - * Fill \a buf with \a buflen random bytes. - */ -SPA_EXPORT -ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags) +static inline ssize_t make_random(void *buf, size_t buflen, unsigned int flags) { ssize_t bytes; int read_errno; @@ -183,6 +175,63 @@ ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags) return bytes; } +/** Fill a buffer with random data + * \param buf a buffer to fill + * \param buflen the number of bytes to fill + * \param flags optional flags + * \return the number of bytes filled + * + * Fill \a buf with \a buflen random bytes. + */ +SPA_EXPORT +ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags) +{ + ssize_t res; + do { + res = make_random(buf, buflen, flags); + } while ((res == -1) && (errno == EINTR)); + if (res == -1) + return -errno; + if ((size_t)res != buflen) + return -ENODATA; + return res; +} + +static char statebuf[256]; +static struct random_data random_state; + +/** Fill a buffer with random data + * \param buf a buffer to fill + * \param buflen the number of bytes to fill + * + * Fill \a buf with \a buflen random bytes. This functions uses + * pw_getrandom() but falls back to a pseudo random number + * generator in case of failure. + */ +SPA_EXPORT +void pw_random(void *buf, size_t buflen) +{ + if (pw_getrandom(buf, buflen, 0) < 0) { + uint8_t *p = buf; + while (buflen-- > 0) { + int32_t val; + random_r(&random_state, &val); + *p++ = (uint8_t) val;; + } + } +} + +void pw_random_init() +{ + unsigned int seed; + if (pw_getrandom(&seed, sizeof(seed), 0) < 0) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + seed = (unsigned int) SPA_TIMESPEC_TO_NSEC(&ts); + } + initstate_r(seed, statebuf, sizeof(statebuf), &random_state); +} + SPA_EXPORT void* pw_reallocarray(void *ptr, size_t nmemb, size_t size) { diff --git a/src/pipewire/utils.h b/src/pipewire/utils.h index 46190dfae..d5aa6c228 100644 --- a/src/pipewire/utils.h +++ b/src/pipewire/utils.h @@ -72,6 +72,10 @@ pw_strip(char *str, const char *whitespace); SPA_WARN_UNUSED_RESULT ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags); +void pw_random(void *buf, size_t buflen); + +#define pw_rand32() ({ uint32_t val; pw_random(&val, sizeof(val)); val; }) + void* pw_reallocarray(void *ptr, size_t nmemb, size_t size); #ifdef PW_ENABLE_DEPRECATED