tipc: bound the device MTU accepted for L2 bearers
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: <IRQ> 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) </IRQ> 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. Cc: stable+noautosel@kernel.org # local DoS by userns are a dime a dozen Fixes: ed193ece2649 ("tipc: simplify link mtu negotiation") Reported-by: Gongming Wang <gmwgg05@gmail.com> Reported-by: Mingda Zhang <npczmd@qq.com> Reported-by: Xiaoyu Zhou <xiao-yu.zhou@connect.polyu.hk> Reported-by: Qinrun Dai <jupmouse@gmail.com> Signed-off-by: Yunpeng Tian <shionthanatos@gmail.com> Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech> Link: https://patch.msgid.link/20261003035018.397-1-shionthanatos@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>