rfork(2): add RFSPAWN flag
When RFSPAWN is passed, rfork exhibits vfork(2) semantics but also resets signal handlers in the child during creation to avoid a point of corruption of parent state from the child. This flag will be used by posix_spawn(3) to handle potential signal issues. Reviewed by: jilles, kib Differential Revision: https://reviews.freebsd.org/D19058
This commit is contained in:
parent
cf4707bb2f
commit
245d8426fc
@ -5,7 +5,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 12, 2011
|
||||
.Dd September 25, 2019
|
||||
.Dt RFORK 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -34,7 +34,9 @@ and open files.
|
||||
The
|
||||
.Fa flags
|
||||
argument
|
||||
is the logical OR of some subset of:
|
||||
is either
|
||||
.Dv RFSPAWN
|
||||
or the logical OR of some subset of:
|
||||
.Bl -tag -width ".Dv RFLINUXTHPN"
|
||||
.It Dv RFPROC
|
||||
If set a new process is created; otherwise changes affect the
|
||||
@ -105,6 +107,14 @@ open until either they are explicitly closed
|
||||
or all processes sharing the table exit.
|
||||
.Pp
|
||||
If
|
||||
.Dv RFSPAWN
|
||||
is passed,
|
||||
.Nm
|
||||
will use
|
||||
.Xr vfork 2
|
||||
semantics but reset all signal actions in the child to default.
|
||||
.Pp
|
||||
If
|
||||
.Dv RFPROC
|
||||
is set, the
|
||||
value returned in the parent process
|
||||
|
@ -170,10 +170,18 @@ sys_rfork(struct thread *td, struct rfork_args *uap)
|
||||
/* Don't allow kernel-only flags. */
|
||||
if ((uap->flags & RFKERNELONLY) != 0)
|
||||
return (EINVAL);
|
||||
/* RFSPAWN must not appear with others */
|
||||
if ((uap->flags & RFSPAWN) != 0 && uap->flags != RFSPAWN)
|
||||
return (EINVAL);
|
||||
|
||||
AUDIT_ARG_FFLAGS(uap->flags);
|
||||
bzero(&fr, sizeof(fr));
|
||||
fr.fr_flags = uap->flags;
|
||||
if ((uap->flags & RFSPAWN) != 0) {
|
||||
fr.fr_flags = RFFDG | RFPROC | RFPPWAIT | RFMEM;
|
||||
fr.fr_flags2 = FR2_DROPSIG_CAUGHT;
|
||||
} else {
|
||||
fr.fr_flags = uap->flags;
|
||||
}
|
||||
fr.fr_pidp = &pid;
|
||||
error = fork1(td, &fr);
|
||||
if (error == 0) {
|
||||
@ -471,6 +479,11 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
|
||||
} else {
|
||||
sigacts_copy(newsigacts, p1->p_sigacts);
|
||||
p2->p_sigacts = newsigacts;
|
||||
if ((fr->fr_flags2 & FR2_DROPSIG_CAUGHT) != 0) {
|
||||
mtx_lock(&p2->p_sigacts->ps_mtx);
|
||||
sig_drop_caught(p2);
|
||||
mtx_unlock(&p2->p_sigacts->ps_mtx);
|
||||
}
|
||||
}
|
||||
|
||||
if (fr->fr_flags & RFTSIGZMB)
|
||||
|
@ -986,12 +986,7 @@ execsigs(struct proc *p)
|
||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||
ps = p->p_sigacts;
|
||||
mtx_lock(&ps->ps_mtx);
|
||||
while (SIGNOTEMPTY(ps->ps_sigcatch)) {
|
||||
sig = sig_ffs(&ps->ps_sigcatch);
|
||||
sigdflt(ps, sig);
|
||||
if ((sigprop(sig) & SIGPROP_IGNORE) != 0)
|
||||
sigqueue_delete_proc(p, sig);
|
||||
}
|
||||
sig_drop_caught(p);
|
||||
|
||||
/*
|
||||
* As CloudABI processes cannot modify signal handlers, fully
|
||||
@ -3857,3 +3852,20 @@ sigacts_shared(struct sigacts *ps)
|
||||
|
||||
return (ps->ps_refcnt > 1);
|
||||
}
|
||||
|
||||
void
|
||||
sig_drop_caught(struct proc *p)
|
||||
{
|
||||
int sig;
|
||||
struct sigacts *ps;
|
||||
|
||||
ps = p->p_sigacts;
|
||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||
mtx_assert(&ps->ps_mtx, MA_OWNED);
|
||||
while (SIGNOTEMPTY(ps->ps_sigcatch)) {
|
||||
sig = sig_ffs(&ps->ps_sigcatch);
|
||||
sigdflt(ps, sig);
|
||||
if ((sigprop(sig) & SIGPROP_IGNORE) != 0)
|
||||
sigqueue_delete_proc(p, sig);
|
||||
}
|
||||
}
|
||||
|
@ -1006,6 +1006,8 @@ struct fork_req {
|
||||
int *fr_pd_fd;
|
||||
int fr_pd_flags;
|
||||
struct filecaps *fr_pd_fcaps;
|
||||
int fr_flags2;
|
||||
#define FR2_DROPSIG_CAUGHT 0x00001 /* Drop caught non-DFL signals */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -381,6 +381,7 @@ void sigacts_copy(struct sigacts *dest, struct sigacts *src);
|
||||
void sigacts_free(struct sigacts *ps);
|
||||
struct sigacts *sigacts_hold(struct sigacts *ps);
|
||||
int sigacts_shared(struct sigacts *ps);
|
||||
void sig_drop_caught(struct proc *p);
|
||||
void sigexit(struct thread *td, int sig) __dead2;
|
||||
int sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **);
|
||||
int sig_ffs(sigset_t *set);
|
||||
|
@ -188,11 +188,14 @@
|
||||
#define RFTSIGNUM(flags) (((flags) >> RFTSIGSHIFT) & RFTSIGMASK)
|
||||
#define RFTSIGFLAGS(signum) ((signum) << RFTSIGSHIFT)
|
||||
#define RFPROCDESC (1<<28) /* return a process descriptor */
|
||||
#define RFPPWAIT (1<<31) /* parent sleeps until child exits (vfork) */
|
||||
/* kernel: parent sleeps until child exits (vfork) */
|
||||
#define RFPPWAIT (1<<31)
|
||||
/* user: vfork(2) semantics, clear signals */
|
||||
#define RFSPAWN (1U<<31)
|
||||
#define RFFLAGS (RFFDG | RFPROC | RFMEM | RFNOWAIT | RFCFDG | \
|
||||
RFTHREAD | RFSIGSHARE | RFLINUXTHPN | RFSTOPPED | RFHIGHPID | RFTSIGZMB | \
|
||||
RFPROCDESC | RFPPWAIT)
|
||||
#define RFKERNELONLY (RFSTOPPED | RFHIGHPID | RFPPWAIT | RFPROCDESC)
|
||||
RFPROCDESC | RFSPAWN | RFPPWAIT)
|
||||
#define RFKERNELONLY (RFSTOPPED | RFHIGHPID | RFPROCDESC)
|
||||
|
||||
#endif /* __BSD_VISIBLE */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user