Skip to content

Commit c3317f4

Browse files
Jon Maloydavem330
authored andcommitted
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 218527f ("tipc: replace name table service range array with rb tree") Reported-by: [email protected] Signed-off-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1c2734b commit c3317f4

File tree

3 files changed

+9
-3
lines changed

3 files changed

+9
-3
lines changed

net/tipc/name_table.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,13 +665,14 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,
665665
/**
666666
* tipc_nametbl_subscribe - add a subscription object to the name table
667667
*/
668-
void tipc_nametbl_subscribe(struct tipc_subscription *sub)
668+
bool tipc_nametbl_subscribe(struct tipc_subscription *sub)
669669
{
670670
struct name_table *nt = tipc_name_table(sub->net);
671671
struct tipc_net *tn = tipc_net(sub->net);
672672
struct tipc_subscr *s = &sub->evt.s;
673673
u32 type = tipc_sub_read(s, seq.type);
674674
struct tipc_service *sc;
675+
bool res = true;
675676

676677
spin_lock_bh(&tn->nametbl_lock);
677678
sc = tipc_service_find(sub->net, type);
@@ -685,8 +686,10 @@ void tipc_nametbl_subscribe(struct tipc_subscription *sub)
685686
pr_warn("Failed to subscribe for {%u,%u,%u}\n", type,
686687
tipc_sub_read(s, seq.lower),
687688
tipc_sub_read(s, seq.upper));
689+
res = false;
688690
}
689691
spin_unlock_bh(&tn->nametbl_lock);
692+
return res;
690693
}
691694

692695
/**

net/tipc/name_table.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
126126
struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
127127
u32 lower, u32 upper,
128128
u32 node, u32 key);
129-
void tipc_nametbl_subscribe(struct tipc_subscription *s);
129+
bool tipc_nametbl_subscribe(struct tipc_subscription *s);
130130
void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
131131
int tipc_nametbl_init(struct net *net);
132132
void tipc_nametbl_stop(struct net *net);

net/tipc/subscr.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ struct tipc_subscription *tipc_sub_subscribe(struct net *net,
153153
memcpy(&sub->evt.s, s, sizeof(*s));
154154
spin_lock_init(&sub->lock);
155155
kref_init(&sub->kref);
156-
tipc_nametbl_subscribe(sub);
156+
if (!tipc_nametbl_subscribe(sub)) {
157+
kfree(sub);
158+
return NULL;
159+
}
157160
timer_setup(&sub->timer, tipc_sub_timeout, 0);
158161
timeout = tipc_sub_read(&sub->evt.s, timeout);
159162
if (timeout != TIPC_WAIT_FOREVER)

0 commit comments

Comments
 (0)