Changeset View
Standalone View
sys/kern/kern_sig.c
Show First 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | |||||
static int capmode_coredump; | static int capmode_coredump; | ||||
SYSCTL_INT(_kern, OID_AUTO, capmode_coredump, CTLFLAG_RWTUN, | SYSCTL_INT(_kern, OID_AUTO, capmode_coredump, CTLFLAG_RWTUN, | ||||
&capmode_coredump, 0, "Allow processes in capability mode to dump core"); | &capmode_coredump, 0, "Allow processes in capability mode to dump core"); | ||||
static int do_coredump = 1; | static int do_coredump = 1; | ||||
SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, | SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, | ||||
&do_coredump, 0, "Enable/Disable coredumps"); | &do_coredump, 0, "Enable/Disable coredumps"); | ||||
static int do_corestop = 0; | |||||
SYSCTL_INT(_kern, OID_AUTO, corestop, CTLFLAG_RW, | |||||
&do_corestop, 0, "Stop the process instead of dumping core"); | |||||
static int set_core_nodump_flag = 0; | static int set_core_nodump_flag = 0; | ||||
SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, | SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, | ||||
0, "Enable setting the NODUMP flag on coredump files"); | 0, "Enable setting the NODUMP flag on coredump files"); | ||||
static int coredump_devctl = 0; | static int coredump_devctl = 0; | ||||
SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl, | SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl, | ||||
0, "Generate a devctl notification when processes coredump"); | 0, "Generate a devctl notification when processes coredump"); | ||||
▲ Show 20 Lines • Show All 1,830 Lines • ▼ Show 20 Lines | #endif | ||||
postsig_done(sig, td, ps); | postsig_done(sig, td, ps); | ||||
mtx_unlock(&ps->ps_mtx); | mtx_unlock(&ps->ps_mtx); | ||||
} else { | } else { | ||||
/* | /* | ||||
* Avoid a possible infinite loop if the thread | * Avoid a possible infinite loop if the thread | ||||
* masking the signal or process is ignoring the | * masking the signal or process is ignoring the | ||||
* signal. | * signal. | ||||
*/ | */ | ||||
if (kern_forcesigexit && (SIGISMEMBER(sigmask, sig) || | if (kern_forcesigexit && (SIGISMEMBER(sigmask, sig) || | ||||
kib: You never clear P2_CORESTOPPED. | |||||
ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN)) { | ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN)) { | ||||
SIGDELSET(td->td_sigmask, sig); | SIGDELSET(td->td_sigmask, sig); | ||||
SIGDELSET(ps->ps_sigcatch, sig); | SIGDELSET(ps->ps_sigcatch, sig); | ||||
SIGDELSET(ps->ps_sigignore, sig); | SIGDELSET(ps->ps_sigignore, sig); | ||||
ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; | ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; | ||||
td->td_pflags &= ~TDP_SIGFASTBLOCK; | td->td_pflags &= ~TDP_SIGFASTBLOCK; | ||||
td->td_sigblock_val = 0; | td->td_sigblock_val = 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 925 Lines • ▼ Show 20 Lines | #ifdef DIAGNOSTIC | ||||
* Are you sure you want to ignore SIGSEGV | * Are you sure you want to ignore SIGSEGV | ||||
* in init? XXX | * in init? XXX | ||||
*/ | */ | ||||
printf("Process (pid %lu) got signal %d\n", | printf("Process (pid %lu) got signal %d\n", | ||||
(u_long)p->p_pid, sig); | (u_long)p->p_pid, sig); | ||||
#endif | #endif | ||||
break; /* == ignore */ | break; /* == ignore */ | ||||
} | } | ||||
/* | /* | ||||
* If the process is being corestopped, signals | |||||
* that would otherwise coredump turn into stops. | |||||
*/ | |||||
if ((p->p_flag2 & P2_CORESTOPPED) && | |||||
(prop & SIGPROP_CORE)) { | |||||
prop |= SIGPROP_STOP; | |||||
} | |||||
/* | |||||
* If there is a pending stop signal to process with | * If there is a pending stop signal to process with | ||||
* default action, stop here, then clear the signal. | * default action, stop here, then clear the signal. | ||||
* Traced or exiting processes should ignore stops. | * Traced or exiting processes should ignore stops. | ||||
* Additionally, a member of an orphaned process group | * Additionally, a member of an orphaned process group | ||||
* should ignore tty stops. | * should ignore tty stops. | ||||
*/ | */ | ||||
if (prop & SIGPROP_STOP) { | if (prop & SIGPROP_STOP) { | ||||
Not Done Inline ActionsIf I would play with something like this, I would just changed this line to if ((prop & SIGPROP_STOP) != 0 || (corestop && (prop & SIGPROP_CORE) != 0)) Then if SIGPROP_CORE is set, I would send notifications before stopping. kib: If I would play with something like this, I would just changed this line to
```
if ((prop &… | |||||
if (p->p_flag & | if (p->p_flag & | ||||
(P_TRACED | P_WEXIT | P_SINGLE_EXIT) || | (P_TRACED | P_WEXIT | P_SINGLE_EXIT) || | ||||
(p->p_pgrp->pg_jobc == 0 && | (p->p_pgrp->pg_jobc == 0 && | ||||
prop & SIGPROP_TTYSTOP)) | prop & SIGPROP_TTYSTOP)) | ||||
break; /* == ignore */ | break; /* == ignore */ | ||||
if (TD_SBDRY_INTR(td)) { | if (TD_SBDRY_INTR(td)) { | ||||
KASSERT((td->td_flags & TDF_SBDRY) != 0, | KASSERT((td->td_flags & TDF_SBDRY) != 0, | ||||
("lost TDF_SBDRY")); | ("lost TDF_SBDRY")); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if ((p->p_flag & P_STOPPED_SIG) && (n == p->p_numthreads)) { | ||||
PROC_LOCK(p->p_pptr); | PROC_LOCK(p->p_pptr); | ||||
childproc_stopped(p, (p->p_flag & P_TRACED) ? | childproc_stopped(p, (p->p_flag & P_TRACED) ? | ||||
CLD_TRAPPED : CLD_STOPPED); | CLD_TRAPPED : CLD_STOPPED); | ||||
PROC_UNLOCK(p->p_pptr); | PROC_UNLOCK(p->p_pptr); | ||||
PROC_SLOCK(p); | PROC_SLOCK(p); | ||||
} | } | ||||
} | } | ||||
static void | |||||
corestop(int sig) | |||||
{ | |||||
char strbuf[32]; | |||||
struct thread *td; | |||||
struct proc *p; | |||||
int rv; | |||||
td = curthread; | |||||
kibUnsubmitted Done Inline ActionsI think you should pass td as an argument. kib: I think you should pass td as an argument. | |||||
p = td->td_proc; | |||||
KASSERT((p->p_flag2 & P2_CORESTOPPED) == 0, | |||||
kibUnsubmitted Not Done Inline ActionsWhy is this assert valid ? Also, you should document, by asserts, all the locks that are assumed in this functions. The proc lock at least. Which leads to the question, how wise is to log and send devctl notification under the process lock (and sigacts mutex as well). kib: Why is this assert valid ?
Also, you should document, by asserts, all the locks that are… | |||||
traszAuthorUnsubmitted Done Inline ActionsIs the assert ok now? Regarding logs and devctl - I'm not sure. WITNESS doesn't yell about it, so I'm assuming it's ok? The sigacts mutex would be easy to get rid of; proc - not sure. trasz: Is the assert ok now?
Regarding logs and devctl - I'm not sure. WITNESS doesn't yell about it… | |||||
("%s: P2_CORESTOPPED already set", __func__)); | |||||
/* | /* | ||||
* Borrow policy checking from coredump(9). | |||||
*/ | |||||
if ((!sugid_coredump && (p->p_flag & P_SUGID) != 0) || | |||||
(p->p_flag2 & P2_NOTRACE) != 0) { | |||||
PROC_UNLOCK(p); | |||||
return; | |||||
} | |||||
p->p_flag2 |= P2_CORESTOPPED; | |||||
log(LOG_INFO, | |||||
"pid %d (%s), jid %d, uid %d: would exit on " | |||||
"signal %d (core stopped)\n", p->p_pid, p->p_comm, | |||||
p->p_ucred->cr_prison->pr_id, | |||||
td->td_ucred->cr_uid, | |||||
sig &~ WCOREFLAG); | |||||
rv = snprintf(strbuf, sizeof(strbuf), | |||||
"pid=%d euid=%d", p->p_pid, p->p_ucred->cr_uid); | |||||
KASSERT(rv > 0 && rv < sizeof(strbuf), | |||||
("%s: snprintf failed\n", __func__)); | |||||
devctl_notify("kernel", "signal", "corestop", strbuf); | |||||
} | |||||
/* | |||||
* Take the action for the specified signal | * Take the action for the specified signal | ||||
* from the current set of pending signals. | * from the current set of pending signals. | ||||
*/ | */ | ||||
int | int | ||||
postsig(int sig) | postsig(int sig) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
struct proc *p; | struct proc *p; | ||||
Show All 19 Lines | postsig(int sig) | ||||
action = ps->ps_sigact[_SIG_IDX(sig)]; | action = ps->ps_sigact[_SIG_IDX(sig)]; | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
if (KTRPOINT(td, KTR_PSIG)) | if (KTRPOINT(td, KTR_PSIG)) | ||||
ktrpsig(sig, action, td->td_pflags & TDP_OLDMASK ? | ktrpsig(sig, action, td->td_pflags & TDP_OLDMASK ? | ||||
&td->td_oldsigmask : &td->td_sigmask, ksi.ksi_code); | &td->td_oldsigmask : &td->td_sigmask, ksi.ksi_code); | ||||
#endif | #endif | ||||
if (action == SIG_DFL) { | if (action == SIG_DFL) { | ||||
if (do_corestop && (sigprop(sig) & SIGPROP_CORE)) { | |||||
corestop(sig); | |||||
kibUnsubmitted Not Done Inline ActionsYou basically loose the original signal there, I do not see how could the code work as intended, reliably. kib: You basically loose the original signal there, I do not see how could the code work as… | |||||
traszAuthorUnsubmitted Done Inline ActionsI think I got it right this time. Or rather - as right as reasonably possible. trasz: I think I got it right this time. Or rather - as right as reasonably possible. | |||||
} else { | |||||
/* | /* | ||||
* Default action, where the default is to kill | * Default action, where the default is to kill | ||||
* the process. (Other cases were ignored above.) | * the process. (Other cases were ignored above.) | ||||
*/ | */ | ||||
mtx_unlock(&ps->ps_mtx); | mtx_unlock(&ps->ps_mtx); | ||||
proc_td_siginfo_capture(td, &ksi.ksi_info); | proc_td_siginfo_capture(td, &ksi.ksi_info); | ||||
sigexit(td, sig); | sigexit(td, sig); | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
} | |||||
} else { | } else { | ||||
/* | /* | ||||
* If we get here, the signal must be caught. | * If we get here, the signal must be caught. | ||||
*/ | */ | ||||
KASSERT(action != SIG_IGN, ("postsig action %p", action)); | KASSERT(action != SIG_IGN, ("postsig action %p", action)); | ||||
KASSERT(!SIGISMEMBER(td->td_sigmask, sig), | KASSERT(!SIGISMEMBER(td->td_sigmask, sig), | ||||
("postsig action: blocked sig %d", sig)); | ("postsig action: blocked sig %d", sig)); | ||||
▲ Show 20 Lines • Show All 671 Lines • ▼ Show 20 Lines | nosys(struct thread *td, struct nosys_args *args) | ||||
} | } | ||||
if (kern_lognosys == 2 || kern_lognosys == 3) { | if (kern_lognosys == 2 || kern_lognosys == 3) { | ||||
printf("pid %d comm %s: nosys %d\n", p->p_pid, p->p_comm, | printf("pid %d comm %s: nosys %d\n", p->p_pid, p->p_comm, | ||||
td->td_sa.code); | td->td_sa.code); | ||||
} | } | ||||
return (ENOSYS); | return (ENOSYS); | ||||
} | } | ||||
/* | /* | ||||
Not Done Inline ActionsYou still never clear the flag. kib: You still never clear the flag. | |||||
* Send a SIGIO or SIGURG signal to a process or process group using stored | * Send a SIGIO or SIGURG signal to a process or process group using stored | ||||
* credentials rather than those of the current process. | * credentials rather than those of the current process. | ||||
*/ | */ | ||||
void | void | ||||
pgsigio(struct sigio **sigiop, int sig, int checkctty) | pgsigio(struct sigio **sigiop, int sig, int checkctty) | ||||
{ | { | ||||
ksiginfo_t ksi; | ksiginfo_t ksi; | ||||
struct sigio *sigio; | struct sigio *sigio; | ||||
ksiginfo_init(&ksi); | ksiginfo_init(&ksi); | ||||
ksi.ksi_signo = sig; | ksi.ksi_signo = sig; | ||||
ksi.ksi_code = SI_KERNEL; | ksi.ksi_code = SI_KERNEL; | ||||
SIGIO_LOCK(); | SIGIO_LOCK(); | ||||
sigio = *sigiop; | sigio = *sigiop; | ||||
if (sigio == NULL) { | if (sigio == NULL) { | ||||
SIGIO_UNLOCK(); | SIGIO_UNLOCK(); | ||||
return; | return; | ||||
} | } | ||||
if (sigio->sio_pgid > 0) { | if (sigio->sio_pgid > 0) { | ||||
PROC_LOCK(sigio->sio_proc); | PROC_LOCK(sigio->sio_proc); | ||||
if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc->p_ucred)) | if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc->p_ucred)) | ||||
kern_psignal(sigio->sio_proc, sig); | kern_psignal(sigio->sio_proc, sig); | ||||
PROC_UNLOCK(sigio->sio_proc); | PROC_UNLOCK(sigio->sio_proc); | ||||
} else if (sigio->sio_pgid < 0) { | } else if (sigio->sio_pgid < 0) { | ||||
Not Done Inline ActionsAgain this erases any info about the signal. kib: Again this erases any info about the signal. | |||||
struct proc *p; | struct proc *p; | ||||
Not Done Inline ActionsThis is weird. More weird is that you stopping the process without notifying potential debugger. kib: This is weird. More weird is that you stopping the process without notifying potential… | |||||
PGRP_LOCK(sigio->sio_pgrp); | PGRP_LOCK(sigio->sio_pgrp); | ||||
LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { | LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state == PRS_NORMAL && | if (p->p_state == PRS_NORMAL && | ||||
CANSIGIO(sigio->sio_ucred, p->p_ucred) && | CANSIGIO(sigio->sio_ucred, p->p_ucred) && | ||||
Not Done Inline ActionsThis block was copied/pasted. Can you refactor instead ? kib: This block was copied/pasted. Can you refactor instead ? | |||||
(checkctty == 0 || (p->p_flag & P_CONTROLT))) | (checkctty == 0 || (p->p_flag & P_CONTROLT))) | ||||
kern_psignal(p, sig); | kern_psignal(p, sig); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
PGRP_UNLOCK(sigio->sio_pgrp); | PGRP_UNLOCK(sigio->sio_pgrp); | ||||
} | } | ||||
SIGIO_UNLOCK(); | SIGIO_UNLOCK(); | ||||
Not Done Inline ActionsThis is a recursion, perhaps infinite. kib: This is a recursion, perhaps infinite. | |||||
} | } | ||||
static int | static int | ||||
filt_sigattach(struct knote *kn) | filt_sigattach(struct knote *kn) | ||||
{ | { | ||||
struct proc *p = curproc; | struct proc *p = curproc; | ||||
kn->kn_ptr.p_proc = p; | kn->kn_ptr.p_proc = p; | ||||
▲ Show 20 Lines • Show All 312 Lines • Show Last 20 Lines |
You never clear P2_CORESTOPPED.