From f3a1c6504679b039ba563b5b45c9bbe1113dfbad Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 2 Jun 2017 17:41:11 +0200 Subject: config: ensure the RNG is initialized before setting It's possible that get_random_bytes() will return bad randomness if it hasn't been seeded. This patch makes configuration block until the RNG is properly initialized. Reference: http://www.openwall.com/lists/kernel-hardening/2017/06/02/2 --- src/compat/compat.h | 43 +++++++++++++++++++++++++++++++++++++++++++ src/config.c | 5 +++++ 2 files changed, 48 insertions(+) diff --git a/src/compat/compat.h b/src/compat/compat.h index 6a5f33c..68d62b9 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -222,6 +222,49 @@ static const struct in6_addr our_in6addr_any = IN6ADDR_ANY_INIT; #define in6addr_any our_in6addr_any #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) +#include +#include +#include +struct rng_initializer { + struct completion done; + struct random_ready_callback cb; +}; +static inline void rng_initialized_callback(struct random_ready_callback *cb) +{ + complete(&container_of(cb, struct rng_initializer, cb)->done); +} +static inline int wait_for_random_bytes(void) +{ + static bool rng_is_initialized = false; + int ret; + if (unlikely(!rng_is_initialized)) { + struct rng_initializer rng = { + .done = COMPLETION_INITIALIZER(rng.done), + .cb = { .owner = THIS_MODULE, .func = rng_initialized_callback } + }; + ret = add_random_ready_callback(&rng.cb); + if (!ret) { + ret = wait_for_completion_interruptible(&rng.done); + if (ret) { + del_random_ready_callback(&rng.cb); + return ret; + } + } else if (ret != -EALREADY) + return ret; + rng_is_initialized = true; + } + return 0; +} +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +/* This is a disaster. Without this API, we really have no way of + * knowing if it's initialized. We just return that it has and hope + * for the best... */ +static inline int wait_for_random_bytes(void) +{ + return 0; +} +#endif /* https://lkml.org/lkml/2015/6/12/415 */ #include diff --git a/src/config.c b/src/config.c index d3b6611..286c874 100644 --- a/src/config.c +++ b/src/config.c @@ -8,6 +8,7 @@ #include "hashtables.h" #include "peer.h" #include "uapi.h" +#include static int set_device_port(struct wireguard_device *wg, u16 port) { @@ -134,6 +135,10 @@ int config_set_device(struct wireguard_device *wg, void __user *user_device) void __user *user_peer; bool modified_static_identity = false; + /* It's important that the Linux RNG is fully seeded before we let the user + * actually configure the device, so that we're assured to have good ephemerals. */ + wait_for_random_bytes(); + BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); -- cgit v1.2.3-59-g8ed1b