From 61e1a8b01dca5d1d6eaa191ac9c12c240e4b2d75 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 1 Jun 2017 06:46:25 +0200 Subject: receive: trim incoming packets to IP header length --- src/data.c | 2 +- src/receive.c | 15 +++++++++++++++ src/tests/netns.sh | 2 +- 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 -- cgit v1.2.3-59-g8ed1b