[PATCH] tipc: bound reassembly size in tipc_buf_append()
From: Noah Weinberger
Date: Sun Nov 08 2026 - 17:26:25 EST
Hello,
tipc_buf_append() accumulates fragments on the head skb without any
cumulative size or fragment-count limit: head->len and head->truesize
grow with every appended fragment, and the declared inner message size
is only checked by tipc_msg_validate() once the LAST_FRAGMENT arrives.
A peer that has established a TIPC link can send a FIRST_FRAGMENT
followed by an unbounded stream of in-sequence FRAGMENT packets. Each
fragment consumes a sequence number, so the link receive window slides
and every packet passes the window check; nothing bounds the reassembly
if the last fragment never arrives. The head skb's frag list therefore
grows by roughly one bearer-MTU skb per attacker packet - a remote
memory-exhaustion denial of service on any host with TIPC enabled and a
bearer up.
The patch bounds the accumulated size to TIPC_MAX_USER_MSG_SIZE. A
tighter variant would validate against the first fragment's declared
msg_size(); the simple bound is the minimal fix.
Affected version/commit: mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07), net/tipc/msg.c:141-205 (tipc_buf_append), net/tipc/link.c:1297-1322, 1343-1397, 1778-1820 (callers).
Longstanding code.
This was found during an assisted (AI-supported) static source review of
mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07); every code path cited below was re-verified by the
reporter against that tree. The patch below has NOT been compiled and has
NOT been runtime tested, and no reproducer was produced - the triggering
conditions are described above instead. Please treat this as a report for
verification rather than a battle-tested fix.
Reported-by: Noah Weinberger <noahweinberger2003@xxxxxxxxx>
---
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 39dfd33..b37db2c 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -145,6 +145,13 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (skb_has_frag_list(frag) && __skb_linearize(frag))
goto err;
*buf = NULL;
+
+ /* Bound the reassembled message size: a peer that never sends
+ * the last fragment could otherwise grow the head skb (and its
+ * frag list) without any limit.
+ */
+ if (head->len + frag->len > TIPC_MAX_USER_MSG_SIZE)
+ goto err;
frag = skb_unclone_full(frag, GFP_ATOMIC);
if (unlikely(!frag))
goto err;