aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2018-06-19 01:22:57 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2018-06-19 05:09:35 +0200
commit0a8a62cbae17840ad7de35bba7fc4b04ebf76ac0 (patch)
tree46089cb0b408909ee0dd51ce2efd5d5c9fcf0c02 /src
parentnoise: wait for crng before taking locks (diff)
downloadwireguard-monolithic-historical-0a8a62cbae17840ad7de35bba7fc4b04ebf76ac0.tar.xz
wireguard-monolithic-historical-0a8a62cbae17840ad7de35bba7fc4b04ebf76ac0.zip
receive: drop handshake packets if rng is not initialized
Otherwise it's too easy to trigger cookie reply messages.
Diffstat (limited to 'src')
-rw-r--r--src/compat/compat.h53
-rw-r--r--src/receive.c4
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);