aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2016-04-07 10:09:13 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-07 17:00:13 -0400
commit4e801fa14f68223d36480bced975ebf0c5f9a284 (patch)
tree01b0373d98b732f1fb29a6e6721b5dc95fe02938 /net/tipc
parentba35855e24d12d872e6173692bc34d48d96db39c (diff)
tipc: eliminate buffer leak in bearer layer
When enabling a bearer we create a 'neigbor discoverer' instance by calling the function tipc_disc_create() before the bearer is actually registered in the list of enabled bearers. Because of this, the very first discovery broadcast message, created by the mentioned function, is lost, since it cannot find any valid bearer to use. Furthermore, the used send function, tipc_bearer_xmit_skb() does not free the given buffer when it cannot find a bearer, resulting in the leak of exactly one send buffer each time a bearer is enabled. This commit fixes this problem by introducing two changes: 1) Instead of attemting to send the discovery message directly, we let tipc_disc_create() return the discovery buffer to the calling function, tipc_enable_bearer(), so that the latter can send it when the enabling sequence is finished. 2) In tipc_bearer_xmit_skb(), as well as in the two other transmit functions at the bearer layer, we now free the indicated buffer or buffer chain when a valid bearer cannot be found. Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/bearer.c51
-rw-r--r--net/tipc/discover.c7
-rw-r--r--net/tipc/discover.h2
3 files changed, 29 insertions, 31 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 27a5406213c6..20566e9a1369 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -205,6 +205,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
205 struct tipc_bearer *b; 205 struct tipc_bearer *b;
206 struct tipc_media *m; 206 struct tipc_media *m;
207 struct tipc_bearer_names b_names; 207 struct tipc_bearer_names b_names;
208 struct sk_buff *skb;
208 char addr_string[16]; 209 char addr_string[16];
209 u32 bearer_id; 210 u32 bearer_id;
210 u32 with_this_prio; 211 u32 with_this_prio;
@@ -301,7 +302,7 @@ restart:
301 b->net_plane = bearer_id + 'A'; 302 b->net_plane = bearer_id + 'A';
302 b->priority = priority; 303 b->priority = priority;
303 304
304 res = tipc_disc_create(net, b, &b->bcast_addr); 305 res = tipc_disc_create(net, b, &b->bcast_addr, &skb);
305 if (res) { 306 if (res) {
306 bearer_disable(net, b); 307 bearer_disable(net, b);
307 pr_warn("Bearer <%s> rejected, discovery object creation failed\n", 308 pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
@@ -310,7 +311,8 @@ restart:
310 } 311 }
311 312
312 rcu_assign_pointer(tn->bearer_list[bearer_id], b); 313 rcu_assign_pointer(tn->bearer_list[bearer_id], b);
313 314 if (skb)
315 tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr);
314 pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n", 316 pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
315 name, 317 name,
316 tipc_addr_string_fill(addr_string, disc_domain), priority); 318 tipc_addr_string_fill(addr_string, disc_domain), priority);
@@ -450,6 +452,8 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
450 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); 452 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
451 if (likely(b)) 453 if (likely(b))
452 b->media->send_msg(net, skb, b, dest); 454 b->media->send_msg(net, skb, b, dest);
455 else
456 kfree_skb(skb);
453 rcu_read_unlock(); 457 rcu_read_unlock();
454} 458}
455 459
@@ -468,11 +472,11 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
468 472
469 rcu_read_lock(); 473 rcu_read_lock();
470 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); 474 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
471 if (likely(b)) { 475 if (unlikely(!b))
472 skb_queue_walk_safe(xmitq, skb, tmp) { 476 __skb_queue_purge(xmitq);
473 __skb_dequeue(xmitq); 477 skb_queue_walk_safe(xmitq, skb, tmp) {
474 b->media->send_msg(net, skb, b, dst); 478 __skb_dequeue(xmitq);
475 } 479 b->media->send_msg(net, skb, b, dst);
476 } 480 }
477 rcu_read_unlock(); 481 rcu_read_unlock();
478} 482}
@@ -490,14 +494,14 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
490 494
491 rcu_read_lock(); 495 rcu_read_lock();
492 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); 496 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
493 if (likely(b)) { 497 if (unlikely(!b))
494 skb_queue_walk_safe(xmitq, skb, tmp) { 498 __skb_queue_purge(xmitq);
495 hdr = buf_msg(skb); 499 skb_queue_walk_safe(xmitq, skb, tmp) {
496 msg_set_non_seq(hdr, 1); 500 hdr = buf_msg(skb);
497 msg_set_mc_netid(hdr, net_id); 501 msg_set_non_seq(hdr, 1);
498 __skb_dequeue(xmitq); 502 msg_set_mc_netid(hdr, net_id);
499 b->media->send_msg(net, skb, b, &b->bcast_addr); 503 __skb_dequeue(xmitq);
500 } 504 b->media->send_msg(net, skb, b, &b->bcast_addr);
501 } 505 }
502 rcu_read_unlock(); 506 rcu_read_unlock();
503} 507}
@@ -513,24 +517,21 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
513 * ignores packets sent using interface multicast, and traffic sent to other 517 * ignores packets sent using interface multicast, and traffic sent to other
514 * nodes (which can happen if interface is running in promiscuous mode). 518 * nodes (which can happen if interface is running in promiscuous mode).
515 */ 519 */
516static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev, 520static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,
517 struct packet_type *pt, struct net_device *orig_dev) 521 struct packet_type *pt, struct net_device *orig_dev)
518{ 522{
519 struct tipc_bearer *b; 523 struct tipc_bearer *b;
520 524
521 rcu_read_lock(); 525 rcu_read_lock();
522 b = rcu_dereference_rtnl(dev->tipc_ptr); 526 b = rcu_dereference_rtnl(dev->tipc_ptr);
523 if (likely(b)) { 527 if (likely(b && (skb->pkt_type <= PACKET_BROADCAST))) {
524 if (likely(buf->pkt_type <= PACKET_BROADCAST)) { 528 skb->next = NULL;
525 buf->next = NULL; 529 tipc_rcv(dev_net(dev), skb, b);
526 tipc_rcv(dev_net(dev), buf, b); 530 rcu_read_unlock();
527 rcu_read_unlock(); 531 return NET_RX_SUCCESS;
528 return NET_RX_SUCCESS;
529 }
530 } 532 }
531 rcu_read_unlock(); 533 rcu_read_unlock();
532 534 kfree_skb(skb);
533 kfree_skb(buf);
534 return NET_RX_DROP; 535 return NET_RX_DROP;
535} 536}
536 537
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index f1e738e80535..ad9d477cc242 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -268,10 +268,9 @@ exit:
268 * Returns 0 if successful, otherwise -errno. 268 * Returns 0 if successful, otherwise -errno.
269 */ 269 */
270int tipc_disc_create(struct net *net, struct tipc_bearer *b, 270int tipc_disc_create(struct net *net, struct tipc_bearer *b,
271 struct tipc_media_addr *dest) 271 struct tipc_media_addr *dest, struct sk_buff **skb)
272{ 272{
273 struct tipc_link_req *req; 273 struct tipc_link_req *req;
274 struct sk_buff *skb;
275 274
276 req = kmalloc(sizeof(*req), GFP_ATOMIC); 275 req = kmalloc(sizeof(*req), GFP_ATOMIC);
277 if (!req) 276 if (!req)
@@ -293,9 +292,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
293 setup_timer(&req->timer, disc_timeout, (unsigned long)req); 292 setup_timer(&req->timer, disc_timeout, (unsigned long)req);
294 mod_timer(&req->timer, jiffies + req->timer_intv); 293 mod_timer(&req->timer, jiffies + req->timer_intv);
295 b->link_req = req; 294 b->link_req = req;
296 skb = skb_clone(req->buf, GFP_ATOMIC); 295 *skb = skb_clone(req->buf, GFP_ATOMIC);
297 if (skb)
298 tipc_bearer_xmit_skb(net, req->bearer_id, skb, &req->dest);
299 return 0; 296 return 0;
300} 297}
301 298
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
index c9b12770c5ed..b80a335389c0 100644
--- a/net/tipc/discover.h
+++ b/net/tipc/discover.h
@@ -40,7 +40,7 @@
40struct tipc_link_req; 40struct tipc_link_req;
41 41
42int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr, 42int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr,
43 struct tipc_media_addr *dest); 43 struct tipc_media_addr *dest, struct sk_buff **skb);
44void tipc_disc_delete(struct tipc_link_req *req); 44void tipc_disc_delete(struct tipc_link_req *req);
45void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr); 45void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr);
46void tipc_disc_add_dest(struct tipc_link_req *req); 46void tipc_disc_add_dest(struct tipc_link_req *req);