All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2 v2 0/2] ss: fix vsock port filtering
@ 2026-08-17 12:54 Luigi Leonardi
  2026-08-17 12:54 ` [PATCH iproute2 v2 1/2] ss: move lport and rport in struct sockstat from int to long Luigi Leonardi
  2026-08-17 12:54 ` [PATCH iproute2 v2 2/2] ss: fix vsock port filter Luigi Leonardi
  0 siblings, 2 replies; 3+ messages in thread
From: Luigi Leonardi @ 2026-08-17 12:54 UTC (permalink / raw)
  To: Stefano Garzarella, Stefan Hajnoczi, netdev, Luigi Leonardi
  Cc: Stephen Hemminger

Vsock port filtering is broken for ports in [1, 2^31−1] (i.e. any port
whose u32 representation has bit 31 clear, which includes all ordinarily
assigned vsock ports).

To reproduce:

    ncat -l --vsock -p 27354
    ss --vsock -l src :27354   # shows nothing

    # Without the filter the socket is visible:
    ss --vsock -l

Ports in [2^31, UINT_MAX−1] are not affected by accident.

aafilter.port was extended to 8 bytes to support unix socket inode
numbers larger than INT_MAX (see 012cb515). The vsock parsing path
initialises a.port to -1L and then calls get_u32() via a cast to write
the user-supplied port into it. get_u32() only writes 4 bytes, leaving
the upper 32 bits as 0xFFFFFFFF. For ports < 2^31 this produces a
mismatch with sockstat.lport.
For ports >= 2^31 the int-to-long sign extension also fills
the upper 32 bits with 0xFFFFFFFF, accidentally matching the corrupted
a.port and hiding the bug.

Commit 1 switches from int to long for sockstat.lport/rport
Commit 2 fixes a bug in the parsing of the filter port, that didn't
clear the upper bits.

Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
Changes in v2:
- Expanded lport and rport in sockstat from int to long [Stefano]
- Applied suggestion from Stephen for port filtering.
- Link to v1: https://lore.kernel.org/all/20260421-fix_vsock-v1-1-812c80a76c1a@redhat.com

---
Luigi Leonardi (2):
      ss: move lport and rport in struct sockstat from int to long
      ss: fix vsock port filter

 misc/ss.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)
---
base-commit: da2ccdf862cb1eab45de082cc71fcb4e5d712e78
change-id: 20260817-fix_vsock-f7b374d5cadd

Best regards,
-- 
Luigi Leonardi <leonardi@redhat.com>


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

* [PATCH iproute2 v2 1/2] ss: move lport and rport in struct sockstat from int to long
  2026-08-17 12:54 [PATCH iproute2 v2 0/2] ss: fix vsock port filtering Luigi Leonardi
@ 2026-08-17 12:54 ` Luigi Leonardi
  2026-08-17 12:54 ` [PATCH iproute2 v2 2/2] ss: fix vsock port filter Luigi Leonardi
  1 sibling, 0 replies; 3+ messages in thread
From: Luigi Leonardi @ 2026-08-17 12:54 UTC (permalink / raw)
  To: Stefano Garzarella, Stefan Hajnoczi, netdev, Luigi Leonardi

Commit 012cb515 ("ss: change aafilter port from int to long (inode
support)") widened aafilter.port to long so that unix socket inode
numbers larger than INT_MAX can be used as port filter values, but left
sockstat.lport and sockstat.rport as int. This means large u32 values
(e.g. vsock ports or unix inodes > INT_MAX) are truncated on the
socket-stat side, making the comparison against aafilter.port always
fail.

Widen lport and rport to long and update the sscanf format specifiers
in proc_parse_inet_addr() and unix_show() accordingly.

Fixes: 012cb515 ("ss: change aafilter port from int to long (inode support)")
Suggested-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
 misc/ss.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index 14e9f27a..ff1a88de 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -809,8 +809,8 @@ struct sockstat {
 	uint16_t	    raw_prot;
 	inet_prefix	    local;
 	inet_prefix	    remote;
-	int		    lport;
-	int		    rport;
+	long		    lport;
+	long		    rport;
 	int		    state;
 	int		    rq, wq;
 	unsigned int ino;
@@ -2490,23 +2490,23 @@ static int proc_parse_inet_addr(char *loc, char *rem, int family, struct
 {
 	s->local.family = s->remote.family = family;
 	if (family == AF_INET) {
-		sscanf(loc, "%x:%x", s->local.data, (unsigned *)&s->lport);
-		sscanf(rem, "%x:%x", s->remote.data, (unsigned *)&s->rport);
+		sscanf(loc, "%x:%lx", s->local.data, (unsigned long *)&s->lport);
+		sscanf(rem, "%x:%lx", s->remote.data, (unsigned long *)&s->rport);
 		s->local.bytelen = s->remote.bytelen = 4;
 		return 0;
 	} else {
-		sscanf(loc, "%08x%08x%08x%08x:%x",
+		sscanf(loc, "%08x%08x%08x%08x:%lx",
 		       s->local.data,
 		       s->local.data + 1,
 		       s->local.data + 2,
 		       s->local.data + 3,
-		       &s->lport);
-		sscanf(rem, "%08x%08x%08x%08x:%x",
+		       (unsigned long *)&s->lport);
+		sscanf(rem, "%08x%08x%08x%08x:%lx",
 		       s->remote.data,
 		       s->remote.data + 1,
 		       s->remote.data + 2,
 		       s->remote.data + 3,
-		       &s->rport);
+		       (unsigned long *)&s->rport);
 		s->local.bytelen = s->remote.bytelen = 16;
 		return 0;
 	}
@@ -4638,8 +4638,8 @@ static int unix_show(struct filter *f)
 		if (!(u = calloc(1, sizeof(*u))))
 			break;
 
-		if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
-			   &u->rport, &u->rq, &u->wq, &flags, &u->type,
+		if (sscanf(buf, "%lx: %x %x %x %x %x %d %s",
+			   (unsigned long *)&u->rport, &u->rq, &u->wq, &flags, &u->type,
 			   &u->state, &u->ino, name) < 8)
 			name[0] = 0;
 

-- 
2.55.0


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

* [PATCH iproute2 v2 2/2] ss: fix vsock port filter
  2026-08-17 12:54 [PATCH iproute2 v2 0/2] ss: fix vsock port filtering Luigi Leonardi
  2026-08-17 12:54 ` [PATCH iproute2 v2 1/2] ss: move lport and rport in struct sockstat from int to long Luigi Leonardi
@ 2026-08-17 12:54 ` Luigi Leonardi
  1 sibling, 0 replies; 3+ messages in thread
From: Luigi Leonardi @ 2026-08-17 12:54 UTC (permalink / raw)
  To: Stefano Garzarella, Stefan Hajnoczi, netdev, Luigi Leonardi
  Cc: Stephen Hemminger

parse_hostcond() initializes aafilter.port to -1L (0xFFFFFFFFFFFFFFFF)
as a sentinel for "no port filter". When parsing a vsock port it called
get_u32() via a cast:

    get_u32((__u32 *)&a.port, port, 0)

get_u32() only writes 4 bytes, leaving the upper 32 bits of the 8-byte
long set from the -1 initialization. For example, for port 27354 this
produces 0xFFFFFFFF00006ADA, which never compares equal to sockstat.lport and
causes all vsock port filters to silently match nothing.

Fix by parsing into a temporary __u32 and assigning it to a.port, which
zero-extends the value correctly. When the user specifies '*' the if
block is skipped entirely and the -1 sentinel is preserved.

Fixes: 012cb515 ("ss: change aafilter port from int to long (inode support)")
Suggested-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
 misc/ss.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/misc/ss.c b/misc/ss.c
index ff1a88de..a3570715 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -2322,9 +2322,13 @@ void *parse_hostcond(char *addr, bool is_port)
 
 		port = find_port(addr, is_port);
 
-		if (port && strcmp(port, "*") &&
-		    get_u32((__u32 *)&a.port, port, 0))
-			return NULL;
+		if (port && strcmp(port, "*")) {
+			__u32 vport;
+
+			if (get_u32(&vport, port, 0))
+				return NULL;
+			a.port = vport;
+		}
 
 		if (!is_port && addr[0] && strcmp(addr, "*")) {
 			a.addr.bitlen = 32;

-- 
2.55.0


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

end of thread, other threads:[~2026-08-17 12:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17 12:54 [PATCH iproute2 v2 0/2] ss: fix vsock port filtering Luigi Leonardi
2026-08-17 12:54 ` [PATCH iproute2 v2 1/2] ss: move lport and rport in struct sockstat from int to long Luigi Leonardi
2026-08-17 12:54 ` [PATCH iproute2 v2 2/2] ss: fix vsock port filter Luigi Leonardi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.