diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2017-06-01 06:46:25 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2017-06-01 06:46:25 +0200 |
commit | 0f6f08010228c2b4d3a38c66f8e9cfd1d23ad5f3 (patch) | |
tree | c9bf451c20cbd942880e781952b15d6bf268bb92 | |
parent | 0ee5757d36ef3ef02646e34eb465b52a33fa910d (diff) |
receive: trim incoming packets to IP header length
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | src/data.c | 2 | ||||
-rw-r--r-- | src/receive.c | 15 | ||||
-rwxr-xr-x | src/tests/netns.sh | 2 |
3 files changed, 17 insertions, 2 deletions
@@ -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 |