From 0a8a62cbae17840ad7de35bba7fc4b04ebf76ac0 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 19 Jun 2018 01:22:57 +0200 Subject: receive: drop handshake packets if rng is not initialized Otherwise it's too easy to trigger cookie reply messages. --- src/compat/compat.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 +#include +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 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); -- cgit v1.2.3-59-g8ed1b