summaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2018-04-11 16:52:09 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-12 21:46:10 -0400
commitc3317f4db831b7564ff8d1670326456a7fbbbcb3 (patch)
tree845a5dd46e764b071f8dedcf56233457ad10121b /net/tipc
parent1c2734b31d72316e3faaad88c0c9c46fa92a4b20 (diff)
tipc: fix unbalanced reference counter
When a topology subscription is created, we may encounter (or KASAN may provoke) a failure to create a corresponding service instance in the binding table. Instead of letting the tipc_nametbl_subscribe() report the failure back to the caller, the function just makes a warning printout and returns, without incrementing the subscription reference counter as expected by the caller. This makes the caller believe that the subscription was successful, so it will at a later moment try to unsubscribe the item. This involves a sub_put() call. Since the reference counter never was incremented in the first place, we get a premature delete of the subscription item, followed by a "use-after-free" warning. We fix this by adding a return value to tipc_nametbl_subscribe() and make the caller aware of the failure to subscribe. This bug seems to always have been around, but this fix only applies back to the commit shown below. Given the low risk of this happening we believe this to be sufficient. Fixes: commit 218527fe27ad ("tipc: replace name table service range array with rb tree") Reported-by: syzbot+aa245f26d42b8305d157@syzkaller.appspotmail.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/name_table.c5
-rw-r--r--net/tipc/name_table.h2
-rw-r--r--net/tipc/subscr.c5
3 files changed, 9 insertions, 3 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index b1fe20972aa9..4068eaad61a6 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -665,13 +665,14 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,
665/** 665/**
666 * tipc_nametbl_subscribe - add a subscription object to the name table 666 * tipc_nametbl_subscribe - add a subscription object to the name table
667 */ 667 */
668void tipc_nametbl_subscribe(struct tipc_subscription *sub) 668bool tipc_nametbl_subscribe(struct tipc_subscription *sub)
669{ 669{
670 struct name_table *nt = tipc_name_table(sub->net); 670 struct name_table *nt = tipc_name_table(sub->net);
671 struct tipc_net *tn = tipc_net(sub->net); 671 struct tipc_net *tn = tipc_net(sub->net);
672 struct tipc_subscr *s = &sub->evt.s; 672 struct tipc_subscr *s = &sub->evt.s;
673 u32 type = tipc_sub_read(s, seq.type); 673 u32 type = tipc_sub_read(s, seq.type);
674 struct tipc_service *sc; 674 struct tipc_service *sc;
675 bool res = true;
675 676
676 spin_lock_bh(&tn->nametbl_lock); 677 spin_lock_bh(&tn->nametbl_lock);
677 sc = tipc_service_find(sub->net, type); 678 sc = tipc_service_find(sub->net, type);
@@ -685,8 +686,10 @@ void tipc_nametbl_subscribe(struct tipc_subscription *sub)
685 pr_warn("Failed to subscribe for {%u,%u,%u}\n", type, 686 pr_warn("Failed to subscribe for {%u,%u,%u}\n", type,
686 tipc_sub_read(s, seq.lower), 687 tipc_sub_read(s, seq.lower),
687 tipc_sub_read(s, seq.upper)); 688 tipc_sub_read(s, seq.upper));
689 res = false;
688 } 690 }
689 spin_unlock_bh(&tn->nametbl_lock); 691 spin_unlock_bh(&tn->nametbl_lock);
692 return res;
690} 693}
691 694
692/** 695/**
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 4b14fc28d9e2..0febba41da86 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -126,7 +126,7 @@ struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
126struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, 126struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
127 u32 lower, u32 upper, 127 u32 lower, u32 upper,
128 u32 node, u32 key); 128 u32 node, u32 key);
129void tipc_nametbl_subscribe(struct tipc_subscription *s); 129bool tipc_nametbl_subscribe(struct tipc_subscription *s);
130void tipc_nametbl_unsubscribe(struct tipc_subscription *s); 130void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
131int tipc_nametbl_init(struct net *net); 131int tipc_nametbl_init(struct net *net);
132void tipc_nametbl_stop(struct net *net); 132void tipc_nametbl_stop(struct net *net);
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index b7d80bc5f4ab..f340e53da625 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -153,7 +153,10 @@ struct tipc_subscription *tipc_sub_subscribe(struct net *net,
153 memcpy(&sub->evt.s, s, sizeof(*s)); 153 memcpy(&sub->evt.s, s, sizeof(*s));
154 spin_lock_init(&sub->lock); 154 spin_lock_init(&sub->lock);
155 kref_init(&sub->kref); 155 kref_init(&sub->kref);
156 tipc_nametbl_subscribe(sub); 156 if (!tipc_nametbl_subscribe(sub)) {
157 kfree(sub);
158 return NULL;
159 }
157 timer_setup(&sub->timer, tipc_sub_timeout, 0); 160 timer_setup(&sub->timer, tipc_sub_timeout, 0);
158 timeout = tipc_sub_read(&sub->evt.s, timeout); 161 timeout = tipc_sub_read(&sub->evt.s, timeout);
159 if (timeout != TIPC_WAIT_FOREVER) 162 if (timeout != TIPC_WAIT_FOREVER)