mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
libcasper: tolerate kernels without PD_NOWAITPID
Commit 1a296762b3 made libcasper pass PD_NOWAITPID to pdfork(2).
Kernels predating the flag (15.1 and earlier, since the flag first
ships in 15.2) reject it with EINVAL, which makes cap_init() and every
service fork fail when a newer world runs on an older kernel, for
example in a poudriere jail.
Add casper_pdfork(), which retries without the flag on EINVAL, and use
it at both pdfork(2) call sites. The retry is safe because the kernel
validates pdfork flags before creating a child. On such kernels the
zombie must still be reaped with waitpid(2), as before the flag was
introduced.
The fallback is compiled out once __FreeBSD_version reaches 1700000,
so it disappears from main when stable/16 branches while remaining in
the stable/15 and stable/16 branches that need it.
Reviewed by: kib
MFC after: 3 days
Differential Revision: https://reviews.freebsd.org/D60401
This commit is contained in:
1 parent
ea23918b02
commit
b4e2c9abaf
3 files changed
+25
-2
No files matched your search
@@ -95,7 +95,7 @@ cap_init(void)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pid = pdfork(&pfd, PD_NOWAITPID);
|
||||
pid = casper_pdfork(&pfd);
|
||||
if (pid == 0) {
|
||||
/* Child. */
|
||||
close(sock[0]);
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
#ifndef _LIBCASPER_IMPL_H_
|
||||
#define _LIBCASPER_IMPL_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/procdesc.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libcasper.h"
|
||||
@@ -44,6 +48,25 @@ struct service_connection;
|
||||
bool fd_is_valid(int fd);
|
||||
void fd_fix_environment(int *fdp);
|
||||
|
||||
static inline pid_t
|
||||
casper_pdfork(int *fdp)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = pdfork(fdp, PD_NOWAITPID);
|
||||
#if __FreeBSD_version < 1700000
|
||||
/*
|
||||
* Kernels predating PD_NOWAITPID (introduced in 15.2) reject the
|
||||
* flag with EINVAL before creating a child, so retrying without
|
||||
* it is safe. The child must then be reaped with waitpid(2), as
|
||||
* before. This fallback is compiled out starting with 17.0.
|
||||
*/
|
||||
if (pid == -1 && errno == EINVAL)
|
||||
pid = pdfork(fdp, 0);
|
||||
#endif
|
||||
return (pid);
|
||||
}
|
||||
|
||||
/* Private service functions. */
|
||||
struct service *service_alloc(const char *name,
|
||||
service_limit_func_t *limitfunc,
|
||||
|
||||
@@ -149,7 +149,7 @@ zygote_main(int *sockp)
|
||||
error = errno;
|
||||
goto send;
|
||||
}
|
||||
pid = pdfork(&procfd, PD_NOWAITPID);
|
||||
pid = casper_pdfork(&procfd);
|
||||
switch (pid) {
|
||||
case -1:
|
||||
/* Failure. */
|
||||
|
||||
Reference in new issue
Block a user