]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tipc: fix bc_ackers underflow on duplicate GRP_ACK_MSG
authorOleh Konko <security@1seal.org>
Thu, 2 Apr 2026 09:48:57 +0000 (09:48 +0000)
committerJakub Kicinski <kuba@kernel.org>
Fri, 3 Apr 2026 22:31:17 +0000 (15:31 -0700)
The GRP_ACK_MSG handler in tipc_group_proto_rcv() currently decrements
bc_ackers on every inbound group ACK, even when the same member has
already acknowledged the current broadcast round.

Because bc_ackers is a u16, a duplicate ACK received after the last
legitimate ACK wraps the counter to 65535. Once wrapped,
tipc_group_bc_cong() keeps reporting congestion and later group
broadcasts on the affected socket stay blocked until the group is
recreated.

Fix this by ignoring duplicate or stale ACKs before touching bc_acked or
bc_ackers. This makes repeated GRP_ACK_MSG handling idempotent and
prevents the underflow path.

Fixes: 2f487712b893 ("tipc: guarantee that group broadcast doesn't bypass group unicast")
Cc: stable@vger.kernel.org
Signed-off-by: Oleh Konko <security@1seal.org>
Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/41a4833f368641218e444fdcff822039.security@1seal.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/tipc/group.c

index e0e6227b433b757948ff33c9b70a4fa2804bf0af..14e6732624e28edc20ff80163787bca3018cb2dd 100644 (file)
@@ -746,6 +746,7 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
        u32 port = msg_origport(hdr);
        struct tipc_member *m, *pm;
        u16 remitted, in_flight;
+       u16 acked;
 
        if (!grp)
                return;
@@ -798,7 +799,10 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
        case GRP_ACK_MSG:
                if (!m)
                        return;
-               m->bc_acked = msg_grp_bc_acked(hdr);
+               acked = msg_grp_bc_acked(hdr);
+               if (less_eq(acked, m->bc_acked))
+                       return;
+               m->bc_acked = acked;
                if (--grp->bc_ackers)
                        return;
                list_del_init(&m->small_win);