tipc_disc_rcv() reads the peer net hash, suggested node address and the media address area from header words that live beyond the minimum TIPC header size, and copies a 16 byte node identity from the message data. tipc_msg_validate() only guarantees the minimum header size, so a discovery message (LINK_CONFIG user) with a smaller declared header or without data makes these accesses read past the end of the message. The path is: a frame received on a TIPC bearer is delivered to tipc_rcv(), which calls tipc_msg_validate() and then dispatches non-sequential LINK_CONFIG messages to tipc_disc_rcv(). Discovery traffic needs no established link, so any node on the bearer media can send such a message. The accesses can read up to 52 bytes past the end of the validated message but remain inside the skb data allocation, where KASAN does not report them, and the values read are used as the peer's node identity and media address. Discovery messages are always built with the maximum size header plus a node identity, see tipc_disc_init_msg(). Discard discovery messages that do not carry both before accessing the fields. Fixes: 948fa2d115c5 ("tipc: increase size of tipc discovery messages") Reported-by: Abaci Assisted-by: abaci:qwen3.8-max Signed-off-by: Chuyf26 --- net/tipc/discover.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 685389d4b245..74673ca1f2d5 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -195,27 +195,47 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb, { struct tipc_net *tn = tipc_net(net); struct tipc_msg *hdr = buf_msg(skb); - u32 pnet_hash = msg_peer_net_hash(hdr); - u16 caps = msg_node_capabilities(hdr); + u32 pnet_hash; + u16 caps; bool legacy = tn->legacy_addr_format; - u32 sugg = msg_sugg_node_addr(hdr); - u32 signature = msg_node_sig(hdr); + u32 sugg; + u32 signature; u8 peer_id[NODE_ID_LEN] = {0,}; - u32 dst = msg_dest_domain(hdr); - u32 net_id = msg_bc_netid(hdr); + u32 dst; + u32 net_id; struct tipc_media_addr maddr; - u32 src = msg_prevnode(hdr); - u32 mtyp = msg_type(hdr); + u32 src; + u32 mtyp; bool dupl_addr = false; bool respond = false; u32 self; int err; + /* Discovery messages always carry the maximum size TIPC header + * plus a node identity, see tipc_disc_init_msg(). The header + * fields and the media address area accessed below live beyond + * the minimum header size, so discard shorter messages before + * reading them. + */ + if (msg_hdr_sz(hdr) < MAX_H_SIZE || + msg_size(hdr) < MAX_H_SIZE + NODE_ID_LEN) { + kfree_skb(skb); + return; + } + if (skb_linearize(skb)) { kfree_skb(skb); return; } hdr = buf_msg(skb); + pnet_hash = msg_peer_net_hash(hdr); + caps = msg_node_capabilities(hdr); + sugg = msg_sugg_node_addr(hdr); + signature = msg_node_sig(hdr); + dst = msg_dest_domain(hdr); + net_id = msg_bc_netid(hdr); + src = msg_prevnode(hdr); + mtyp = msg_type(hdr); if (caps & TIPC_NODE_ID128) memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN); -- 2.43.5