From: Ruide Cao tipc_get_gap_ack_blks() reads len, ugack_cnt and bgack_cnt directly from msg_data(hdr) before verifying that a STATE message actually contains the fixed Gap ACK block header in its logical data area. A peer that negotiates TIPC_GAP_ACK_BLOCK can send a short STATE message with a declared TIPC payload shorter than struct tipc_gap_ack_blks and still append a few physical bytes after the header. The helper then trusts those bytes as Gap ACK metadata, and the forged bgack_cnt/len values can drive the broadcast receive path into kmemdup() beyond the skb boundary. Fix this by rejecting Gap ACK parsing unless the logical STATE payload is large enough to cover the fixed header, and by rejecting declared Gap ACK lengths that are smaller than the fixed header or larger than the logical payload. Return 0 for invalid lengths so callers do not treat malformed Gap ACK data as monitor payload offset, while preserving the declared size for valid but unused Gap ACK records. This keeps malformed Gap ACK data ignored without misaligning monitor payload parsing in unicast STATE messages. Fixes: d7626b5acff9 ("tipc: introduce Gap ACK blocks for broadcast link") Reported-by: Yifan Wu Reported-by: Juefei Pu Co-developed-by: Yuan Tan Signed-off-by: Yuan Tan Suggested-by: Xin Liu Tested-by: Ren Wei Signed-off-by: Ruide Cao Signed-off-by: Ren Wei --- net/tipc/link.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 49dfc098d89b..a364822c1cd8 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1415,12 +1415,20 @@ u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l, struct tipc_msg *hdr, bool uc) { struct tipc_gap_ack_blks *p; - u16 sz = 0; + u16 sz = 0, dlen = msg_data_sz(hdr); /* Does peer support the Gap ACK blocks feature? */ if (l->peer_caps & TIPC_GAP_ACK_BLOCK) { + if (dlen < sizeof(*p)) + goto ignore; + p = (struct tipc_gap_ack_blks *)msg_data(hdr); sz = ntohs(p->len); + if (sz < sizeof(*p) || sz > dlen) { + sz = 0; + goto ignore; + } + /* Sanity check */ if (sz == struct_size(p, gacks, size_add(p->ugack_cnt, p->bgack_cnt))) { /* Good, check if the desired type exists */ @@ -1434,6 +1442,8 @@ u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l, } } } + +ignore: /* Other cases: ignore! */ p = NULL; -- 2.34.1