From 0a0257228be902ff09608bcaf19ae7c6d58b028f Mon Sep 17 00:00:00 2001 From: Tung Nguyen Date: Thu, 29 Oct 2026 10:04:48 +0700 Subject: [PATCH] tipc: reject attaching bearer of different media to the same occupied device Currently, two bearers of different media types can be added to the same device (e.g., "eth:eth0" and "ib:eth0") via tipc command: tipc bearer enable media eth dev eth0 tipc bearer enable media ib dev eth0 For each command execution, tipc_enable_l2_media() is called: tipc_enable_l2_media() dev_get_by_name() dev_hold() As a result, device->dev_refcnt is incremented twice, but the second bearer replaces the first one. This causes a leak in device->dev_refcnt. Fix this by rejecting a bearer with a different media type when the device is already occupied. Fixes: cb30a63384bc ("tipc: refactor function tipc_enable_bearer()") Reported-by: Jiakai Xu Closes: http://lore.kernel.org/netdev/20260918013509.1853952-1-xujiakai24@mails.ucas.ac.cn/ Signed-off-by: Tung Nguyen Link: https://patch.msgid.link/20261029030522.8306-1-tung.quang.nguyen@est.tech Signed-off-by: Jakub Kicinski --- net/tipc/bearer.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 774f68d1a2b3..60a6f4a3c0fb 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -287,17 +287,50 @@ static int tipc_enable_bearer(struct net *net, const char *name, bearer_id = MAX_BEARERS; i = MAX_BEARERS; while (i-- != 0) { + struct net_device *dev; + b = rtnl_dereference(tn->bearer_list[i]); if (!b) { bearer_id = i; continue; } if (!strcmp(name, b->name)) { +duplicate: errstr = "already enabled"; NL_SET_ERR_MSG(extack, "Already enabled"); goto rejected; } + /* udp media can be used together with any media */ + if (b->media->type_id == TIPC_MEDIA_TYPE_UDP || + m->type_id == TIPC_MEDIA_TYPE_UDP) + goto priority; + + dev = __dev_get_by_name(net, b_names.if_name); + + if (!dev) { + res = -ENODEV; + errstr = "no device for the media"; + NL_SET_ERR_MSG(extack, "No device for the media"); + goto rejected; + } + + if (rtnl_dereference(b->media_ptr) == dev) { + char *dev_name = strchr((const char *)b->name, ':') + 1; + + /* Not allow altname of occupied device */ + if (strcmp(dev_name, b_names.if_name) && + b->media->type_id == m->type_id) + goto duplicate; + + /* Not allow eth and ib to attach to the same device */ + errstr = "same dev for different media"; + NL_SET_ERR_MSG(extack, + "Same dev for different media"); + goto rejected; + } + +priority: if (b->priority == prio && (++with_this_prio > 2)) { pr_warn("Bearer <%s>: already 2 bearers with priority %u\n",