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

openvswitch: Fix skb leak using IPv6 defrag

nf_ct_frag6_gather() makes a clone of each skb passed to it, and if the
reassembly is successful, expects the caller to free all of the original
skbs using nf_ct_frag6_consume_orig(). This call was previously missing,
meaning that the original fragments were never freed (with the exception
of the last fragment to arrive).

Fix this by ensuring that all original fragments except for the last
fragment are freed via nf_ct_frag6_consume_orig(). The last fragment
will be morphed into the head, so it must not be freed yet. Furthermore,
retain the ->next pointer for the head after skb_morph().

Fixes: 7f8a436eaa2c ("openvswitch: Add conntrack action")
Reported-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Joe Stringer <joestringer@nicira.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Joe Stringer and committed by
David S. Miller
6f5cadee 190b8ffb

+7
+7
net/openvswitch/conntrack.c
··· 326 326 return -EINVAL; 327 327 } 328 328 329 + /* Don't free 'skb' even though it is one of the original 330 + * fragments, as we're going to morph it into the head. 331 + */ 332 + skb_get(skb); 333 + nf_ct_frag6_consume_orig(reasm); 334 + 329 335 key->ip.proto = ipv6_hdr(reasm)->nexthdr; 330 336 skb_morph(skb, reasm); 337 + skb->next = reasm->next; 331 338 consume_skb(reasm); 332 339 ovs_cb.mru = IP6CB(skb)->frag_max_size; 333 340 #endif