Page MenuHomeFreeBSD

D39830.id121076.diff
No OneTemporary

D39830.id121076.diff

diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -3013,13 +3013,6 @@
prison_deref(pr, drflags);
}
-static void
-prison_kill_processes_cb(struct proc *p, void *arg __unused)
-{
-
- kern_psignal(p, SIGKILL);
-}
-
/*
* Note the iteration does not guarantee acting on all processes.
* Most notably there may be fork or jail_attach in progress.
@@ -3191,7 +3184,7 @@
/* Kill any processes attached to a killed prison. */
if (killpr != NULL)
- prison_proc_iterate(killpr, prison_kill_processes_cb, NULL);
+ kern_prsignal(curthread, killpr, SIGKILL);
/*
* Finish removing any unreferenced prisons, which couldn't happen
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -43,6 +43,7 @@
#include "opt_ktrace.h"
#include <sys/param.h>
+#include <sys/_unrhdr.h>
#include <sys/capsicum.h>
#include <sys/ctype.h>
#include <sys/systm.h>
@@ -83,6 +84,7 @@
#include <sys/sysent.h>
#include <sys/syslog.h>
#include <sys/sysproto.h>
+#include <sys/taskqueue.h>
#include <sys/timers.h>
#include <sys/unistd.h>
#include <sys/vmmeter.h>
@@ -108,7 +110,7 @@
"struct thread *", "struct proc *", "int");
static int coredump(struct thread *);
-static int killpg1(struct thread *td, int sig, int pgid, int all,
+static int killpg1(struct thread *td, int sig, int pgid, struct prison *pr,
ksiginfo_t *ksi);
static int issignal(struct thread *td);
static void reschedule_signals(struct proc *p, sigset_t block, int flags);
@@ -1765,27 +1767,105 @@
struct killpg1_ctx {
struct thread *td;
+ struct proc *target;
+ struct ucred *cr;
+ struct sx *lock;
ksiginfo_t *ksi;
int sig;
bool sent;
bool found;
+ int count;
int ret;
+ struct unrhdr pids;
+ struct task t;
};
static void
-killpg1_sendsig_locked(struct proc *p, struct killpg1_ctx *arg)
+killpg1_kill_proc_locked(struct killpg1_ctx *arg)
{
+ struct proc *p;
+ bool need_stop;
int err;
- err = p_cansignal(arg->td, p, arg->sig);
- if (err == 0 && arg->sig != 0)
- pksignal(p, arg->sig, arg->ksi);
- if (err != ESRCH)
+ p = arg->target;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ PROC_ASSERT_HELD(p);
+
+ err = cr_cansignal(arg->cr, p, arg->sig);
+ if (err != ESRCH) {
arg->found = true;
+ arg->count++;
+ }
if (err == 0)
arg->sent = true;
else if (arg->ret == 0 && err != ESRCH && err != EPERM)
arg->ret = err;
+ if (err != 0 || arg->sig == 0)
+ return;
+
+ /*
+ * The need_stop indicates if the target process needs to be
+ * suspended before being signalled. This is needed when we
+ * guarantee that all processes in subtree are signalled,
+ * avoiding the race with some process not yet fully linked
+ * into all structures during fork, ignored by iterator, and
+ * then escaping signalling.
+ *
+ * The thread cannot usefully stop itself anyway, and if other
+ * thread of the current process forks while the current
+ * thread signals the whole subtree, it is an application
+ * race.
+ */
+
+ if ((p->p_flag & (P_KPROC | P_SYSTEM | P_STOPPED)) == 0)
+ need_stop = thread_single(p, SINGLE_ALLPROC) == 0;
+ else
+ need_stop = false;
+ (void)pksignal(p, arg->sig, arg->ksi);
+ if (need_stop)
+ thread_single_end(p, SINGLE_ALLPROC);
+}
+
+
+static void
+killpg1_proc_work(void *arg, int pending __unused)
+{
+ struct killpg1_ctx *w;
+
+ w = arg;
+ PROC_LOCK(w->target);
+ if ((w->target->p_flag2 & P2_WEXIT) == 0)
+ killpg1_kill_proc_locked(w);
+ PROC_UNLOCK(w->target);
+
+ sx_xlock(w->lock);
+ w->target = NULL;
+ wakeup(&w->target);
+ sx_xunlock(w->lock);
+}
+
+
+static void
+killpg1_sendsig_locked(struct proc *p, struct killpg1_ctx *arg, struct sx *lock)
+{
+
+ sx_assert(lock, SX_SLOCKED);
+
+ if ((p->p_flag2 & P2_WEXIT) != 0)
+ return;
+ _PHOLD_LITE(p);
+ PROC_UNLOCK(p);
+ if (alloc_unr_specific(&arg->pids, p->p_pid) != p->p_pid)
+ goto out;
+ arg->target = p;
+ arg->lock = lock;
+ taskqueue_enqueue(taskqueue_thread, &arg->t);
+ while (arg->target != NULL) {
+ sx_sleep(&arg->target, lock, PWAIT, "killpg", 0);
+ }
+out:
+ PROC_LOCK(p);
+ _PRELE(p);
}
static void
@@ -1797,7 +1877,7 @@
return;
PROC_LOCK(p);
- killpg1_sendsig_locked(p, arg);
+ killpg1_sendsig_locked(p, arg, &proctree_lock);
PROC_UNLOCK(p);
}
@@ -1810,7 +1890,7 @@
(p == ctx->td->td_proc) || p->p_state == PRS_NEW)
return;
- killpg1_sendsig_locked(p, ctx);
+ killpg1_sendsig_locked(p, ctx, &allproc_lock);
}
/*
@@ -1818,51 +1898,86 @@
* cp is calling process.
*/
static int
-killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi)
+killpg1(struct thread *td, int sig, int pgid, struct prison *pr,
+ ksiginfo_t *ksi)
{
- struct proc *p;
+ struct proc *p, *ptmp;
struct pgrp *pgrp;
struct killpg1_ctx arg;
+ arg.cr = crhold(td->td_ucred);
arg.td = td;
arg.ksi = ksi;
arg.sig = sig;
arg.sent = false;
- arg.found = false;
+ arg.count = 0;
arg.ret = 0;
- if (all) {
- /*
- * broadcast
- */
- prison_proc_iterate(td->td_ucred->cr_prison,
- kill_processes_prison_cb, &arg);
- } else {
- sx_slock(&proctree_lock);
- if (pgid == 0) {
+ init_unrhdr(&arg.pids, 1, PID_MAX, UNR_NO_MTX);
+ TASK_INIT(&arg.t, 0, killpg1_proc_work, &arg);
+
+ /*
+ * Prevent swapout, since ctx, ksi are
+ * allocated on the stack. We sleep in
+ * killpg1_sendsig_locked() waiting for
+ * task to complete single-threading.
+ */
+ PHOLD(td->td_proc);
+
+ do {
+ arg.found = false;
+ if (pr != NULL) {
/*
- * zero pgid means send to my process group.
+ * broadcast
*/
- pgrp = td->td_proc->p_pgrp;
- PGRP_LOCK(pgrp);
+ prison_proc_iterate(pr, kill_processes_prison_cb, &arg);
} else {
- pgrp = pgfind(pgid);
- if (pgrp == NULL) {
- sx_sunlock(&proctree_lock);
- return (ESRCH);
+ sx_slock(&proctree_lock);
+ if (pgid == 0) {
+ /*
+ * zero pgid means send to my process group.
+ */
+ pgrp = td->td_proc->p_pgrp;
+ PGRP_LOCK(pgrp);
+ } else {
+ pgrp = pgfind(pgid);
+ if (pgrp == NULL) {
+ sx_sunlock(&proctree_lock);
+ arg.ret = ESRCH;
+ goto out;
+ }
}
+ PGRP_UNLOCK(pgrp);
+ LIST_FOREACH_SAFE(p, &pgrp->pg_members, p_pglist, ptmp)
+ killpg1_sendsig(p, false, &arg);
+ sx_sunlock(&proctree_lock);
}
- sx_sunlock(&proctree_lock);
- LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
- killpg1_sendsig(p, false, &arg);
- }
- PGRP_UNLOCK(pgrp);
- }
- MPASS(arg.ret != 0 || arg.found || !arg.sent);
+ } while (arg.found);
+out:
+ PRELE(td->td_proc);
+ crfree(arg.cr);
+ clean_unrhdr(&arg.pids);
+ clear_unrhdr(&arg.pids);
+
+ MPASS(arg.ret != 0 || arg.count != 0 || !arg.sent);
if (arg.ret == 0 && !arg.sent)
- arg.ret = arg.found ? EPERM : ESRCH;
+ arg.ret = arg.count != 0 ? EPERM : ESRCH;
return (arg.ret);
}
+int
+kern_prsignal(struct thread *td, struct prison *pr, int sig)
+{
+ ksiginfo_t ksi;
+
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = sig;
+ ksi.ksi_code = SI_USER;
+ ksi.ksi_pid = td->td_proc->p_pid;
+ ksi.ksi_uid = td->td_ucred->cr_ruid;
+
+ return (killpg1(td, sig, 0, pr, &ksi));
+}
+
#ifndef _SYS_SYSPROTO_H_
struct kill_args {
int pid;
@@ -1916,11 +2031,11 @@
}
switch (pid) {
case -1: /* broadcast signal */
- return (killpg1(td, signum, 0, 1, &ksi));
+ return (killpg1(td, signum, 0, td->td_ucred->cr_prison, &ksi));
case 0: /* signal own process group */
- return (killpg1(td, signum, 0, 0, &ksi));
+ return (killpg1(td, signum, 0, NULL, &ksi));
default: /* negative explicit process group */
- return (killpg1(td, signum, -pid, 0, &ksi));
+ return (killpg1(td, signum, -pid, NULL, &ksi));
}
/* NOTREACHED */
}
diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h
--- a/sys/sys/signalvar.h
+++ b/sys/sys/signalvar.h
@@ -324,6 +324,7 @@
}
struct pgrp;
+struct prison;
struct proc;
struct sigio;
struct thread;
@@ -390,6 +391,7 @@
void pgsigio(struct sigio **sigiop, int sig, int checkctty);
void pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi);
int postsig(int sig);
+int kern_prsignal(struct thread *td, struct prison *pr, int sig);
void kern_psignal(struct proc *p, int sig);
int ptracestop(struct thread *td, int sig, ksiginfo_t *si);
void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *retmask);

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 16, 4:02 PM (35 m, 32 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31538645
Default Alt Text
D39830.id121076.diff (8 KB)

Event Timeline