Date: Wed, 18 Nov 2020 01:18:09 +0000 From: bugzilla-noreply@freebsd.org To: bugs@FreeBSD.org Subject: [Bug 251227] setpgid sometimes returns ESRCH instead of EACCES Message-ID: <bug-251227-227@https.bugs.freebsd.org/bugzilla/>
next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D251227 Bug ID: 251227 Summary: setpgid sometimes returns ESRCH instead of EACCES Product: Base System Version: 12.2-RELEASE Hardware: Any OS: Any Status: New Severity: Affects Many People Priority: --- Component: kern Assignee: bugs@FreeBSD.org Reporter: mqudsi@neosmart.net setpgid(2) says > [ESRCH] The requested process does not exist. > [ESRCH] The target process is not the calling process or a > child of the calling process. > [EACCES] The requested process is a child of the calling > process, but it has performed an exec(3) operatio= n. However, as demonstrated by the following test, FreeBSD is incorrectly returning ESRCH when setpgid(2) is called on a child that has called both fork(2) and execv(3) by the time the parent calls setpgid(2). ``` #include <assert.h> #include <errno.h> #include <stdio.h> #include <unistd.h> int main() { pid_t pid =3D vfork(); if (pid =3D=3D 0) { // Child process char * const argv[] =3D { "env", "true", NULL }; execv("/usr/bin/env", argv); assert(0 && "child returned after execv!"); } // Parent process sleep(1); int result =3D setpgid(pid, pid); assert(result !=3D 0); printf("error code: %d\n", errno); assert(errno =3D=3D EACCES && "incorrect error code returned!"); return 0; } ``` The test above fails on FreeBSD 11.2 and FreeBSD 12.2; it passes on Linux. The underlying issue appears to be some sort of race condition: the implementation of sys_setpgid in sys/kern/kern_prot.c correctly checks for = the P_EXEC flag and sets errno to EACCES if present. You'll notice the use of vfork(2) in the test above, which, though not guaranteed, in practice blocks execution of the parent process until exec(3) has been called in the child. If the sleep(1) call is omitted from the test, the test passes (EACCES is returned because execv(3) has been called by the child process). With or without the call to sleep(1), the unreaped child process remains present until the parent terminates (i.e. the referenced ta= rget pid does exist). Fundamentally, the behavior of the parent (and in particul= ar, the return code from its call to setpgid) should be the same both with and without the call to sleep(1), given the semantics of vfork(3). (The behavior does not change if /usr/bin/true is spawned directly instead = of via /usr/bin/env, i.e. this is not an issue with child vs grandchild.) --=20 You are receiving this mail because: You are the assignee for the bug.=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-251227-227>