summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-06-01 06:46:25 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-06-01 06:46:25 +0200
commit0f6f08010228c2b4d3a38c66f8e9cfd1d23ad5f3 (patch)
treec9bf451c20cbd942880e781952b15d6bf268bb92
parent0ee5757d36ef3ef02646e34eb465b52a33fa910d (diff)
receive: trim incoming packets to IP header length
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--src/data.c2
-rw-r--r--src/receive.c15
-rwxr-xr-xsrc/tests/netns.sh2
3 files changed, 17 insertions, 2 deletions
diff --git a/src/data.c b/src/data.c
index 9210304..d7f9332 100644
--- a/src/data.c
+++ b/src/data.c
@@ -192,7 +192,7 @@ static inline bool skb_decrypt(struct sk_buff *skb, struct noise_symmetric_key *
if (!chacha20poly1305_decrypt_sg(sg, sg, skb->len, NULL, 0, PACKET_CB(skb)->nonce, key->key))
return false;
- return pskb_trim(skb, skb->len - noise_encrypted_len(0)) == 0;
+ return !pskb_trim(skb, skb->len - noise_encrypted_len(0));
}
static inline bool get_encryption_nonce(u64 *nonce, struct noise_symmetric_key *key)
diff --git a/src/receive.c b/src/receive.c
index b582d00..5807465 100644
--- a/src/receive.c
+++ b/src/receive.c
@@ -237,10 +237,15 @@ void packet_consume_data_done(struct sk_buff *skb, struct wireguard_peer *peer,
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) {
+ len = ntohs(ip_hdr(skb)->tot_len);
+ if (unlikely(len < sizeof(struct iphdr)))
+ goto dishonest_packet_size;
skb->protocol = htons(ETH_P_IP);
if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
IP_ECN_set_ce(ip_hdr(skb));
+
} else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) {
+ len = ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr);
skb->protocol = htons(ETH_P_IPV6);
if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
IP6_ECN_set_ce(skb, ipv6_hdr(skb));
@@ -251,6 +256,16 @@ void packet_consume_data_done(struct sk_buff *skb, struct wireguard_peer *peer,
goto packet_processed;
}
+ if (unlikely(len > skb->len)) {
+dishonest_packet_size:
+ net_dbg_ratelimited("%s: Packet is lying about its size from peer %Lu (%pISpfsc)\n", netdev_pub(peer->device)->name, peer->internal_id, &peer->endpoint.addr);
+ ++dev->stats.rx_errors;
+ ++dev->stats.rx_length_errors;
+ goto packet_processed;
+ }
+ if (len < skb->len && pskb_trim(skb, len))
+ goto packet_processed;
+
timers_data_received(peer);
routed_peer = routing_table_lookup_src(&wg->peer_routing_table, skb);
diff --git a/src/tests/netns.sh b/src/tests/netns.sh
index 1ad767e..72f6333 100755
--- a/src/tests/netns.sh
+++ b/src/tests/netns.sh
@@ -143,7 +143,7 @@ n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
# Before calling tests, we first make sure that the stats counters are working
n2 ping -c 10 -f -W 1 192.168.241.1
{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
-[[ $rx_bytes -ge 1052 && $tx_bytes -ge 1516 && $rx_bytes -lt 2500 && $rx_bytes -lt 2500 ]]
+[[ $rx_bytes -ge 932 && $tx_bytes -ge 1516 && $rx_bytes -lt 2500 && $rx_bytes -lt 2500 ]]
tests
ip1 link set wg0 mtu $big_mtu
ip2 link set wg0 mtu $big_mtu