From nobody Fri Apr 3 06:54:52 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fn8c22RY7z6Y5Fs for ; Fri, 03 Apr 2026 06:54:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fn8c20wHcz3fJC for ; Fri, 03 Apr 2026 06:54:58 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775199298; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hfuZMW1JNgyPXGqYqx+HQOqcp2MPUdEORuSo5C4GJgM=; b=TuA7K3lo1ITYyKLA52NPsTXvIo0IoohBGrVkPGfPZxNx1zQwCX8IH2qtl2CN8RJEY5kd3B 4iPg5lbrvZE12yMm6P7VV+l56OU+junE0fXkU8NdwmkBIfi/9mgkRCf3Rd8elggRiLGW7E 7E1SeknBlPTl4Ow1T/rAIEJ2UkfS5iCW2ku5LfcsNh5w2CuAYa+tL8TeBPqSSXpFoMX9hL ChJIntAZ/0DBlVbHMzE0Z7EqmSLpqT8p2zQWmTfg3/R6anyh8C51T321c1bVjG5ow5VEqZ WOX8D9IjBo8PBkDOKj6p5AotmMzjbeQngYSibWBHto2hkLMBaDTB2CTk87LWaA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1775199298; a=rsa-sha256; cv=none; b=SiZnVO0aBE4v8V0ywF3ztquwrz+Z7GSJOqS9lQ4UaSAw0fKBbj/DnQeA0Ggh6jAg6sV1K1 V1QirYOOxIS3sP4EhrDT6lK2EXwg1bcrbZEhwtMo9GJAmdJDZ7Vh+9tdTYuEq+wGP44Yqn 1yhzeROCxS6hmL8DA0qs8BKjpcJMponX2VnegWruo7GOslZlK6UBD0j3vlqX4yu+rYOYoE CJ4OJzr2/z01xaxYsUE1PDgahiaR/4RwWbLORV5od2k9nsYkqe51EDLvnBYWDYKPmb5CYa lC5dDcjA0NekbRyZ+EfrNZtpJso72RHEfjhvXbqksJNDUnLm5NNh+rsFoGbfYQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775199298; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hfuZMW1JNgyPXGqYqx+HQOqcp2MPUdEORuSo5C4GJgM=; b=bMRmqcUuS3fU5eU0TRiMMn7yPY3PnVxOZJAbZDB/hVwxm5fQ0EGoUCshCSgXzJ0FEr/Ytp +hbvqrUkWJ4mE9vUvT0slTD3KZtlX9pFXnPBSkUiq4P/tDIQsuZDEc5yH2CAh5eg2QRI8f v7qD19O/nb084sR1z5b7LgEnvvKSmqH4JIEjaUldDKmxMEngPXRyDQZk2Z4MPFvcjT1jqQ Ork8F47Nmha0xGu6XodQEir0XNeSXky99x6qxEkhlZMX6kHYm2R8PdXPqeYkv0lL0iua4r saRB89MVUBjbCSe8pJisRuvdZ6Q2whUeFCqToM/Pc3SUR5u0AjGrC9QzROsWZA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fn8c20SnNzdg4 for ; Fri, 03 Apr 2026 06:54:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 2356e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 03 Apr 2026 06:54:52 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Ishan Agrawal From: Kristof Provost Subject: git: 8ef0093f297a - main - truss: add support for decoding Netlink messages List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 8ef0093f297af7c917037f058af9813105e67662 Auto-Submitted: auto-generated Date: Fri, 03 Apr 2026 06:54:52 +0000 Message-Id: <69cf643c.2356e.2d0a0374@gitrepo.freebsd.org> The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=8ef0093f297af7c917037f058af9813105e67662 commit 8ef0093f297af7c917037f058af9813105e67662 Author: Ishan Agrawal AuthorDate: 2026-01-06 12:05:59 +0000 Commit: Kristof Provost CommitDate: 2026-04-03 06:52:29 +0000 truss: add support for decoding Netlink messages Netlink usage is growing in FreeBSD. This patch adds support to `truss(1)` to decode Netlink headers in sendmsg/recvmsg calls, making debugging network configuration tools significantly easier. Changes: libsysdecode: Add `sysdecode_netlink()` to parse struct `nlmsghdr`. truss: Detect `AF_NETLINK` sockets and decode the message payload. Reviewed by: kp Signed-off-by: Ishan Agrawal Github PR: https://github.com/freebsd/freebsd-src/pull/1950 --- lib/libsysdecode/Makefile | 2 +- lib/libsysdecode/netlink.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ lib/libsysdecode/sysdecode.h | 1 + usr.bin/truss/syscalls.c | 67 ++++++++++++++++++++++++++++++- 4 files changed, 162 insertions(+), 2 deletions(-) diff --git a/lib/libsysdecode/Makefile b/lib/libsysdecode/Makefile index 60422d3fc9ef..85c76bcffd8e 100644 --- a/lib/libsysdecode/Makefile +++ b/lib/libsysdecode/Makefile @@ -2,7 +2,7 @@ LIB= sysdecode -SRCS= errno.c flags.c ioctl.c signal.c syscallnames.c utrace.c support.c +SRCS= errno.c flags.c ioctl.c netlink.c signal.c syscallnames.c utrace.c support.c .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \ ${MACHINE_CPUARCH} == "i386" SRCS+= linux.c diff --git a/lib/libsysdecode/netlink.c b/lib/libsysdecode/netlink.c new file mode 100644 index 000000000000..a28a0a061134 --- /dev/null +++ b/lib/libsysdecode/netlink.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2026 Ishan Agrawal + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include +#include +#include + +#include "sysdecode.h" + +/* + * Decodes a buffer as a Netlink message stream. + * + * Returns true if the data was successfully decoded as Netlink. + * Returns false if the data is malformed, allowing the caller + * to fallback to a standard hex/string dump. + */ +bool +sysdecode_netlink(FILE *fp, const void *buf, size_t len) +{ + const struct nlmsghdr *nl = buf; + size_t remaining = len; + bool first = true; + + /* Basic sanity check: Buffer must be at least one header size. */ + if (remaining < sizeof(struct nlmsghdr)) + return (false); + + /* * Protocol Sanity Check: + * The first message length must be valid (>= header) and fit + * inside the provided buffer snapshot. + */ + if (nl->nlmsg_len < sizeof(struct nlmsghdr) || nl->nlmsg_len > remaining) + return (false); + + fprintf(fp, "netlink{"); + + while (remaining >= sizeof(struct nlmsghdr)) { + if (!first) + fprintf(fp, ","); + + /* Safety check for current message. */ + if (nl->nlmsg_len < sizeof(struct nlmsghdr) || + nl->nlmsg_len > remaining) { + fprintf(fp, ""); + break; + } + + fprintf(fp, "len=%u,type=", nl->nlmsg_len); + + /* Decode Standard Message Types. */ + switch (nl->nlmsg_type) { + case NLMSG_NOOP: + fprintf(fp, "NLMSG_NOOP"); + break; + case NLMSG_ERROR: + fprintf(fp, "NLMSG_ERROR"); + break; + case NLMSG_DONE: + fprintf(fp, "NLMSG_DONE"); + break; + case NLMSG_OVERRUN: + fprintf(fp, "NLMSG_OVERRUN"); + break; + default: + fprintf(fp, "%u", nl->nlmsg_type); + break; + } + + fprintf(fp, ",flags="); + /* TODO: decode flags symbolically using sysdecode_mask. */ + fprintf(fp, "0x%x", nl->nlmsg_flags); + + fprintf(fp, ",seq=%u,pid=%u", nl->nlmsg_seq, nl->nlmsg_pid); + + /* Handle Alignment (Netlink messages are 4-byte aligned). */ + size_t aligned_len = NLMSG_ALIGN(nl->nlmsg_len); + if (aligned_len > remaining) + remaining = 0; + else + remaining -= aligned_len; + + nl = (const struct nlmsghdr *)(const void *)((const char *)nl + aligned_len); + first = false; + } + + fprintf(fp, "}"); + return (true); +} diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h index c95d7f71379b..dad9d447478c 100644 --- a/lib/libsysdecode/sysdecode.h +++ b/lib/libsysdecode/sysdecode.h @@ -134,6 +134,7 @@ 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); #if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index 7b299bd2e1ff..abb9d18d6783 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -1568,6 +1569,66 @@ user_ptr32_to_psaddr(int32_t user_pointer) return ((psaddr_t)(uintptr_t)user_pointer); } +#define NETLINK_MAX_DECODE 4096 + +/* + * Reads the first IOV and attempts to print it as Netlink using libsysdecode. + * Returns true if successful, false if fallback to standard print is needed. + */ +static bool +print_netlink(FILE *fp, struct trussinfo *trussinfo, struct msghdr *msg) +{ + struct sockaddr_storage ss; + struct iovec iov; + struct ptrace_io_desc piod; + char *buf; + pid_t pid = trussinfo->curthread->proc->pid; + bool success = false; + + /* Only decode AF_NETLINK sockets. */ + if (msg->msg_name == NULL || msg->msg_namelen < offsetof(struct sockaddr, sa_data) + || msg->msg_iovlen == 0 || msg->msg_iov == NULL) + return (false); + + if (get_struct(pid, (uintptr_t)msg->msg_name, &ss, + MIN(sizeof(ss), msg->msg_namelen)) == -1) + return (false); + + if (ss.ss_family != AF_NETLINK) + return (false); + + if (get_struct(pid, (uintptr_t)msg->msg_iov, &iov, sizeof(iov)) == -1) + return (false); + + /* Cap read size to avoid unbounded allocations. */ + size_t read_len = MIN(iov.iov_len, NETLINK_MAX_DECODE); + if (read_len == 0) + return (false); + + buf = malloc(read_len); + if (buf == NULL) + return (false); + + /* Snapshot User Memory using PTRACE. */ + piod.piod_op = PIOD_READ_D; + piod.piod_offs = iov.iov_base; + piod.piod_addr = buf; + piod.piod_len = read_len; + + if (ptrace(PT_IO, pid, (caddr_t)&piod, 0) == -1) { + free(buf); + return (false); + } + + /* Delegate Decoding to libsysdecode. */ + if (sysdecode_netlink(fp, buf, read_len)) { + success = true; + } + free(buf); + + return (success); +} + /* * Converts a syscall argument into a string. Said string is * allocated via malloc(), so needs to be free()'d. sc is @@ -2706,7 +2767,11 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval, fputs("{", fp); print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen); fprintf(fp, ",%d,", msghdr.msg_namelen); - print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen); + /* Attempt Netlink decode; fallback to standard iovec if it fails. */ + if (!print_netlink(fp, trussinfo, &msghdr)) { + print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, + msghdr.msg_iovlen); + } fprintf(fp, ",%d,", msghdr.msg_iovlen); print_cmsgs(fp, pid, sc->type & OUT, &msghdr); fprintf(fp, ",%u,", msghdr.msg_controllen);