struct tipc_bearer keeps the bearer MTU in a u32 while struct tipc_link keeps the link MTU in a u16. tipc_enable_l2_media() and the NETDEV_CHANGEMTU notifier both do b->mtu = dev->mtu, tipc_link_create() assigns that into l->mtu, and tipc_link_set_queue_limits() divides by it: int max_bulk = TIPC_MAX_PUBL / (l->mtu / ITEM_SIZE); ITEM_SIZE is 20, so a device MTU of 65536 truncates to 0 and the division faults. tipc_mtu_bad() is the only check on either assignment and tests a lower bound only. The truncation defeats even that: a device MTU of 65556 passes it, yet the link comes out with l->mtu = 20, below the TIPC_MIN_BEARER_MTU the check exists to enforce, and tipc_link_mss() then evaluates 20 - INT_H_SIZE - EMSG_OVERHEAD as an int and stores it in the u32 tipc_link_entry::mtu. Read back over TIPC_NL_LINK_GET, every device MTU above 65535 leaves the link with a wrong MTU: 20 at 65556, 464 at 66000, 32768 at 98304. The bound added in commit 9f29cd8a8e79 ("tipc: fix u16 MTU truncation in media and bearer MTU validation") applies to TIPC_NLA_PROP_MTU in tipc_nl_prop_policy, which covers TIPC_NL_MEDIA_SET and TIPC_NL_BEARER_SET. A device MTU never passes through that policy. dummy sets max_mtu to 0, and dev_validate_mtu() applies its ceiling only when max_mtu is non-zero, so the device accepts 65536; a macvlan inherits max_mtu from its lower device, and two macvlans in bridge mode on one dummy carry each other's TIPC discovery frames, so the bearer reaches tipc_node_check_dest() and tipc_link_create() with b->mtu = 65536. TIPC_NL_BEARER_ENABLE is GENL_UNS_ADMIN_PERM, so an unprivileged user can do this in a user namespace of their own, on a kernel that has TIPC loaded. Oops: divide error: 0000 [#1] SMP KASAN NOPTI RIP: 0010:tipc_link_create (net/tipc/link.c:2531 net/tipc/link.c:520) Call Trace: tipc_node_check_dest (net/tipc/node.c:1284) tipc_disc_rcv (net/tipc/discover.c:252) tipc_rcv (net/tipc/node.c:2134) tipc_l2_rcv_msg (net/tipc/bearer.c:669) __netif_receive_skb_one_core (net/core/dev.c:6216) process_backlog (net/core/dev.c:6680) __napi_poll (net/core/dev.c:7739) net_rx_action (net/core/dev.c:7802) handle_softirqs (kernel/softirq.c:622) Kernel panic - not syncing: Fatal exception in interrupt Give tipc_mtu_bad() the matching upper bound, so the limit sits next to the existing minimum and one check covers both assignments. A device MTU of 65535 is still accepted and the link still comes up, with the 65532 that TIPC rounds it to. The u32 max_pkt fields became u16 mtu and advertised_mtu in commit ed193ece2649 ("tipc: simplify link mtu negotiation"), which also removed link_init_max_pkt(); that had clamped the bearer MTU to MAX_MSG_SIZE before it could reach this division. Fixes: ed193ece2649 ("tipc: simplify link mtu negotiation") Reported-by: Yunpeng Tian Reported-by: Gongming Wang Reported-by: Mingda Zhang Reported-by: Xiaoyu Zhou Reported-by: Qinrun Dai Cc: stable@vger.kernel.org # v4.1 Signed-off-by: Yunpeng Tian --- Reproduced on 7.2.0, with the net/tipc files byte-identical to mainline as of 2026-10-02, both as an unprivileged user and as root, 3 runs of 3 at a device MTU of 65536. At 131072 the low 16 bits are zero as well, but the two nodes never completed discovery here, so that case was not observed. With the patch applied, 65536, 65555, 65556, 66000 and 98304 are all refused by tipc_mtu_bad() and TIPC_NL_BEARER_ENABLE returns -EINVAL, while 65535 still brings the link up. net/tipc/bearer.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -63,6 +63,13 @@ /* Minimum bearer MTU */ #define TIPC_MIN_BEARER_MTU (MAX_H_SIZE + INT_H_SIZE) +/* Maximum bearer MTU + * + * struct tipc_link stores the link MTU in a u16, so a larger bearer MTU would + * be truncated when a link is created on the bearer. + */ +#define TIPC_MAX_BEARER_MTU U16_MAX + /* Identifiers for distinguishing between broadcast/multicast and replicast */ #define TIPC_BROADCAST_SUPPORT 1 @@ -254,12 +261,13 @@ tipc_clone_to_loopback(net, pkts); } -/* check if device MTU is too low for tipc headers */ +/* check if device MTU is usable for tipc bearers */ static inline bool tipc_mtu_bad(struct net_device *dev) { - if (dev->mtu >= TIPC_MIN_BEARER_MTU) + if (dev->mtu >= TIPC_MIN_BEARER_MTU && + dev->mtu <= TIPC_MAX_BEARER_MTU) return false; - netdev_warn(dev, "MTU too low for tipc bearer\n"); + netdev_warn(dev, "MTU not usable for tipc bearer\n"); return true; }