From nobody Mon Jan 26 14:37:33 2026 X-Original-To: dev-commits-src-main@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 4f0B2j6HQtz6QMDT for ; Mon, 26 Jan 2026 14:37:33 +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 "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4f0B2j4wZTz3s6x for ; Mon, 26 Jan 2026 14:37:33 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1769438253; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=pJBP7vgYnUPVkyjyJ+PL5jN5QwkxjTYzqZpV6ZN/cuU=; b=C89wjgTDGsUvpMpP5c/Vts/q55wHRGf0c6FBveOeXPAII9BYr7DHgyIUUuESkhtAPOApJZ 2PnrdUxzK/6nNSGHZdSYu4qV+QVm0ZJGRPeu7XFUPK5RWfrJeAETS9BvrYIEt/QVs9L5RF aAeYaicWcU/gGnTUi2FA4jaCr/eZHO+2ag7d9j4RGdUkoBO73bqWQy9ufvMy5zFo7i/Viy VWYLVoudPxAo6+WlFETf0E7FL5minYD4rpeWIelPnGvIhLdFHq81obdv058OfCCK8Z73nH z4DSPdVbvWymi7pY1QC47skMijppX8l00xBaSTyl+16jppdRcnSrlT6Qc8DpjA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1769438253; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=pJBP7vgYnUPVkyjyJ+PL5jN5QwkxjTYzqZpV6ZN/cuU=; b=A0iafsfnF/iXLfLtMN3ZHaP8rTYT5yBYURHp88xf+yIGf4P0gzcKhcSldj33YbciD7U3/w 0ll4t1lVYaio3c2bwFCCGtfEUmUHeReT1mnJZJn/j9q9N1yBwu4X1bL0W9UE1jmTRC2U7D r2QIqWAgSTKW7/yggiZc7sXgctXfvDbbv9GdelNhh5W5dj64mJ+G0qVBNZE9/YanAFrUPx 2+gEmdpTAnDB3QIpAbRDFT+Nt708rAP8QUKl0hsQRJS4xh18aC7nTvKuMX8JWdzXNeXhbu Pc27x7oeIus7d0IIP7XfIIzWYQ5pENODRNFijCvmoL7MzuL29k/zvcRsrD78bw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1769438253; a=rsa-sha256; cv=none; b=UFHhULv4QtB0Qh2HuDZsuFYnlEc+GnG5CBxBMUfdyYsCmpEBALK2B5hxD2wa3TEc/np76m DDF+A/oQgrP12ygQDXl0NesHjnJh3KDcMWedNGA7q2xNo54bBs5sKVWlVByhOAdyvqmw3c 62Z8AuKayfUODju9Zqfmj3mZarIPdexN6K1yCbdJmJJm0FgYeYiB3PBAhVCp5cH/6BMASR JwGfspSZ7Uyix1F1bArCbbJ+w91gPm01CSoWDGX1bz+RpfDmj7bTEoHX7z5SrCggVFioDl iOV6NhndTEMJ6039qmb1CnNu702RX5UtPjxS70AU+xb6W1NOVvJtDPq5xcl3iQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4f0B2j4ShGz8LK for ; Mon, 26 Jan 2026 14:37:33 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 32408 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 26 Jan 2026 14:37:33 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alan Somers Subject: git: d1e6057fa47e - main - Add tests for pdrfork List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: asomers X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: d1e6057fa47e842c63461b64b29ac5d3e9fdad76 Auto-Submitted: auto-generated Date: Mon, 26 Jan 2026 14:37:33 +0000 Message-Id: <69777c2d.32408.6fa6e8cd@gitrepo.freebsd.org> The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=d1e6057fa47e842c63461b64b29ac5d3e9fdad76 commit d1e6057fa47e842c63461b64b29ac5d3e9fdad76 Author: Alan Somers AuthorDate: 2026-01-25 16:13:43 +0000 Commit: Alan Somers CommitDate: 2026-01-26 14:37:08 +0000 Add tests for pdrfork MFC With: 5c2ee618d5ec21f110c4da40e9f17833b2ab8b76 Sponsored by: ConnectWise --- tests/sys/kern/Makefile | 1 + tests/sys/kern/pdrfork.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index b3611f34996d..0440b9a023eb 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -29,6 +29,7 @@ ATF_TESTS_C+= ktls_test ATF_TESTS_C+= ktrace_test ATF_TESTS_C+= listener_wakeup ATF_TESTS_C+= module_test +ATF_TESTS_C+= pdrfork ATF_TESTS_C+= prace ATF_TESTS_C+= procdesc ATF_TESTS_C+= ptrace_test diff --git a/tests/sys/kern/pdrfork.c b/tests/sys/kern/pdrfork.c new file mode 100644 index 000000000000..fa644b6658d7 --- /dev/null +++ b/tests/sys/kern/pdrfork.c @@ -0,0 +1,187 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026 ConnectWise + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +static void basic_usage(int rfflags) { + int pd = -1; + pid_t pid, pd_pid, waited_pid; + int r, status; + + pid = pdrfork(&pd, 0, rfflags); + ATF_REQUIRE_MSG(pid >= 0, "rfork failed with %s", strerror(errno)); + if (pid == 0) { + /* In child */ + _exit(0); + } + ATF_REQUIRE_MSG(pd >= 0, "rfork did not return a process descriptor"); + r = pdgetpid(pd, &pd_pid); + ATF_CHECK_EQ_MSG(r, 0, "pdgetpid failed: %s", strerror(errno)); + + /* We should be able to collect the child's status */ + waited_pid = waitpid(pid, &status, WEXITED | WNOWAIT); + ATF_CHECK_EQ(waited_pid, pid); + + /* But after closing the process descriptor, we won't */ + close(pd); + waited_pid = waitpid(pid, &status, WEXITED | WNOHANG); + ATF_CHECK_EQ(-1, waited_pid); + ATF_CHECK_EQ(ECHILD, errno); +} + +/* pdrfork does not return a process descriptor to the child */ +ATF_TC_WITHOUT_HEAD(child_gets_no_pidfd); +ATF_TC_BODY(child_gets_no_pidfd, tc) +{ + int pd = -1; + pid_t pid, pd_pid, waited_pid; + int r, status; + + pid = pdrfork(&pd, 0, RFPROC | RFPROCDESC); + ATF_REQUIRE_MSG(pid >= 0, "rfork failed with %s", strerror(errno)); + if (pid == 0) { + /* + * In child. We can't do very much here before we exec, so + * just use our exit status to report success. + */ + _exit(pd == -1); + } + ATF_REQUIRE_MSG(pd >= 0, "rfork did not return a process descriptor"); + r = pdgetpid(pd, &pd_pid); + ATF_CHECK_EQ_MSG(r, 0, "pdgetpid failed: %s", strerror(errno)); + + waited_pid = waitpid(pid, &status, WEXITED | WNOWAIT); + ATF_CHECK_EQ(waited_pid, pid); + ATF_REQUIRE(WIFEXITED(status) && (WEXITSTATUS(status) == true)); + + close(pd); +} + +/* If the pidfd argument is invalid, the error should be handled gracefully */ +ATF_TC_WITHOUT_HEAD(efault); +ATF_TC_BODY(efault, tc) +{ + ATF_REQUIRE_ERRNO(EFAULT, pdrfork((int*)-1, 0, RFPROC | RFPROCDESC) < 0); +} + +/* Invalid combinations of flags should return EINVAL */ +ATF_TC_WITHOUT_HEAD(einval); +ATF_TC_BODY(einval, tc) +{ + int pd = -1; + + ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, -1, RFSPAWN) < 0); + ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, -1) < 0); + ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFSPAWN | RFNOWAIT) < 0); + ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFPROC | RFFDG| RFCFDG) < 0); + ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFPROCDESC) < 0); +} + +/* + * Without RFSPAWN, RFPROC, or RFPROCDESC, an existing process may be modified + */ +ATF_TC_WITHOUT_HEAD(modify_child); +ATF_TC_BODY(modify_child, tc) +{ + int fdp = -1; + pid_t pid1, pid2; + + pid1 = pdfork(&fdp, 0); + if (pid1 == 0) + _exit(0); + ATF_REQUIRE_MSG(pid1 >= 0, "pdfork failed: %s", strerror(errno)); + ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); + + pid2 = pdrfork(&fdp, 0, RFNOWAIT); + ATF_REQUIRE_MSG(pid2 >= 0, "pdrfork failed: %s", strerror(errno)); + ATF_CHECK_EQ_MSG(pid2, 0, + "pdrfork created a process even though we told it not to"); + + close(fdp); +} + +/* + * Basic usage with RFPROC. No process descriptor will be created. + * I'm not sure why you would use pdrfork in this case instead of plain rfork + */ +ATF_TC_WITHOUT_HEAD(rfproc); +ATF_TC_BODY(rfproc, tc) +{ + int pd = -1; + pid_t pid; + + pid = pdrfork(&pd, 0, RFPROC); + ATF_REQUIRE_MSG(pid > 0, "rfork failed with %s", strerror(errno)); + if (pid == 0) + _exit(0); + + ATF_REQUIRE_EQ_MSG(pd, -1, + "rfork(RFPROC) returned a process descriptor"); +} + +/* basic usage with RFPROCDESC */ +ATF_TC_WITHOUT_HEAD(rfprocdesc); +ATF_TC_BODY(rfprocdesc, tc) +{ + basic_usage(RFPROC | RFPROCDESC); +} + +/* basic usage with RFSPAWN */ +/* + * Skip on i386 and x86_64 because RFSPAWN cannot be used from C code on those + * architectures. See lib/libc/gen/posix_spawn.c for details. + */ +#if !(defined(__i386__)) && !(defined(__amd64__)) +ATF_TC_WITHOUT_HEAD(rfspawn); +ATF_TC_BODY(rfspawn, tc) +{ + basic_usage(RFSPAWN); +} +#endif + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, child_gets_no_pidfd); + ATF_TP_ADD_TC(tp, efault); + ATF_TP_ADD_TC(tp, einval); + ATF_TP_ADD_TC(tp, modify_child); + ATF_TP_ADD_TC(tp, rfproc); + ATF_TP_ADD_TC(tp, rfprocdesc); +#if !(defined(__i386__)) && !(defined(__amd64__)) + ATF_TP_ADD_TC(tp, rfspawn); +#endif + + return (atf_no_error()); +}