Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: bridge: Move specific fragmented packet to slow_path instead of dropping it

The config NF_CONNTRACK_BRIDGE will change the bridge forwarding for
fragmented packets.

The original bridge does not know that it is a fragmented packet and
forwards it directly, after NF_CONNTRACK_BRIDGE is enabled, function
nf_br_ip_fragment and br_ip6_fragment will check the headroom.

In original br_forward, insufficient headroom of skb may indeed exist,
but there's still a way to save the skb in the device driver after
dev_queue_xmit.So droping the skb will change the original bridge
forwarding in some cases.

Fixes: 3c171f496ef5 ("netfilter: bridge: add connection tracking system")
Signed-off-by: Huajian Yang <huajianyang@asrmicro.com>
Reviewed-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Huajian Yang and committed by
Pablo Neira Ayuso
aa04c6f4 836b313a

+12 -12
+6 -6
net/bridge/netfilter/nf_conntrack_bridge.c
··· 60 60 struct ip_fraglist_iter iter; 61 61 struct sk_buff *frag; 62 62 63 - if (first_len - hlen > mtu || 64 - skb_headroom(skb) < ll_rs) 63 + if (first_len - hlen > mtu) 65 64 goto blackhole; 66 65 67 - if (skb_cloned(skb)) 66 + if (skb_cloned(skb) || 67 + skb_headroom(skb) < ll_rs) 68 68 goto slow_path; 69 69 70 70 skb_walk_frags(skb, frag) { 71 - if (frag->len > mtu || 72 - skb_headroom(frag) < hlen + ll_rs) 71 + if (frag->len > mtu) 73 72 goto blackhole; 74 73 75 - if (skb_shared(frag)) 74 + if (skb_shared(frag) || 75 + skb_headroom(frag) < hlen + ll_rs) 76 76 goto slow_path; 77 77 } 78 78
+6 -6
net/ipv6/netfilter.c
··· 164 164 struct ip6_fraglist_iter iter; 165 165 struct sk_buff *frag2; 166 166 167 - if (first_len - hlen > mtu || 168 - skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) 167 + if (first_len - hlen > mtu) 169 168 goto blackhole; 170 169 171 - if (skb_cloned(skb)) 170 + if (skb_cloned(skb) || 171 + skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) 172 172 goto slow_path; 173 173 174 174 skb_walk_frags(skb, frag2) { 175 - if (frag2->len > mtu || 176 - skb_headroom(frag2) < (hlen + hroom + sizeof(struct frag_hdr))) 175 + if (frag2->len > mtu) 177 176 goto blackhole; 178 177 179 178 /* Partially cloned skb? */ 180 - if (skb_shared(frag2)) 179 + if (skb_shared(frag2) || 180 + skb_headroom(frag2) < (hlen + hroom + sizeof(struct frag_hdr))) 181 181 goto slow_path; 182 182 } 183 183