diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2018-06-19 01:22:57 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2018-06-19 05:09:35 +0200 |
commit | 5d7bdaaf0bd7b5a28ad196109f5ec3cdb550bd02 (patch) | |
tree | d3ddb13296b3676478cdf778b0e27a9d7c347951 /src | |
parent | f9759e17543657e62bd2a487762f419ed6d2f907 (diff) |
receive: drop handshake packets if rng is not initialized
Otherwise it's too easy to trigger cookie reply messages.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/compat/compat.h | 53 | ||||
-rw-r--r-- | src/receive.c | 4 |
2 files changed, 55 insertions, 2 deletions
diff --git a/src/compat/compat.h b/src/compat/compat.h index 2853c09..f2d7e17 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -623,6 +623,59 @@ static inline void new_icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 #define icmpv6_send(a,b,c,d) new_icmpv6_send(a,b,c,d) #endif +/* https://lkml.org/lkml/2018/6/18/1361 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) +#include <linux/random.h> +#include <linux/slab.h> +struct rng_is_initialized_callback { + struct random_ready_callback cb; + atomic_t *rng_state; +}; +static inline void rng_is_initialized_callback(struct random_ready_callback *cb) +{ + struct rng_is_initialized_callback *rdy = container_of(cb, struct rng_is_initialized_callback, cb); + atomic_set(rdy->rng_state, 2); + kfree(rdy); +} +static inline bool rng_is_initialized(void) +{ + static atomic_t rng_state = ATOMIC_INIT(0); + + if (atomic_read(&rng_state) == 2) + return true; + + if (atomic_cmpxchg(&rng_state, 0, 1) == 0) { + int ret; + struct rng_is_initialized_callback *rdy = kmalloc(sizeof(*rdy), GFP_ATOMIC); + if (!rdy) { + atomic_set(&rng_state, 0); + return false; + } + rdy->cb.owner = THIS_MODULE; + rdy->cb.func = rng_is_initialized_callback; + rdy->rng_state = &rng_state; + ret = add_random_ready_callback(&rdy->cb); + if (ret) + kfree(rdy); + if (ret == -EALREADY) { + atomic_set(&rng_state, 2); + return true; + } else if (ret) + atomic_set(&rng_state, 0); + return false; + } + return false; +} +#else +/* 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 bool rng_is_initialized(void) +{ + return true; +} +#endif + /* PaX compatibility */ #ifdef CONSTIFY_PLUGIN #include <linux/cache.h> diff --git a/src/receive.c b/src/receive.c index c5062f8..92a47c8 100644 --- a/src/receive.c +++ b/src/receive.c @@ -470,8 +470,8 @@ void packet_receive(struct wireguard_device *wg, struct sk_buff *skb) case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): { int cpu; - if (skb_queue_len(&wg->incoming_handshakes) > MAX_QUEUED_INCOMING_HANDSHAKES) { - net_dbg_skb_ratelimited("%s: Too many handshakes queued, dropping packet from %pISpfsc\n", wg->dev->name, skb); + if (skb_queue_len(&wg->incoming_handshakes) > MAX_QUEUED_INCOMING_HANDSHAKES || unlikely(!rng_is_initialized())) { + net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n", wg->dev->name, skb); goto err; } skb_queue_tail(&wg->incoming_handshakes, skb); |