git: 8a1576dc26b9 - main - truss: track Netlink socket protocols

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Sun, 05 Jul 2026 14:15:53 UTC
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=8a1576dc26b90706948061e5ed33f07a03a5899c

commit 8a1576dc26b90706948061e5ed33f07a03a5899c
Author:     Ishan Agrawal <iagrawal9990@gmail.com>
AuthorDate: 2026-07-04 03:40:31 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2026-07-05 14:03:20 +0000

    truss: track Netlink socket protocols
    
    Record the Netlink protocol associated with AF_NETLINK sockets when
    they are created and pass it to libsysdecode during message decoding.
    
    Use the protocol to distinguish between Generic Netlink and Route
    Netlink sockets, ensuring that Generic Netlink decoding is only
    performed for NETLINK_GENERIC sockets.
    
    Signed-off-by:  Ishan Agrawal <iagrawal9990@gmail.com>
    Reviewed by:    kp
    Sponsored-by :  Google LLC (GSoC 2026)
---
 lib/libsysdecode/netlink.c   |  2 +-
 lib/libsysdecode/sysdecode.h |  3 ++-
 usr.bin/truss/setup.c        |  1 +
 usr.bin/truss/syscalls.c     | 32 ++++++++++++++++++++------------
 usr.bin/truss/truss.h        |  1 +
 5 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/lib/libsysdecode/netlink.c b/lib/libsysdecode/netlink.c
index 2143a0d391a5..723272d3b8da 100644
--- a/lib/libsysdecode/netlink.c
+++ b/lib/libsysdecode/netlink.c
@@ -21,7 +21,7 @@
  * to fallback to a standard hex/string dump.
  */
 bool
-sysdecode_netlink(FILE *fp, const void *buf, size_t len)
+sysdecode_netlink(FILE *fp, const void *buf, size_t len, int protocol)
 {
 	const struct nlmsghdr *nl = buf;
 	size_t remaining = len;
diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h
index 3675a582a9b8..bd38bb5bdc42 100644
--- a/lib/libsysdecode/sysdecode.h
+++ b/lib/libsysdecode/sysdecode.h
@@ -136,7 +136,8 @@ bool	sysdecode_wait4_options(FILE *_fp, int _options, int *_rem);
 bool	sysdecode_wait6_options(FILE *_fp, int _options, int *_rem);
 const char *sysdecode_whence(int _whence);
 bool	sysdecode_shmflags(FILE *_fp, int _flags, int *_rem);
-bool	sysdecode_netlink(FILE *_fp, const void *_buf, size_t _len);
+bool	sysdecode_netlink(FILE *_fp, const void *_buf, size_t _len,
+    int _protocol);
 
 #if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
 
diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c
index ecc4a1792144..d35b392aba1e 100644
--- a/usr.bin/truss/setup.c
+++ b/usr.bin/truss/setup.c
@@ -587,6 +587,7 @@ exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
 
 		f->fd = (int)psr.sr_retval[0];
 		f->domain = (int)t->cs.args[0];
+		f->protocol = (int)t->cs.args[2];
 
 		LIST_INSERT_HEAD(&p->fdlist, f, entries);
 	}
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index dbc621124071..a92c903dc691 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -1573,17 +1573,17 @@ user_ptr32_to_psaddr(int32_t user_pointer)
  * Check whether a file descriptor belongs to an AF_NETLINK socket
  * for the current traced process.
  */
-static bool
-is_netlink(struct trussinfo *trussinfo, int num_fd)
+static int
+get_netlink_protocol(struct trussinfo *trussinfo, int num_fd)
 {
 	struct procinfo *p = trussinfo->curthread->proc;
 	struct fd_domain *f;
 
 	LIST_FOREACH(f, &p->fdlist, entries) {
 		if (f->fd == num_fd && f->domain == AF_NETLINK)
-			return (true);
+			return (f->protocol);
 	}
-	return (false);
+	return (-1);
 }
 
 #define NETLINK_MAX_DECODE 4096
@@ -1593,7 +1593,8 @@ is_netlink(struct trussinfo *trussinfo, int num_fd)
  * and attempt to decode and print it.
  */
 static bool
-print_netlink(FILE *fp, struct trussinfo *trussinfo, void *msg, size_t len)
+print_netlink(FILE *fp, struct trussinfo *trussinfo, void *msg, size_t len,
+    int protocol)
 {
 	char *buf;
 	pid_t pid = trussinfo->curthread->proc->pid;
@@ -1615,7 +1616,7 @@ print_netlink(FILE *fp, struct trussinfo *trussinfo, void *msg, size_t len)
 		return (false);
 	}
 
-	if (sysdecode_netlink(fp, buf, read_len)) {
+	if (sysdecode_netlink(fp, buf, read_len, protocol)) {
 		success = true;
 	}
 	free(buf);
@@ -1690,12 +1691,18 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
 	}
 	case BinString: {
 		if ((strcmp(decode->name, "sendto") == 0 ||
-		    strcmp(decode->name, "recvfrom") == 0) &&
-		    is_netlink(trussinfo, (int)args[0]))
-			if (print_netlink(fp, trussinfo,
+		    strcmp(decode->name, "recvfrom") == 0)) {
+
+			int protocol =
+			    get_netlink_protocol(trussinfo, (int)args[0]);
+
+			if ((protocol != -1) &&
+			    print_netlink(fp, trussinfo,
 			    (void *)args[sc->offset],
-			    (size_t)args[sc->offset + 1]))
+			    (size_t)args[sc->offset + 1],
+			    protocol))
 				break;
+		}
 		/*
 		 * Binary block of data that might have printable characters.
 		 * XXX If type|OUT, assume that the length is the syscall's
@@ -2770,11 +2777,12 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
 		print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen);
 		fprintf(fp, ",%d,", msghdr.msg_namelen);
 		/* Attempt Netlink decode; fallback to standard iovec if it fails. */
-		if ((!is_netlink(trussinfo, (int)args[0])) ||
+		int protocol = get_netlink_protocol(trussinfo, (int)args[0]);
+		if ((protocol == -1) ||
 		    (get_struct(pid, (uintptr_t)msghdr.msg_iov,
 		    &iov, sizeof(iov)) == -1) ||
 		    (!print_netlink(fp, trussinfo, (void *)iov.iov_base,
-		    (size_t)iov.iov_len))) {
+		    (size_t)iov.iov_len, protocol))) {
 			print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov,
 			    msghdr.msg_iovlen);
 		}
diff --git a/usr.bin/truss/truss.h b/usr.bin/truss/truss.h
index 737ebc184806..077460fe4090 100644
--- a/usr.bin/truss/truss.h
+++ b/usr.bin/truss/truss.h
@@ -100,6 +100,7 @@ struct fd_domain
 
 	int fd;
 	int domain;
+	int protocol;
 };
 
 struct procinfo {