1*a4aaee21SDag-Erling Smørgrav /*-
2*a4aaee21SDag-Erling Smørgrav * Copyright (c) 2023 Klara, Inc.
3*a4aaee21SDag-Erling Smørgrav *
4*a4aaee21SDag-Erling Smørgrav * SPDX-License-Identifier: BSD-2-Clause
5*a4aaee21SDag-Erling Smørgrav */
6*a4aaee21SDag-Erling Smørgrav
7*a4aaee21SDag-Erling Smørgrav #include <sys/resource.h>
8*a4aaee21SDag-Erling Smørgrav #include <sys/wait.h>
9*a4aaee21SDag-Erling Smørgrav
10*a4aaee21SDag-Erling Smørgrav #include <errno.h>
11*a4aaee21SDag-Erling Smørgrav #include <libutil.h>
12*a4aaee21SDag-Erling Smørgrav #include <unistd.h>
13*a4aaee21SDag-Erling Smørgrav
14*a4aaee21SDag-Erling Smørgrav #include <atf-c.h>
15*a4aaee21SDag-Erling Smørgrav
16*a4aaee21SDag-Erling Smørgrav ATF_TC(forkfail);
ATF_TC_HEAD(forkfail,tc)17*a4aaee21SDag-Erling Smørgrav ATF_TC_HEAD(forkfail, tc)
18*a4aaee21SDag-Erling Smørgrav {
19*a4aaee21SDag-Erling Smørgrav atf_tc_set_md_var(tc, "descr", "Check for fd leak when fork() fails");
20*a4aaee21SDag-Erling Smørgrav atf_tc_set_md_var(tc, "require.user", "unprivileged");
21*a4aaee21SDag-Erling Smørgrav }
22*a4aaee21SDag-Erling Smørgrav
ATF_TC_BODY(forkfail,tc)23*a4aaee21SDag-Erling Smørgrav ATF_TC_BODY(forkfail, tc)
24*a4aaee21SDag-Erling Smørgrav {
25*a4aaee21SDag-Erling Smørgrav struct rlimit orl, nrl;
26*a4aaee21SDag-Erling Smørgrav pid_t pid;
27*a4aaee21SDag-Erling Smørgrav int prevfd, fd, pty;
28*a4aaee21SDag-Erling Smørgrav
29*a4aaee21SDag-Erling Smørgrav /* set process limit to 1 so fork() will fail */
30*a4aaee21SDag-Erling Smørgrav ATF_REQUIRE_EQ(0, getrlimit(RLIMIT_NPROC, &orl));
31*a4aaee21SDag-Erling Smørgrav nrl = orl;
32*a4aaee21SDag-Erling Smørgrav nrl.rlim_cur = 1;
33*a4aaee21SDag-Erling Smørgrav ATF_REQUIRE_EQ(0, setrlimit(RLIMIT_NPROC, &nrl));
34*a4aaee21SDag-Erling Smørgrav /* check first free fd */
35*a4aaee21SDag-Erling Smørgrav ATF_REQUIRE((fd = dup(0)) > 0);
36*a4aaee21SDag-Erling Smørgrav ATF_REQUIRE_EQ(0, close(fd));
37*a4aaee21SDag-Erling Smørgrav /* attempt forkpty() */
38*a4aaee21SDag-Erling Smørgrav pid = forkpty(&pty, NULL, NULL, NULL);
39*a4aaee21SDag-Erling Smørgrav if (pid == 0) {
40*a4aaee21SDag-Erling Smørgrav /* child - fork() unexpectedly succeeded */
41*a4aaee21SDag-Erling Smørgrav _exit(0);
42*a4aaee21SDag-Erling Smørgrav }
43*a4aaee21SDag-Erling Smørgrav ATF_CHECK_ERRNO(EAGAIN, pid < 0);
44*a4aaee21SDag-Erling Smørgrav if (pid > 0) {
45*a4aaee21SDag-Erling Smørgrav /* parent - fork() unexpectedly succeeded */
46*a4aaee21SDag-Erling Smørgrav (void)waitpid(pid, NULL, 0);
47*a4aaee21SDag-Erling Smørgrav }
48*a4aaee21SDag-Erling Smørgrav /* check that first free fd hasn't changed */
49*a4aaee21SDag-Erling Smørgrav prevfd = fd;
50*a4aaee21SDag-Erling Smørgrav ATF_REQUIRE((fd = dup(0)) > 0);
51*a4aaee21SDag-Erling Smørgrav ATF_CHECK_EQ(prevfd, fd);
52*a4aaee21SDag-Erling Smørgrav }
53*a4aaee21SDag-Erling Smørgrav
ATF_TP_ADD_TCS(tp)54*a4aaee21SDag-Erling Smørgrav ATF_TP_ADD_TCS(tp)
55*a4aaee21SDag-Erling Smørgrav {
56*a4aaee21SDag-Erling Smørgrav ATF_TP_ADD_TC(tp, forkfail);
57*a4aaee21SDag-Erling Smørgrav return (atf_no_error());
58*a4aaee21SDag-Erling Smørgrav }
59