diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2015-11-16 16:34:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-11-17 14:39:28 -0500 |
commit | cf554ada0be7077906aa9a17faf151ff66e3cb8e (patch) | |
tree | 73f8237dcd14a6d0f57e3fd99f4c98e4743c8777 /drivers/net/ipvlan | |
parent | eb3f8b42aaba19325eff7e99842ca36429a0a3b8 (diff) |
ipvlan: fix leak in ipvlan_rcv_frame
Pass a **skb to ipvlan_rcv_frame so that if skb_share_check returns a
new skb, we actually use it during further processing.
It's safe to ignore the new skb in the ipvlan_xmit_* functions, because
they call ipvlan_rcv_frame with local == true, so that dev_forward_skb
is called and always takes ownership of the skb.
Fixes: 2ad7bf363841 ("ipvlan: Initial check-in of the IPVLAN driver.")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ipvlan')
-rw-r--r-- | drivers/net/ipvlan/ipvlan_core.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index d50887e3df6d..a9148e46dad0 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c | |||
@@ -254,7 +254,7 @@ acct: | |||
254 | } | 254 | } |
255 | } | 255 | } |
256 | 256 | ||
257 | static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, | 257 | static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb, |
258 | bool local) | 258 | bool local) |
259 | { | 259 | { |
260 | struct ipvl_dev *ipvlan = addr->master; | 260 | struct ipvl_dev *ipvlan = addr->master; |
@@ -262,6 +262,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, | |||
262 | unsigned int len; | 262 | unsigned int len; |
263 | rx_handler_result_t ret = RX_HANDLER_CONSUMED; | 263 | rx_handler_result_t ret = RX_HANDLER_CONSUMED; |
264 | bool success = false; | 264 | bool success = false; |
265 | struct sk_buff *skb = *pskb; | ||
265 | 266 | ||
266 | len = skb->len + ETH_HLEN; | 267 | len = skb->len + ETH_HLEN; |
267 | if (unlikely(!(dev->flags & IFF_UP))) { | 268 | if (unlikely(!(dev->flags & IFF_UP))) { |
@@ -273,6 +274,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, | |||
273 | if (!skb) | 274 | if (!skb) |
274 | goto out; | 275 | goto out; |
275 | 276 | ||
277 | *pskb = skb; | ||
276 | skb->dev = dev; | 278 | skb->dev = dev; |
277 | skb->pkt_type = PACKET_HOST; | 279 | skb->pkt_type = PACKET_HOST; |
278 | 280 | ||
@@ -486,7 +488,7 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) | |||
486 | 488 | ||
487 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); | 489 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); |
488 | if (addr) | 490 | if (addr) |
489 | return ipvlan_rcv_frame(addr, skb, true); | 491 | return ipvlan_rcv_frame(addr, &skb, true); |
490 | 492 | ||
491 | out: | 493 | out: |
492 | skb->dev = ipvlan->phy_dev; | 494 | skb->dev = ipvlan->phy_dev; |
@@ -506,7 +508,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) | |||
506 | if (lyr3h) { | 508 | if (lyr3h) { |
507 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); | 509 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); |
508 | if (addr) | 510 | if (addr) |
509 | return ipvlan_rcv_frame(addr, skb, true); | 511 | return ipvlan_rcv_frame(addr, &skb, true); |
510 | } | 512 | } |
511 | skb = skb_share_check(skb, GFP_ATOMIC); | 513 | skb = skb_share_check(skb, GFP_ATOMIC); |
512 | if (!skb) | 514 | if (!skb) |
@@ -589,7 +591,7 @@ static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb, | |||
589 | 591 | ||
590 | addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); | 592 | addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); |
591 | if (addr) | 593 | if (addr) |
592 | ret = ipvlan_rcv_frame(addr, skb, false); | 594 | ret = ipvlan_rcv_frame(addr, pskb, false); |
593 | 595 | ||
594 | out: | 596 | out: |
595 | return ret; | 597 | return ret; |
@@ -626,7 +628,7 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, | |||
626 | 628 | ||
627 | addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); | 629 | addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); |
628 | if (addr) | 630 | if (addr) |
629 | ret = ipvlan_rcv_frame(addr, skb, false); | 631 | ret = ipvlan_rcv_frame(addr, pskb, false); |
630 | } | 632 | } |
631 | 633 | ||
632 | return ret; | 634 | return ret; |