summaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2016-05-31 23:43:00 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-01 20:48:46 -0400
commit260916dfb48c374f7840f3b86e69afd3afdb6e96 (patch)
treef3d2d75d159a68ee886d04cd130d05107f388bbd /drivers/net/macvlan.c
parent595d0b29463343c3be995d3948930b8231e5b8cd (diff)
macvlan: Fix potential use-after free for broadcasts
When we postpone a broadcast packet we save the source port in the skb if it is local. However, the source port can disappear before we get a chance to process the packet. This patch fixes this by holding a ref count on the netdev. It also delays the skb->cb modification until after we allocate the new skb as you should not modify shared skbs. Fixes: 412ca1550cbe ("macvlan: Move broadcasts into a work queue") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index cb01023eab41..a71fa592b1fb 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -305,11 +305,14 @@ static void macvlan_process_broadcast(struct work_struct *w)
305 305
306 rcu_read_unlock(); 306 rcu_read_unlock();
307 307
308 if (src)
309 dev_put(src->dev);
308 kfree_skb(skb); 310 kfree_skb(skb);
309 } 311 }
310} 312}
311 313
312static void macvlan_broadcast_enqueue(struct macvlan_port *port, 314static void macvlan_broadcast_enqueue(struct macvlan_port *port,
315 const struct macvlan_dev *src,
313 struct sk_buff *skb) 316 struct sk_buff *skb)
314{ 317{
315 struct sk_buff *nskb; 318 struct sk_buff *nskb;
@@ -319,8 +322,12 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,
319 if (!nskb) 322 if (!nskb)
320 goto err; 323 goto err;
321 324
325 MACVLAN_SKB_CB(nskb)->src = src;
326
322 spin_lock(&port->bc_queue.lock); 327 spin_lock(&port->bc_queue.lock);
323 if (skb_queue_len(&port->bc_queue) < MACVLAN_BC_QUEUE_LEN) { 328 if (skb_queue_len(&port->bc_queue) < MACVLAN_BC_QUEUE_LEN) {
329 if (src)
330 dev_hold(src->dev);
324 __skb_queue_tail(&port->bc_queue, nskb); 331 __skb_queue_tail(&port->bc_queue, nskb);
325 err = 0; 332 err = 0;
326 } 333 }
@@ -429,8 +436,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
429 goto out; 436 goto out;
430 } 437 }
431 438
432 MACVLAN_SKB_CB(skb)->src = src; 439 macvlan_broadcast_enqueue(port, src, skb);
433 macvlan_broadcast_enqueue(port, skb);
434 440
435 return RX_HANDLER_PASS; 441 return RX_HANDLER_PASS;
436 } 442 }