Netdev List
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: netdev@vger.kernel.org
Cc: dsahern@kernel.org, Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH iproute2 09/11] ss: check owner before naming a netlink socket
Date: Thu, 12 Nov 2026 11:59:22 -0800	[thread overview]
Message-ID: <20261112200046.2164391-10-stephen@networkplumber.org> (raw)
In-Reply-To: <20261112200046.2164391-1-stephen@networkplumber.org>

The netlink port id was taken as the pid of the owning process,
but any process can bind any free port id, so ss could show (and
report the SELinux context of) an unrelated process.

Only name the process if it holds the socket. Port ids that cannot
be checked are shown as numbers.

Reported-by: Anthropic OSS scanner (ANT-2026-1FCHVE1N)
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 man/man8/ss.8 |  3 ++-
 misc/ss.c     | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/man/man8/ss.8 b/man/man8/ss.8
index 54af744a..96d25ab0 100644
--- a/man/man8/ss.8
+++ b/man/man8/ss.8
@@ -337,7 +337,8 @@ sockets the initiating process context is displayed as follows:
 .RS
 .RS
 .IP "1." 4
-If valid pid show the process context.
+If the port id is the pid of a process holding the socket, show the process
+context.
 .IP "2." 4
 If destination is kernel (pid = 0) show kernel initial context.
 .IP "3." 4
diff --git a/misc/ss.c b/misc/ss.c
index 9d2f9891..6d37f676 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -4662,10 +4662,47 @@ static int xdp_show(struct filter *f)
 	return handle_netlink_request(f, &req.nlh, sizeof(req), xdp_show_sock);
 }
 
+/* A netlink port id is chosen by whoever binds the socket; it is the
+ * pid of the owner only by convention. Check that the process holds it.
+ */
+static bool netlink_pid_holds_sock(int pid, unsigned int ino)
+{
+	char path[MAX_PATH_LEN];
+	struct dirent *d;
+	bool ret = false;
+	DIR *dir;
+
+	if (pid <= 0 || !ino)
+		return false;
+
+	snprintf(path, sizeof(path), "%s/%d/fd",
+		 getenv("PROC_ROOT") ? : "/proc", pid);
+	dir = opendir(path);
+	if (!dir)
+		return false;
+
+	while (!ret && (d = readdir(dir)) != NULL) {
+		unsigned int fd_ino;
+		ssize_t link_len;
+		char lnk[64];
+
+		link_len = readlinkat(dirfd(dir), d->d_name, lnk, sizeof(lnk) - 1);
+		if (link_len == -1)
+			continue;
+		lnk[link_len] = '\0';
+
+		if (sscanf(lnk, "socket:[%u]", &fd_ino) == 1)
+			ret = fd_ino == ino;
+	}
+	closedir(dir);
+
+	return ret;
+}
+
 static int netlink_show_one(struct filter *f,
 				int prot, int pid, unsigned int groups,
 				int state, int dst_pid, unsigned int dst_group,
-				int rq, int wq,
+				int rq, int wq, unsigned int ino,
 				unsigned long long sk, unsigned long long cb)
 {
 	struct sockstat st = {
@@ -4679,6 +4716,7 @@ static int netlink_show_one(struct filter *f,
 	SPRINT_BUF(prot_buf) = {};
 	const char *prot_name;
 	char procname[64] = {};
+	bool is_owner = false;
 
 	if (f->f) {
 		st.rport = -1;
@@ -4692,6 +4730,9 @@ static int netlink_show_one(struct filter *f,
 
 	prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
 
+	if (pid > 0 && (!numeric || show_proc_ctx))
+		is_owner = netlink_pid_holds_sock(pid, ino);
+
 	if (pid == -1) {
 		procname[0] = '*';
 	} else if (!numeric) {
@@ -4701,7 +4742,7 @@ static int netlink_show_one(struct filter *f,
 		if (!pid) {
 			done = 1;
 			strncpy(procname, "kernel", 7);
-		} else if (pid > 0) {
+		} else if (is_owner) {
 			if (get_task_name(getenv("PROC_ROOT"), pid,
 					  task, sizeof(task)) == 0) {
 				escape_str(procname, task, sizeof(procname));
@@ -4734,13 +4775,13 @@ static int netlink_show_one(struct filter *f,
 	if (show_proc_ctx) {
 		/* The pid value will either be:
 		 *   0 if destination kernel - show kernel initial context.
-		 *   A valid process pid - use getpidcon.
+		 *   The pid of a process holding the socket - use getpidcon.
 		 *   A unique value allocated by the kernel or netlink user
 		 *   to the process - show context as "not available".
 		 */
 		if (!pid)
 			security_get_initial_context("kernel", &pid_context);
-		else if (pid > 0)
+		else if (is_owner)
 			getpidcon(pid, &pid_context);
 
 		out(" proc_ctx=%s", pid_context ? : "unavailable");
@@ -4779,7 +4820,7 @@ static int netlink_show_sock(struct nlmsghdr *nlh, void *arg)
 
 	if (netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
 			 r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
-			 rq, wq, 0, 0)) {
+			 rq, wq, r->ndiag_ino, 0, 0)) {
 		return 0;
 	}
 
-- 
2.53.0


  parent reply	other threads:[~2026-11-12 20:00 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 19:59 [PATCH iproute2 00/11] ss fixes from an OSS scan Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 01/11] ss: fix double close on sock_diag send failure Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 02/11] ss: drop /proc fallback for socket listing Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 03/11] ss: escape names chosen by the socket owner Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 04/11] ss: size the TCPDIAG_FILE buffer to the record Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 05/11] ss: replay all dumps in TCPDIAG_FILE Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 06/11] ss: bound state and type name lookups Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 07/11] ss: fix rpcbind service cache Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 08/11] ss: read socket SELinux context only for -z Stephen Hemminger
2026-11-12 19:59 ` Stephen Hemminger [this message]
2026-11-12 19:59 ` [PATCH iproute2 10/11] ss: keep following events after ENOBUFS Stephen Hemminger
2026-11-12 19:59 ` [PATCH iproute2 11/11] ss: report a failed SCTP or MPTCP dump Stephen Hemminger
  -- strict thread matches above, loose matches on Subject: below --
2026-11-09 21:25 [PATCH iproute2 00/11] ss fixes from an OSS scan Stephen Hemminger
2026-11-09 21:25 ` [PATCH iproute2 09/11] ss: check owner before naming a netlink socket Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261112200046.2164391-10-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=dsahern@kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox