tGl/R/x/56Yn5jMG13kdqqXyXN0 2+lUyeRBtTSbgzglriW6/YTmlqE1gYosHmGo5pRAYVBf7M9vcg0tsgjuN8e99ttJVOXXMJ 65aCGeBPJdM8pgToE0FfbYZoMiN5apDuBkf5ekSLKSg4p7+dU8oXazxifYN1wijQybGVr0 wRqqGUEy9l0REFA8pnaD/Jj0z5dZHzy1dGzxVSnJBwj2yQojfqveg+l6+TfEC++P+tk9T8 4BSqyoIyF79VXQgDx5SrZD+QAqoPzx0UpBIMR4xQVwQ+trJJSGY8X7/fOLajHw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1777474135; a=rsa-sha256; cv=none; b=ChtKw5avAei3FY1XFt5qZVBmqq8FXkBppL9425j4QKM5bx/IRErYnvyICqgDrMEf9oIxYX TFBlPUCyDHtPZY33tXHxSV6Tyhe1XRPiRjkJQ+dC40ZFaKI/JwceueIdS7N4Pjr8jA79xP 4Anxou0QdE+TvmGCta8xf4Q6JJeYhJ1ndnD5epwzHEMUsnRbRi16sadoX0DHFG05ZzMr7a E3e9cdQPYDuk0NfxO61m8heCZ5nnh15p3j+G6JIOuYKqJV8yM7XaSYSWI9k9pUjDfGn49/ pPIQ+g5QYTsfRabsx9r4TQnbAo7nQBYCYxSEJt2GlXdA7kIRQRDojvdVNOEiRg== 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=1777474135; 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=CSSLt6PbThHMRwZk/31dD82s8vP/jfimwkMTBNPq07s=; b=AcAhKEdaY27Ns9UUNs++Dn+Wu4ppaMwN9rIqWz6bkMLEBKOYunMk/1UEr/ClGibyKuHBUh SgfHh9pGF2Jl19abrvjrOb/z3B3pJJwu6aJmC1XQKA5U0P+elJU9kryq5jqqEpgneXEaVN 8jBdWZUH+e7PnxoAoomtWODP+hL4Ynl7E8pZO4XGvKmifzGv277C8vgOObSy+/ItvVvd2U TAsUB70UqggbFfmFWtpOyC4YCB9gKBBO6aGLBOei9wmzmvy+kugG2Xu9dOJR1o+OE/iMdR DNc6ACH+01EKG795tgjBfqHUSnfG/EeojsNiw8sJdPGOVXbkVL9wO41AeAXObA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4g5Ktv2HPHzl60 for ; Wed, 29 Apr 2026 14:48:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3d58c by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 29 Apr 2026 14:48:55 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: Mariusz Zaborski From: Mark Johnston Subject: git: 07296250c728 - stable/14 - libnv: add tests to verify potential overflow issues List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 07296250c728644cc071fe89344ec9f0705da014 Auto-Submitted: auto-generated Date: Wed, 29 Apr 2026 14:48:55 +0000 Message-Id: <69f21a57.3d58c.4e8f8088@gitrepo.freebsd.org> The branch stable/14 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=07296250c728644cc071fe89344ec9f0705da014 commit 07296250c728644cc071fe89344ec9f0705da014 Author: Mariusz Zaborski AuthorDate: 2024-08-29 13:46:01 +0000 Commit: Mark Johnston CommitDate: 2026-04-29 14:45:05 +0000 libnv: add tests to verify potential overflow issues Differential Revision: https://reviews.freebsd.org/D46131 (cherry picked from commit 241a7ddd7112982ed41ccdd047c1dad59ee0256e) --- lib/libnv/tests/Makefile | 9 ++ lib/libnv/tests/nvlist_send_recv_test.c | 193 ++++++++++++++++++++++++++++++++ sys/contrib/libnv/nv_impl.h | 8 ++ sys/contrib/libnv/nvlist.c | 7 -- 4 files changed, 210 insertions(+), 7 deletions(-) diff --git a/lib/libnv/tests/Makefile b/lib/libnv/tests/Makefile index fc377e38ce83..aea416539c4a 100644 --- a/lib/libnv/tests/Makefile +++ b/lib/libnv/tests/Makefile @@ -1,7 +1,16 @@ +.include ATF_TESTS_C= \ nvlist_send_recv_test +.PATH: ${SRCTOP}/lib/libnv +SRCS.nvlist_send_recv_test= msgio.c nvlist_send_recv_test.c +CFLAGS.nvlist_send_recv_test+=-I${SRCTOP}/sys/contrib/libnv +CFLAGS.nvlist_send_recv_test+=-I${SRCTOP}/lib/libnv +.if ${MK_ASAN} != "yes" +CFLAGS.nvlist_send_recv_test+=-DNO_ASAN +.endif + ATF_TESTS_CXX= \ cnv_tests \ dnv_tests \ diff --git a/lib/libnv/tests/nvlist_send_recv_test.c b/lib/libnv/tests/nvlist_send_recv_test.c index 5d4f392ed49c..cd97ccb6b9b9 100644 --- a/lib/libnv/tests/nvlist_send_recv_test.c +++ b/lib/libnv/tests/nvlist_send_recv_test.c @@ -44,6 +44,9 @@ #include +#include +#include + #define ALPHABET "abcdefghijklmnopqrstuvwxyz" #define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF) @@ -543,6 +546,192 @@ ATF_TC_BODY(nvlist_send_recv__send_closed_fd__stream, tc) nvlist_send_recv__send_closed_fd(SOCK_STREAM); } +ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_header_size); +ATF_TC_BODY(nvlist_send_recv__overflow_header_size, tc) +{ + nvlist_t *nvl; + void *packed; + size_t packed_size; + struct nvlist_header *header; + int fd, socks[2], status; + pid_t pid; + +#ifdef NO_ASAN + atf_tc_skip("This test requires ASAN"); +#endif + + ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + /* Child. */ + fd = socks[0]; + close(socks[1]); + + nvl = nvlist_create(0); + ATF_REQUIRE(nvl != NULL); + ATF_REQUIRE(nvlist_empty(nvl)); + + packed = nvlist_pack(nvl, &packed_size); + ATF_REQUIRE(packed != NULL); + ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header)); + + header = (struct nvlist_header *)packed; + header->nvlh_size = SIZE_MAX - sizeof(struct nvlist_header) + 2; + + ATF_REQUIRE_EQ(write(fd, packed, packed_size), + (ssize_t)sizeof(struct nvlist_header)); + + nvlist_destroy(nvl); + free(packed); + + exit(0); + } else { + /* Parent */ + fd = socks[1]; + close(socks[0]); + + errno = 0; + nvl = nvlist_recv(fd, 0); + ATF_REQUIRE(nvl == NULL); + + /* + * Make sure it has failed on EINVAL, and not on + * errors returned by malloc or recv. + */ + ATF_REQUIRE(errno == EINVAL); + + ATF_REQUIRE(waitpid(pid, &status, 0) == pid); + ATF_REQUIRE(status == 0); + close(fd); + } +} + +ATF_TC_WITHOUT_HEAD(nvlist_send_recv__invalid_fd_size); +ATF_TC_BODY(nvlist_send_recv__invalid_fd_size, tc) +{ + nvlist_t *nvl; + void *packed; + size_t packed_size; + struct nvlist_header *header; + int fd, socks[2], status; + pid_t pid; + + ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + /* Child. */ + fd = socks[0]; + close(socks[1]); + + nvl = nvlist_create(0); + ATF_REQUIRE(nvl != NULL); + ATF_REQUIRE(nvlist_empty(nvl)); + + nvlist_add_string(nvl, "nvl/string", "test"); + ATF_REQUIRE_EQ(nvlist_error(nvl), 0); + + packed = nvlist_pack(nvl, &packed_size); + ATF_REQUIRE(packed != NULL); + ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header)); + + header = (struct nvlist_header *)packed; + header->nvlh_descriptors = 0x20; + + ATF_REQUIRE_EQ(write(fd, packed, packed_size), + (ssize_t)packed_size); + + nvlist_destroy(nvl); + free(packed); + + exit(0); + } else { + /* Parent */ + fd = socks[1]; + close(socks[0]); + + nvl = nvlist_recv(fd, 0); + ATF_REQUIRE(nvl == NULL); + + ATF_REQUIRE(waitpid(pid, &status, 0) == pid); + ATF_REQUIRE(status == 0); + } + + close(fd); +} + +ATF_TC_WITHOUT_HEAD(nvlist_send_recv__overflow_fd_size); +ATF_TC_BODY(nvlist_send_recv__overflow_fd_size, tc) +{ + nvlist_t *nvl; + void *packed; + size_t packed_size; + struct nvlist_header *header; + int fd, socks[2], fds[1], status; + pid_t pid; + + ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + /* Child. */ + fd = socks[0]; + close(socks[1]); + + nvl = nvlist_create(0); + ATF_REQUIRE(nvl != NULL); + ATF_REQUIRE(nvlist_empty(nvl)); + + nvlist_add_string(nvl, "nvl/string", "test"); + ATF_REQUIRE_EQ(nvlist_error(nvl), 0); + + packed = nvlist_pack(nvl, &packed_size); + ATF_REQUIRE(packed != NULL); + ATF_REQUIRE(packed_size >= sizeof(struct nvlist_header)); + + header = (struct nvlist_header *)packed; + header->nvlh_descriptors = 0x4000000000000002; + + ATF_REQUIRE_EQ(write(fd, packed, packed_size), + (ssize_t)packed_size); + + fds[0] = dup(STDERR_FILENO); + ATF_REQUIRE(fds[0] >= 0); + ATF_REQUIRE_EQ(fd_send(fd, fds, 1), 0); + + nvlist_destroy(nvl); + free(packed); + + close(fds[0]); + close(fd); + + exit(0); + } else { + /* Parent */ + fd = socks[1]; + close(socks[0]); + + nvl = nvlist_recv(fd, 0); + ATF_REQUIRE(nvl == NULL); + + /* Make sure that fd was not parsed by nvlist */ + ATF_REQUIRE(fd_recv(fd, fds, 1) == 0); + + ATF_REQUIRE(waitpid(pid, &status, 0) == pid); + ATF_REQUIRE(status == 0); + + close(fds[0]); + close(fd); + } +} + ATF_TP_ADD_TCS(tp) { @@ -553,5 +742,9 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds__dgram); ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds__stream); + ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_header_size); + ATF_TP_ADD_TC(tp, nvlist_send_recv__invalid_fd_size); + ATF_TP_ADD_TC(tp, nvlist_send_recv__overflow_fd_size); + return (atf_no_error()); } diff --git a/sys/contrib/libnv/nv_impl.h b/sys/contrib/libnv/nv_impl.h index e9cd3ffabc3f..4ac57fc7b497 100644 --- a/sys/contrib/libnv/nv_impl.h +++ b/sys/contrib/libnv/nv_impl.h @@ -42,6 +42,14 @@ struct nvpair; typedef struct nvpair nvpair_t; #endif +struct nvlist_header { + uint8_t nvlh_magic; + uint8_t nvlh_version; + uint8_t nvlh_flags; + uint64_t nvlh_descriptors; + uint64_t nvlh_size; +} __packed; + #define NV_TYPE_NVLIST_ARRAY_NEXT 254 #define NV_TYPE_NVLIST_UP 255 diff --git a/sys/contrib/libnv/nvlist.c b/sys/contrib/libnv/nvlist.c index 058ec032d3a3..279f31e3a7cc 100644 --- a/sys/contrib/libnv/nvlist.c +++ b/sys/contrib/libnv/nvlist.c @@ -118,13 +118,6 @@ MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist"); #define NVLIST_HEADER_MAGIC 0x6c #define NVLIST_HEADER_VERSION 0x00 -struct nvlist_header { - uint8_t nvlh_magic; - uint8_t nvlh_version; - uint8_t nvlh_flags; - uint64_t nvlh_descriptors; - uint64_t nvlh_size; -} __packed; nvlist_t * nvlist_create(int flags)