Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_sig.c
Show First 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | SYSCTL_INT(_kern, OID_AUTO, lognosys, CTLFLAG_RWTUN, &kern_lognosys, 0, | |||||||||
"Log invalid syscalls"); | "Log invalid syscalls"); | |||||||||
__read_frequently bool sigfastblock_fetch_always = false; | __read_frequently bool sigfastblock_fetch_always = false; | |||||||||
SYSCTL_BOOL(_kern, OID_AUTO, sigfastblock_fetch_always, CTLFLAG_RWTUN, | SYSCTL_BOOL(_kern, OID_AUTO, sigfastblock_fetch_always, CTLFLAG_RWTUN, | |||||||||
&sigfastblock_fetch_always, 0, | &sigfastblock_fetch_always, 0, | |||||||||
"Fetch sigfastblock word on each syscall entry for proper " | "Fetch sigfastblock word on each syscall entry for proper " | |||||||||
"blocking semantic"); | "blocking semantic"); | |||||||||
static bool kern_sig_ign_ign = true; | ||||||||||
SYSCTL_BOOL(_kern, OID_AUTO, sig_ign_ign, CTLFLAG_RWTUN, | ||||||||||
&kern_sig_ign_ign, 0, | ||||||||||
"Ignore ignored signals on delivery, otherwise queue them to " | ||||||||||
markj: Bikeshedding a bit, but instead of calling it "ignore ignored signals", "discard ignored… | ||||||||||
"the target queue"); | ||||||||||
SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); | SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); | |||||||||
/* | /* | |||||||||
* Policy -- Can ucred cr1 send SIGIO to process cr2? | * Policy -- Can ucred cr1 send SIGIO to process cr2? | |||||||||
* Should use cr_cansignal() once cr_cansignal() allows SIGIO and SIGURG | * Should use cr_cansignal() once cr_cansignal() allows SIGIO and SIGURG | |||||||||
* in the right situations. | * in the right situations. | |||||||||
*/ | */ | |||||||||
#define CANSIGIO(cr1, cr2) \ | #define CANSIGIO(cr1, cr2) \ | |||||||||
▲ Show 20 Lines • Show All 988 Lines • ▼ Show 20 Lines | sys_sigwait(struct thread *td, struct sigwait_args *uap) | |||||||||
error = copyin(uap->set, &set, sizeof(set)); | error = copyin(uap->set, &set, sizeof(set)); | |||||||||
if (error) { | if (error) { | |||||||||
td->td_retval[0] = error; | td->td_retval[0] = error; | |||||||||
return (0); | return (0); | |||||||||
} | } | |||||||||
error = kern_sigtimedwait(td, set, &ksi, NULL); | error = kern_sigtimedwait(td, set, &ksi, NULL); | |||||||||
if (error) { | if (error) { | |||||||||
/* | ||||||||||
* sigwait() function shall not return EINTR, but | ||||||||||
* syscall does. Non-ancient libc provides the | ||||||||||
markjUnsubmitted Done Inline Actions
markj: | ||||||||||
* wrapper which hides EINTR. Otherwise, EINTR return | ||||||||||
* is used by libthr to handle required cancellation | ||||||||||
* point in the sigwait(). | ||||||||||
*/ | ||||||||||
if (error == EINTR && td->td_proc->p_osrel < P_OSREL_SIGWAIT) | if (error == EINTR && td->td_proc->p_osrel < P_OSREL_SIGWAIT) | |||||||||
error = ERESTART; | error = ERESTART; | |||||||||
if (error == ERESTART) | if (error == ERESTART) | |||||||||
dchaginUnsubmitted Done Inline ActionsIm fine with change, one question - for now kern_sigtimedwait should never return ERESTART, what is the reason to leave it here? dchagin: Im fine with change, one question - for now kern_sigtimedwait should never return ERESTART… | ||||||||||
kibAuthorUnsubmitted Done Inline ActionsThe comment right above the block should explain it. Very old libc (before symbol versioning) did not contained the loop over EINTR, this is why we translate EINTR to ERESTART one line above. kib: The comment right above the block should explain it. Very old libc (before symbol versioning)… | ||||||||||
markjUnsubmitted Done Inline ActionsBut doesn't it mean that we can instead write if (error == EINTR && td->td_proc->p_osrel < P_OSREL_SIGWAIT) return (ERESTART); td->td_retval[0] = error; return (0); ? Or is it still possible for kern_sigtimedwait() to return ERESTART? markj: But doesn't it mean that we can instead write
```
if (error == EINTR && td->td_proc->p_osrel <… | ||||||||||
return (error); | return (error); | |||||||||
td->td_retval[0] = error; | td->td_retval[0] = error; | |||||||||
return (0); | return (0); | |||||||||
} | } | |||||||||
error = copyout(&ksi.ksi_signo, uap->sig, sizeof(ksi.ksi_signo)); | error = copyout(&ksi.ksi_signo, uap->sig, sizeof(ksi.ksi_signo)); | |||||||||
td->td_retval[0] = error; | td->td_retval[0] = error; | |||||||||
return (0); | return (0); | |||||||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi, | |||||||||
} | } | |||||||||
ksiginfo_init(ksi); | ksiginfo_init(ksi); | |||||||||
/* Some signals can not be waited for. */ | /* Some signals can not be waited for. */ | |||||||||
SIG_CANTMASK(waitset); | SIG_CANTMASK(waitset); | |||||||||
ps = p->p_sigacts; | ps = p->p_sigacts; | |||||||||
PROC_LOCK(p); | PROC_LOCK(p); | |||||||||
saved_mask = td->td_sigmask; | saved_mask = td->td_sigmask; | |||||||||
SIGSETNAND(td->td_sigmask, waitset); | SIGSETNAND(td->td_sigmask, waitset); | |||||||||
if ((p->p_sysent->sv_flags & SV_SIG_IGNIGN) != 0 || | ||||||||||
!kern_sig_ign_ign) | ||||||||||
td->td_pflags2 |= TDP2_SIGWAIT; | ||||||||||
for (;;) { | for (;;) { | |||||||||
mtx_lock(&ps->ps_mtx); | mtx_lock(&ps->ps_mtx); | |||||||||
sig = cursig(td); | sig = cursig(td); | |||||||||
mtx_unlock(&ps->ps_mtx); | mtx_unlock(&ps->ps_mtx); | |||||||||
KASSERT(sig >= 0, ("sig %d", sig)); | KASSERT(sig >= 0, ("sig %d", sig)); | |||||||||
if (sig != 0 && SIGISMEMBER(waitset, sig)) { | if (sig != 0 && SIGISMEMBER(waitset, sig)) { | |||||||||
if (sigqueue_get(&td->td_sigqueue, sig, ksi) != 0 || | if (sigqueue_get(&td->td_sigqueue, sig, ksi) != 0 || | |||||||||
sigqueue_get(&p->p_sigqueue, sig, ksi) != 0) { | sigqueue_get(&p->p_sigqueue, sig, ksi) != 0) { | |||||||||
Show All 28 Lines | for (;;) { | |||||||||
if (traced) { | if (traced) { | |||||||||
error = EINTR; | error = EINTR; | |||||||||
break; | break; | |||||||||
} | } | |||||||||
error = msleep(ps, &p->p_mtx, PPAUSE|PCATCH, "sigwait", timo); | error = msleep(ps, &p->p_mtx, PPAUSE|PCATCH, "sigwait", timo); | |||||||||
if (timeout != NULL) { | /* The syscalls can not be restarted. */ | |||||||||
if (error == ERESTART) { | if (error == ERESTART) | |||||||||
/* Timeout can not be restarted. */ | ||||||||||
error = EINTR; | error = EINTR; | |||||||||
} else if (error == EAGAIN) { | ||||||||||
/* We will calculate timeout by ourself. */ | /* We will calculate timeout by ourself. */ | |||||||||
if (timeout != NULL && error == EAGAIN) | ||||||||||
error = 0; | error = 0; | |||||||||
} | ||||||||||
} | ||||||||||
/* | /* | |||||||||
* If PTRACE_SCE or PTRACE_SCX were set after | * If PTRACE_SCE or PTRACE_SCX were set after | |||||||||
* userspace entered the syscall, return spurious | * userspace entered the syscall, return spurious | |||||||||
* EINTR after wait was done. Only do this as last | * EINTR after wait was done. Only do this as last | |||||||||
* resort after rechecking for possible queued signals | * resort after rechecking for possible queued signals | |||||||||
* and expired timeouts. | * and expired timeouts. | |||||||||
*/ | */ | |||||||||
if (error == 0 && (p->p_ptevents & PTRACE_SYSCALL) != 0) | if (error == 0 && (p->p_ptevents & PTRACE_SYSCALL) != 0) | |||||||||
traced = true; | traced = true; | |||||||||
} | } | |||||||||
td->td_pflags2 &= ~TDP2_SIGWAIT; | ||||||||||
new_block = saved_mask; | new_block = saved_mask; | |||||||||
SIGSETNAND(new_block, td->td_sigmask); | SIGSETNAND(new_block, td->td_sigmask); | |||||||||
td->td_sigmask = saved_mask; | td->td_sigmask = saved_mask; | |||||||||
/* | /* | |||||||||
* Fewer signals can be delivered to us, reschedule signal | * Fewer signals can be delivered to us, reschedule signal | |||||||||
* notification. | * notification. | |||||||||
*/ | */ | |||||||||
▲ Show 20 Lines • Show All 832 Lines • ▼ Show 20 Lines | if (td == NULL) { | |||||||||
td = sigtd(p, sig, false); | td = sigtd(p, sig, false); | |||||||||
sigqueue = &p->p_sigqueue; | sigqueue = &p->p_sigqueue; | |||||||||
} else | } else | |||||||||
sigqueue = &td->td_sigqueue; | sigqueue = &td->td_sigqueue; | |||||||||
SDT_PROBE3(proc, , , signal__send, td, p, sig); | SDT_PROBE3(proc, , , signal__send, td, p, sig); | |||||||||
/* | /* | |||||||||
* If the signal is being ignored, | * If the signal is being ignored, then we forget about it | |||||||||
* then we forget about it immediately. | * immediately, except when the target process executes | |||||||||
* (Note: we don't set SIGCONT in ps_sigignore, | * sigwait(). (Note: we don't set SIGCONT in ps_sigignore, | |||||||||
* and if it is set to SIG_IGN, | * and if it is set to SIG_IGN, action will be SIG_DFL here.) | |||||||||
* action will be SIG_DFL here.) | ||||||||||
*/ | */ | |||||||||
mtx_lock(&ps->ps_mtx); | mtx_lock(&ps->ps_mtx); | |||||||||
if (SIGISMEMBER(ps->ps_sigignore, sig)) { | if (SIGISMEMBER(ps->ps_sigignore, sig)) { | |||||||||
if (kern_sig_ign_ign && | ||||||||||
(p->p_sysent->sv_flags & SV_SIG_IGNIGN) == 0) { | ||||||||||
SDT_PROBE3(proc, , , signal__discard, td, p, sig); | SDT_PROBE3(proc, , , signal__discard, td, p, sig); | |||||||||
mtx_unlock(&ps->ps_mtx); | mtx_unlock(&ps->ps_mtx); | |||||||||
if (ksi && (ksi->ksi_flags & KSI_INS)) | if (ksi && (ksi->ksi_flags & KSI_INS)) | |||||||||
ksiginfo_tryfree(ksi); | ksiginfo_tryfree(ksi); | |||||||||
return (ret); | return (ret); | |||||||||
} else { | ||||||||||
action = SIG_CATCH; | ||||||||||
} | } | |||||||||
if (SIGISMEMBER(td->td_sigmask, sig)) | } else if (SIGISMEMBER(td->td_sigmask, sig)) | |||||||||
action = SIG_HOLD; | action = SIG_HOLD; | |||||||||
else if (SIGISMEMBER(ps->ps_sigcatch, sig)) | else if (SIGISMEMBER(ps->ps_sigcatch, sig)) | |||||||||
action = SIG_CATCH; | action = SIG_CATCH; | |||||||||
else | else | |||||||||
action = SIG_DFL; | action = SIG_DFL; | |||||||||
if (SIGISMEMBER(ps->ps_sigintr, sig)) | if (SIGISMEMBER(ps->ps_sigintr, sig)) | |||||||||
intrval = EINTR; | intrval = EINTR; | |||||||||
else | else | |||||||||
▲ Show 20 Lines • Show All 718 Lines • ▼ Show 20 Lines | if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED && | |||||||||
*/ | */ | |||||||||
sig = SIGSTOP; | sig = SIGSTOP; | |||||||||
td->td_dbgflags |= TDB_FSTP; | td->td_dbgflags |= TDB_FSTP; | |||||||||
} else { | } else { | |||||||||
sig = sig_ffs(&sigpending); | sig = sig_ffs(&sigpending); | |||||||||
} | } | |||||||||
/* | /* | |||||||||
* We should see pending but ignored signals | * We should allow pending but ignored signals below | |||||||||
* only if P_TRACED was on when they were posted. | * only if there is sigwait() active, or P_TRACED was | |||||||||
* on when they were posted. | ||||||||||
*/ | */ | |||||||||
if (SIGISMEMBER(ps->ps_sigignore, sig) && | if (SIGISMEMBER(ps->ps_sigignore, sig) && | |||||||||
(p->p_flag & P_TRACED) == 0) { | (p->p_flag & P_TRACED) == 0 && | |||||||||
(td->td_pflags2 & TDP2_SIGWAIT) == 0) { | ||||||||||
sigqueue_delete(&td->td_sigqueue, sig); | sigqueue_delete(&td->td_sigqueue, sig); | |||||||||
sigqueue_delete(&p->p_sigqueue, sig); | sigqueue_delete(&p->p_sigqueue, sig); | |||||||||
continue; | continue; | |||||||||
} | } | |||||||||
if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) { | if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) { | |||||||||
/* | /* | |||||||||
* If traced, always stop. | * If traced, always stop. | |||||||||
* Remove old signal from queue before the stop. | * Remove old signal from queue before the stop. | |||||||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | #endif | |||||||||
p->p_flag |= P_STOPPED_SIG; | p->p_flag |= P_STOPPED_SIG; | |||||||||
p->p_xsig = sig; | p->p_xsig = sig; | |||||||||
PROC_SLOCK(p); | PROC_SLOCK(p); | |||||||||
sig_suspend_threads(td, p, 0); | sig_suspend_threads(td, p, 0); | |||||||||
thread_suspend_switch(td, p); | thread_suspend_switch(td, p); | |||||||||
PROC_SUNLOCK(p); | PROC_SUNLOCK(p); | |||||||||
mtx_lock(&ps->ps_mtx); | mtx_lock(&ps->ps_mtx); | |||||||||
goto next; | goto next; | |||||||||
} else if (prop & SIGPROP_IGNORE) { | } else if ((prop & SIGPROP_IGNORE) != 0 && | |||||||||
(td->td_pflags2 & TDP2_SIGWAIT) == 0) { | ||||||||||
/* | /* | |||||||||
* Except for SIGCONT, shouldn't get here. | * Default action is to ignore; drop it if | |||||||||
* Default action is to ignore; drop it. | * not in sigtimedwait(). | |||||||||
markjUnsubmitted Done Inline Actions
markj: | ||||||||||
*/ | */ | |||||||||
break; /* == ignore */ | break; /* == ignore */ | |||||||||
} else | } else | |||||||||
return (sig); | return (sig); | |||||||||
/*NOTREACHED*/ | /*NOTREACHED*/ | |||||||||
case (intptr_t)SIG_IGN: | case (intptr_t)SIG_IGN: | |||||||||
/* | if ((td->td_pflags2 & TDP2_SIGWAIT) == 0) | |||||||||
* Masking above should prevent us ever trying | ||||||||||
* to take action on an ignored signal other | ||||||||||
* than SIGCONT, unless process is traced. | ||||||||||
*/ | ||||||||||
if ((prop & SIGPROP_CONT) == 0 && | ||||||||||
(p->p_flag & P_TRACED) == 0) | ||||||||||
printf("issignal\n"); | ||||||||||
break; /* == ignore */ | break; /* == ignore */ | |||||||||
else | ||||||||||
return (sig); | ||||||||||
default: | default: | |||||||||
/* | /* | |||||||||
* This signal has an action, let | * This signal has an action, let | |||||||||
* postsig() process it. | * postsig() process it. | |||||||||
*/ | */ | |||||||||
return (sig); | return (sig); | |||||||||
} | } | |||||||||
▲ Show 20 Lines • Show All 1,213 Lines • Show Last 20 Lines |
Bikeshedding a bit, but instead of calling it "ignore ignored signals", "discard ignored signals" might be more clear.