Page MenuHomeFreeBSD

D55306.id171967.diff
No OneTemporary

D55306.id171967.diff

diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2
--- a/lib/libsys/pdfork.2
+++ b/lib/libsys/pdfork.2
@@ -114,11 +114,13 @@
flags.
The
.Fn pdrfork
-system call requires that the
+system call requires that both the
.Va RFPROC
-or
+and
+.Va RFPROCDESC
+flags, or
.Va RFSPAWN
-flag is specified.
+flag are specified.
.Pp
.Fn pdgetpid
queries the process ID (PID) in the process descriptor
@@ -203,6 +205,24 @@
.Xr fork 2 ) ,
with the following additions:
.Bl -tag -width Er
+.It Bq Er EFAULT
+The copyout of the resulting file descriptor value to the memory pointed
+to by
+.Fa fdp
+failed.
+.Pp
+Note that the child process was already created when this condition
+is detected,
+and the child continues execution, same as the parent.
+If this error must be handled, it is advisable to memoize the
+.Fn getpid
+result before the call to
+.Fn pdfork
+or
+.Fn pdrfork ,
+and compare it to the value returned by
+.Fn getpid
+after, to see if code is executing in parent or child.
.It Bq Er EINVAL
The signal number given to
.Fn pdkill
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -214,6 +214,11 @@
fr.fr_flags = RFFDG | RFPROC | RFPPWAIT | RFMEM | RFPROCDESC;
fr.fr_flags2 = FR2_DROPSIG_CAUGHT;
} else {
+ if ((uap->rfflags & (RFPROC | RFPROCDESC)) !=
+ (RFPROC | RFPROCDESC)) {
+ return (EXTERROR(EINVAL,
+ "RFPROCDESC required %#jx", uap->rfflags));
+ }
fr.fr_flags = uap->rfflags;
}
diff --git a/tests/sys/kern/pdrfork.c b/tests/sys/kern/pdrfork.c
--- a/tests/sys/kern/pdrfork.c
+++ b/tests/sys/kern/pdrfork.c
@@ -26,8 +26,9 @@
*/
#include <sys/types.h>
-#include <sys/user.h>
+#include <sys/mman.h>
#include <sys/procdesc.h>
+#include <sys/user.h>
#include <sys/wait.h>
#include <atf-c.h>
@@ -35,23 +36,19 @@
#include <string.h>
#include <unistd.h>
-static void basic_usage(int rfflags) {
- int pd = -1;
- pid_t pid, pd_pid, waited_pid;
+static void
+basic_usage_tail(int pd, pid_t pid)
+{
+ pid_t 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));
+ ATF_CHECK_EQ(pd_pid, pid);
/* We should be able to collect the child's status */
- waited_pid = waitpid(pid, &status, WEXITED | WNOWAIT);
+ waited_pid = waitpid(pid, &status, WEXITED);
ATF_CHECK_EQ(waited_pid, pid);
/* But after closing the process descriptor, we won't */
@@ -61,6 +58,21 @@
ATF_CHECK_EQ(ECHILD, errno);
}
+static void
+basic_usage(int rfflags)
+{
+ int pd = -1;
+ pid_t pid;
+
+ pid = pdrfork(&pd, 0, rfflags);
+ ATF_REQUIRE_MSG(pid >= 0, "rfork failed with %s", strerror(errno));
+ if (pid == 0) {
+ /* In child */
+ _exit(0);
+ }
+ basic_usage_tail(pd, pid);
+}
+
/* 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)
@@ -82,7 +94,7 @@
r = pdgetpid(pd, &pd_pid);
ATF_CHECK_EQ_MSG(r, 0, "pdgetpid failed: %s", strerror(errno));
- waited_pid = waitpid(pid, &status, WEXITED | WNOWAIT);
+ waited_pid = waitpid(pid, &status, WEXITED );
ATF_CHECK_EQ(waited_pid, pid);
ATF_REQUIRE(WIFEXITED(status) && (WEXITSTATUS(status) == true));
@@ -93,7 +105,23 @@
ATF_TC_WITHOUT_HEAD(efault);
ATF_TC_BODY(efault, tc)
{
- ATF_REQUIRE_ERRNO(EFAULT, pdrfork((int*)-1, 0, RFPROC | RFPROCDESC) < 0);
+ void *unmapped;
+ pid_t my_pid;
+
+ unmapped = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_GUARD, -1, 0);
+ ATF_REQUIRE(unmapped != MAP_FAILED);
+ my_pid = getpid();
+ ATF_REQUIRE_ERRNO(EFAULT, pdrfork(unmapped, 0, RFPROC |
+ RFPROCDESC) < 0);
+ munmap(unmapped, PAGE_SIZE);
+
+ /*
+ * EFAULT only means that the copyout of the procdesc failed.
+ * The runaway children was created anyway. Prevent
+ * double-destruction of the atf stuff.
+ */
+ if (my_pid != getpid())
+ _exit(0);
}
/* Invalid combinations of flags should return EINVAL */
@@ -107,48 +135,8 @@
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");
+ ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFPROC) < 0);
+ ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, 0) < 0);
}
/* basic usage with RFPROCDESC */
@@ -158,30 +146,39 @@
basic_usage(RFPROC | RFPROCDESC);
}
+static int
+rfspawn_fn(void *arg)
+{
+ _exit(0);
+ return (0);
+}
+
/* 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);
-}
+ char *stack = NULL;
+ int pd = -1;
+ pid_t pid;
+
+#if defined(__i386__) || defined(__amd64__)
+#define STACK_SZ (PAGE_SIZE * 10)
+ stack = mmap(NULL, STACK_SZ, PROT_READ | PROT_WRITE, MAP_ANON,
+ -1, 0);
+ ATF_REQUIRE(stack != MAP_FAILED);
+ stack += STACK_SZ;
#endif
+ pid = pdrfork_thread(&pd, 0, RFSPAWN, stack, rfspawn_fn, NULL);
+ basic_usage_tail(pd, pid);
+}
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());
}

File Metadata

Mime Type
text/plain
Expires
Thu, May 14, 5:13 AM (6 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33031783
Default Alt Text
D55306.id171967.diff (6 KB)

Event Timeline