Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/4] tipc: fix missing netlink admin gate and receive-path bugs
@ 2026-06-02 13:35 Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 1/4] tipc: require net admin for TIPCv2 netlink mutators Michael Bommarito
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Michael Bommarito @ 2026-06-02 13:35 UTC (permalink / raw)
  To: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel

This series fixes four independent issues in the TIPC subsystem. They all
require a node that has TIPC configured (the tipc module loaded). Patch 1
is then reachable by a local process with no capabilities; patches 2 to 4
are reachable by a remote TIPC peer once a bearer is enabled. They were
found by an audit of the TIPC netlink, neighbor-discovery, connection and
name-distribution paths with AI assistance; following the kernel's
handling of AI-assisted bug reports they are disclosed in public.

The central issue is patch 1. The TIPCv2 generic-netlink API registers
its state-changing operations without an admin-permission flag. Generic
netlink only checks CAP_NET_ADMIN when an operation sets GENL_ADMIN_PERM
or GENL_UNS_ADMIN_PERM. The legacy TIPC config netlink path gates the
same administrative commands behind netlink_net_capable(CAP_NET_ADMIN);
the v2 path does not. So on a node where the tipc module is loaded, a
local process with zero effective capabilities can set the network id and
node identity, install and flush AEAD key material, and enable, disable
and reconfigure bearers, links and media. This restores the authorization
gate the legacy API has always had.

The other three patches fix input-validation and arithmetic bugs in the
receive paths. They are reachable independently of patch 1 (from a peer
node over a bearer, or over an established TIPC connection):

  1/4 adds GENL_UNS_ADMIN_PERM to the mutating v2 ops, matching the
      legacy API's netlink_net_capable(CAP_NET_ADMIN) gate. A QEMU/KASAN
      repro run as uid/gid 65534 with zero effective capabilities could
      change the network id and node identity, set and flush key
      material, and enable and disable a UDP bearer; with the patch those
      calls return -EPERM.

  2/4 bounds the media-address and node-id reads in tipc_disc_rcv()
      against the received length. A short LINK_CONFIG message otherwise
      makes the handler read past the received data.

  3/4 caps the peer-supplied connection ack so it cannot underflow the
      unsigned 16-bit send counter and leave a connection permanently
      flow-control blocked.

  4/4 rejects a peer PUBLICATION whose lower bound exceeds its upper
      bound. Such a binding can never be matched or withdrawn and leaks
      the publication; the local bind path already rejects it.

For the record, two related TIPC issues are deliberately not in this
series because other contributors already have fixes posted to netdev:
the broadcast Gap-ACK out-of-bounds read in tipc_get_gap_ack_blks()
("tipc: validate Gap ACK blocks in STATE message") and the
neighbor-monitor use-after-free on bearer teardown ("tipc: fix UAF race
in tipc_mon_peer_up/down/remove_peer vs bearer teardown"). This series
does not touch those paths. Note that patch 1 also gates bearer
enable/disable, the operation that exposes TIPC's packet-receive paths to
the network, so it is useful as defence in depth and not only as an
authorization fix.

Each patch was build-tested with no new warnings against v7.1-rc5. The
four patches touch different files and are independent.

Michael Bommarito (4):
  tipc: require net admin for TIPCv2 netlink mutators
  tipc: validate discovery message length before reading media address
  tipc: prevent snt_unacked underflow on CONN_ACK
  tipc: reject inverted service ranges from peer bindings

 net/tipc/discover.c   | 14 ++++++++++++++
 net/tipc/name_distr.c | 11 ++++++++++-
 net/tipc/netlink.c    | 12 ++++++++++++
 net/tipc/socket.c     |  9 ++++++++-
 4 files changed, 44 insertions(+), 2 deletions(-)


base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
-- 
2.53.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net 1/4] tipc: require net admin for TIPCv2 netlink mutators
  2026-06-02 13:35 [PATCH net 0/4] tipc: fix missing netlink admin gate and receive-path bugs Michael Bommarito
@ 2026-06-02 13:35 ` Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 2/4] tipc: validate discovery message length before reading media address Michael Bommarito
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Michael Bommarito @ 2026-06-02 13:35 UTC (permalink / raw)
  To: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel

TIPCv2 registers mutating generic-netlink operations without admin
permission flags. Generic netlink only checks CAP_NET_ADMIN when an
operation sets GENL_ADMIN_PERM or GENL_UNS_ADMIN_PERM, so a local
unprivileged process can currently change TIPC state through commands
such as TIPC_NL_NET_SET, TIPC_NL_KEY_SET, TIPC_NL_KEY_FLUSH, and
bearer enable/disable.

The legacy TIPC netlink API already checks netlink_net_capable(...,
CAP_NET_ADMIN) for administrative commands. Give the TIPCv2 mutators
the equivalent network-namespace-aware generic-netlink gate by setting
GENL_UNS_ADMIN_PERM.

A QEMU/KASAN repro run as uid/gid 65534 with zero effective
capabilities previously succeeded in changing the network id and node
identity, setting and flushing key material, and enabling/disabling a
UDP bearer. With this patch applied the same operations fail with
-EPERM.

Fixes: 0655f6a8635b ("tipc: add bearer disable/enable to new netlink api")
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 net/tipc/netlink.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 1a9a5bdaccf4f..8336a9664703f 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -152,11 +152,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_BEARER_DISABLE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_disable,
 	},
 	{
 		.cmd	= TIPC_NL_BEARER_ENABLE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_enable,
 	},
 	{
@@ -168,11 +170,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_BEARER_ADD,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_add,
 	},
 	{
 		.cmd	= TIPC_NL_BEARER_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_set,
 	},
 	{
@@ -197,11 +201,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_LINK_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_set_link,
 	},
 	{
 		.cmd	= TIPC_NL_LINK_RESET_STATS,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit   = tipc_nl_node_reset_link_stats,
 	},
 	{
@@ -213,6 +219,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_MEDIA_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_media_set,
 	},
 	{
@@ -228,6 +235,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_NET_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_net_set,
 	},
 	{
@@ -238,6 +246,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_MON_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_set_monitor,
 	},
 	{
@@ -255,6 +264,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_PEER_REMOVE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_peer_rm,
 	},
 #ifdef CONFIG_TIPC_MEDIA_UDP
@@ -269,11 +279,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_KEY_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_set_key,
 	},
 	{
 		.cmd	= TIPC_NL_KEY_FLUSH,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_flush_key,
 	},
 #endif
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net 2/4] tipc: validate discovery message length before reading media address
  2026-06-02 13:35 [PATCH net 0/4] tipc: fix missing netlink admin gate and receive-path bugs Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 1/4] tipc: require net admin for TIPCv2 netlink mutators Michael Bommarito
@ 2026-06-02 13:35 ` Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 3/4] tipc: prevent snt_unacked underflow on CONN_ACK Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 4/4] tipc: reject inverted service ranges from peer bindings Michael Bommarito
  3 siblings, 0 replies; 5+ messages in thread
From: Michael Bommarito @ 2026-06-02 13:35 UTC (permalink / raw)
  To: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel

tipc_disc_rcv() reads the sender's media address from the fixed
media-info area of the header (msg_media_addr(), offset
TIPC_MEDIA_INFO_OFFSET) and, when the peer advertises 128-bit node
ids, copies a NODE_ID_LEN node id appended after the header. Neither
read is bounded against the actual received length: tipc_msg_validate()
only enforces a header size in the range [MIN_H_SIZE, MAX_H_SIZE], so a
LINK_CONFIG message as short as MIN_H_SIZE (24 bytes) passes validation
while the media-address read reaches up to MAX_H_SIZE and the node-id
read reaches MAX_H_SIZE + NODE_ID_LEN.

A node always builds discovery messages at MAX_H_SIZE + NODE_ID_LEN
(tipc_disc_init_msg()), so a shorter LINK_CONFIG message is malformed.
Drop such messages before the reads so the media address and node id
are taken from received data rather than from uninitialised tail room
or memory beyond the buffer.

A crafted short LINK_CONFIG datagram otherwise makes tipc_disc_rcv()
read past the received message data when a bearer is enabled.

Fixes: 3d749a6a26b0 ("tipc: Hide media-specific addressing details from generic bearer code")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 net/tipc/discover.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 3e54d2df5683a..daf5f11fc82b4 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -217,6 +217,20 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
 	}
 	hdr = buf_msg(skb);
 
+	/* A discovery message carries the sender's media address within the
+	 * fixed-size header and, when 128-bit ids are advertised, a node id
+	 * appended after it.  A node always builds these messages at
+	 * MAX_H_SIZE + NODE_ID_LEN, so drop anything too short to hold what
+	 * is read below and keep msg2addr() and the node-id copy within the
+	 * received data.
+	 */
+	if (skb->len < MAX_H_SIZE ||
+	    ((caps & TIPC_NODE_ID128) && skb->len < MAX_H_SIZE + NODE_ID_LEN)) {
+		pr_warn_ratelimited("Rcv corrupt discovery message\n");
+		kfree_skb(skb);
+		return;
+	}
+
 	if (caps & TIPC_NODE_ID128)
 		memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN);
 	else
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net 3/4] tipc: prevent snt_unacked underflow on CONN_ACK
  2026-06-02 13:35 [PATCH net 0/4] tipc: fix missing netlink admin gate and receive-path bugs Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 1/4] tipc: require net admin for TIPCv2 netlink mutators Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 2/4] tipc: validate discovery message length before reading media address Michael Bommarito
@ 2026-06-02 13:35 ` Michael Bommarito
  2026-06-02 13:35 ` [PATCH net 4/4] tipc: reject inverted service ranges from peer bindings Michael Bommarito
  3 siblings, 0 replies; 5+ messages in thread
From: Michael Bommarito @ 2026-06-02 13:35 UTC (permalink / raw)
  To: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel

tipc_sk_conn_proto_rcv() subtracts the peer-supplied connection ack
count from the unsigned 16-bit send counter snt_unacked without
checking that it does not exceed the number of messages actually
outstanding:

	tsk->snt_unacked -= msg_conn_ack(hdr);

msg_conn_ack() is read straight from a received CONN_MANAGER/CONN_ACK
message. If the ack count is larger than snt_unacked the subtraction
wraps to a near-maximum value, leaving tsk_conn_cong() permanently true
and starving the connection of further transmits.

Cap the ack to the outstanding count before subtracting. A peer (or,
for a local connection, the connected peer socket) can otherwise wedge
a TIPC connection's send side by sending an oversized connection ack.

Fixes: 10724cc7bb78 ("tipc: redesign connection-level flow control")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 net/tipc/socket.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 9329919fb07f0..9c739a3cea126 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1362,9 +1362,16 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
 			__skb_queue_tail(xmitq, skb);
 		return;
 	} else if (mtyp == CONN_ACK) {
+		u16 conn_ack = msg_conn_ack(hdr);
+
 		was_cong = tsk_conn_cong(tsk);
 		tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr));
-		tsk->snt_unacked -= msg_conn_ack(hdr);
+		/* Cap a peer-supplied ack so a forged value cannot underflow
+		 * the unsigned counter and wedge connection flow control.
+		 */
+		if (conn_ack > tsk->snt_unacked)
+			conn_ack = tsk->snt_unacked;
+		tsk->snt_unacked -= conn_ack;
 		if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL)
 			tsk->snd_win = msg_adv_win(hdr);
 		if (was_cong && !tsk_conn_cong(tsk))
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net 4/4] tipc: reject inverted service ranges from peer bindings
  2026-06-02 13:35 [PATCH net 0/4] tipc: fix missing netlink admin gate and receive-path bugs Michael Bommarito
                   ` (2 preceding siblings ...)
  2026-06-02 13:35 ` [PATCH net 3/4] tipc: prevent snt_unacked underflow on CONN_ACK Michael Bommarito
@ 2026-06-02 13:35 ` Michael Bommarito
  3 siblings, 0 replies; 5+ messages in thread
From: Michael Bommarito @ 2026-06-02 13:35 UTC (permalink / raw)
  To: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel

tipc_update_nametbl() inserts a binding advertised by a peer node using
the lower and upper service-range bounds taken directly from the wire,
without checking that lower <= upper. The local bind path validates the
ordering (tipc_uaddr_valid()), but the name-distribution path does not.

A binding with lower > upper is inserted at the far end of the
service-range rbtree (keyed on lower) where no lookup or withdrawal can
ever match it (service_range_foreach_match() requires sr->lower <= end).
The publication, its service_range node and the augmented rbtree entry
are then leaked for the lifetime of the namespace, and there is no
per-peer cap equivalent to TIPC_MAX_PUBL on locally created bindings.

Reject inverted ranges in the network path as well. A peer node can
otherwise leak unbounded binding-table memory by sending PUBLICATION
items with lower > upper.

Fixes: 37922ea4a310 ("tipc: permit overlapping service ranges in name table")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 net/tipc/name_distr.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 190b49c5cbc3e..b4ff074a2babd 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -283,9 +283,18 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
 	struct tipc_socket_addr sk;
 	struct tipc_uaddr ua;
 	u32 key = ntohl(i->key);
+	u32 lower = ntohl(i->lower);
+	u32 upper = ntohl(i->upper);
+
+	/* A peer-advertised binding with lower > upper can never be matched
+	 * or withdrawn and would leak the publication; the local bind path
+	 * rejects such ranges, so reject ranges learned from the network too.
+	 */
+	if (lower > upper)
+		return false;
 
 	tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
-		   ntohl(i->type), ntohl(i->lower), ntohl(i->upper));
+		   ntohl(i->type), lower, upper);
 	sk.ref = ntohl(i->port);
 	sk.node = node;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-06-02 13:36 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02 13:35 [PATCH net 0/4] tipc: fix missing netlink admin gate and receive-path bugs Michael Bommarito
2026-06-02 13:35 ` [PATCH net 1/4] tipc: require net admin for TIPCv2 netlink mutators Michael Bommarito
2026-06-02 13:35 ` [PATCH net 2/4] tipc: validate discovery message length before reading media address Michael Bommarito
2026-06-02 13:35 ` [PATCH net 3/4] tipc: prevent snt_unacked underflow on CONN_ACK Michael Bommarito
2026-06-02 13:35 ` [PATCH net 4/4] tipc: reject inverted service ranges from peer bindings Michael Bommarito

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox