aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/discover.c
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2014-04-20 22:55:52 -0400
committerDavid S. Miller <davem@davemloft.net>2014-04-22 21:17:53 -0400
commita8b9b96e959f3c035af20b1bd2ba67b0b7269b19 (patch)
tree02d52832745176ee6d63579f50d375caddd1fc62 /net/tipc/discover.c
parent28dd94187afd660a350d01d6bad4a915a6d570b8 (diff)
tipc: fix race in disc create/delete
Commit a21a584d6720ce349b05795b9bcfab3de8e58419 (tipc: fix neighbor detection problem after hw address change) introduces a race condition involving tipc_disc_delete() and tipc_disc_add/remove_dest that can cause TIPC to dereference the pointer to the bearer discovery request structure after it has been freed since a stray pointer is left in the bearer structure. In order to fix the issue, the process of resetting the discovery request handler is optimized: the discovery request handler and request buffer are just reset instead of being freed, allocated and initialized. As the request point is always valid and the request's lock is taken while the request handler is reset, the race doesn't happen any more. Reported-by: Erik Hugne <erik.hugne@ericsson.com> Signed-off-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Tested-by: Erik Hugne <erik.hugne@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/discover.c')
-rw-r--r--net/tipc/discover.c53
1 files changed, 35 insertions, 18 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 3a8f211f08c7..ada42e436f5e 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -71,22 +71,19 @@ struct tipc_link_req {
71 * @type: message type (request or response) 71 * @type: message type (request or response)
72 * @b_ptr: ptr to bearer issuing message 72 * @b_ptr: ptr to bearer issuing message
73 */ 73 */
74static struct sk_buff *tipc_disc_init_msg(u32 type, struct tipc_bearer *b_ptr) 74static void tipc_disc_init_msg(struct sk_buff *buf, u32 type,
75 struct tipc_bearer *b_ptr)
75{ 76{
76 struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
77 struct tipc_msg *msg; 77 struct tipc_msg *msg;
78 u32 dest_domain = b_ptr->domain; 78 u32 dest_domain = b_ptr->domain;
79 79
80 if (buf) { 80 msg = buf_msg(buf);
81 msg = buf_msg(buf); 81 tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
82 tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain); 82 msg_set_non_seq(msg, 1);
83 msg_set_non_seq(msg, 1); 83 msg_set_node_sig(msg, tipc_random);
84 msg_set_node_sig(msg, tipc_random); 84 msg_set_dest_domain(msg, dest_domain);
85 msg_set_dest_domain(msg, dest_domain); 85 msg_set_bc_netid(msg, tipc_net_id);
86 msg_set_bc_netid(msg, tipc_net_id); 86 b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
87 b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
88 }
89 return buf;
90} 87}
91 88
92/** 89/**
@@ -241,8 +238,9 @@ void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr)
241 link_fully_up = link_working_working(link); 238 link_fully_up = link_working_working(link);
242 239
243 if ((type == DSC_REQ_MSG) && !link_fully_up) { 240 if ((type == DSC_REQ_MSG) && !link_fully_up) {
244 rbuf = tipc_disc_init_msg(DSC_RESP_MSG, b_ptr); 241 rbuf = tipc_buf_acquire(INT_H_SIZE);
245 if (rbuf) { 242 if (rbuf) {
243 tipc_disc_init_msg(rbuf, DSC_RESP_MSG, b_ptr);
246 tipc_bearer_send(b_ptr->identity, rbuf, &media_addr); 244 tipc_bearer_send(b_ptr->identity, rbuf, &media_addr);
247 kfree_skb(rbuf); 245 kfree_skb(rbuf);
248 } 246 }
@@ -349,12 +347,11 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
349 if (!req) 347 if (!req)
350 return -ENOMEM; 348 return -ENOMEM;
351 349
352 req->buf = tipc_disc_init_msg(DSC_REQ_MSG, b_ptr); 350 req->buf = tipc_buf_acquire(INT_H_SIZE);
353 if (!req->buf) { 351 if (!req->buf)
354 kfree(req); 352 return -ENOMEM;
355 return -ENOMSG;
356 }
357 353
354 tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
358 memcpy(&req->dest, dest, sizeof(*dest)); 355 memcpy(&req->dest, dest, sizeof(*dest));
359 req->bearer_id = b_ptr->identity; 356 req->bearer_id = b_ptr->identity;
360 req->domain = b_ptr->domain; 357 req->domain = b_ptr->domain;
@@ -379,3 +376,23 @@ void tipc_disc_delete(struct tipc_link_req *req)
379 kfree_skb(req->buf); 376 kfree_skb(req->buf);
380 kfree(req); 377 kfree(req);
381} 378}
379
380/**
381 * tipc_disc_reset - reset object to send periodic link setup requests
382 * @b_ptr: ptr to bearer issuing requests
383 * @dest_domain: network domain to which links can be established
384 */
385void tipc_disc_reset(struct tipc_bearer *b_ptr)
386{
387 struct tipc_link_req *req = b_ptr->link_req;
388
389 spin_lock_bh(&req->lock);
390 tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
391 req->bearer_id = b_ptr->identity;
392 req->domain = b_ptr->domain;
393 req->num_nodes = 0;
394 req->timer_intv = TIPC_LINK_REQ_INIT;
395 k_start_timer(&req->timer, req->timer_intv);
396 tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
397 spin_unlock_bh(&req->lock);
398}