* Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)kern_sig.c 7.56 (Berkeley) %G%
#define SIGPROP /* include signal properties table */
#include <sys/signalvar.h>
#include <sys/resourcevar.h>
#include <sys/user.h> /* for coredump */
* Can process p, with pcred pc, send the signal signo to process q?
#define CANSIGNAL(p, pc, q, signo) \
((pc)->pc_ucred->cr_uid == 0 || \
(pc)->p_ruid == (q)->p_cred->p_ruid || \
(pc)->pc_ucred->cr_uid == (q)->p_cred->p_ruid || \
(pc)->p_ruid == (q)->p_ucred->cr_uid || \
(pc)->pc_ucred->cr_uid == (q)->p_ucred->cr_uid || \
((signo) == SIGCONT && (q)->p_session == (p)->p_session))
sigaction(p
, uap
, retval
)
register struct sigaction_args
*uap
;
register struct sigaction
*sa
;
register struct sigacts
*ps
= p
->p_sigacts
;
if (sig
<= 0 || sig
>= NSIG
|| sig
== SIGKILL
|| sig
== SIGSTOP
)
sa
->sa_handler
= ps
->ps_sigact
[sig
];
sa
->sa_mask
= ps
->ps_catchmask
[sig
];
if ((ps
->ps_sigonstack
& bit
) != 0)
sa
->sa_flags
|= SA_ONSTACK
;
if ((ps
->ps_sigintr
& bit
) == 0)
sa
->sa_flags
|= SA_RESTART
;
if (p
->p_flag
& SNOCLDSTOP
)
sa
->sa_flags
|= SA_NOCLDSTOP
;
if (error
= copyout((caddr_t
)sa
, (caddr_t
)uap
->osa
,
if (error
= copyin((caddr_t
)uap
->nsa
, (caddr_t
)sa
,
register struct sigaction
*sa
;
register struct sigacts
*ps
= p
->p_sigacts
;
* Change setting atomically.
ps
->ps_sigact
[sig
] = sa
->sa_handler
;
ps
->ps_catchmask
[sig
] = sa
->sa_mask
&~ sigcantmask
;
if ((sa
->sa_flags
& SA_RESTART
) == 0)
if (sa
->sa_flags
& SA_ONSTACK
)
ps
->ps_sigonstack
|= bit
;
ps
->ps_sigonstack
&= ~bit
;
if (sa
->sa_flags
& SA_USERTRAMP
)
ps
->ps_usertramp
&= ~bit
;
if (sa
->sa_flags
& SA_NOCLDSTOP
)
p
->p_flag
&= ~SNOCLDSTOP
;
* Set bit in p_sigignore for signals that are set to SIG_IGN,
* and for signals set to SIG_DFL where the default is to ignore.
* However, don't put SIGCONT in p_sigignore,
* as we have to restart the process.
if (sa
->sa_handler
== SIG_IGN
||
(sigprop
[sig
] & SA_IGNORE
&& sa
->sa_handler
== SIG_DFL
)) {
p
->p_sig
&= ~bit
; /* never to be seen again */
p
->p_sigignore
|= bit
; /* easier in psignal */
if (sa
->sa_handler
== SIG_DFL
)
* Initialize signal state for process 0;
* set to ignore signals that are ignored by default.
for (i
= 0; i
< NSIG
; i
++)
if (sigprop
[i
] & SA_IGNORE
&& i
!= SIGCONT
)
p
->p_sigignore
|= sigmask(i
);
* Reset signals for an exec of the specified process.
register struct sigacts
*ps
= p
->p_sigacts
;
* Reset caught signals. Held signals remain held
* through p_sigmask (unless they were caught,
* and are now ignored by default).
nc
= ffs((long)p
->p_sigcatch
);
if (sigprop
[nc
] & SA_IGNORE
) {
ps
->ps_sigact
[nc
] = SIG_DFL
;
* Reset stack state to the user stack.
* Clear set of signals caught on the signal stack.
ps
->ps_sigstk
.ss_flags
= SA_DISABLE
;
ps
->ps_sigstk
.ss_size
= 0;
ps
->ps_sigstk
.ss_base
= 0;
* Manipulate signal mask.
* Note that we receive new mask, not pointer,
* and return old mask as return value;
* the library stub does the rest.
struct sigprocmask_args
{
sigprocmask(p
, uap
, retval
)
struct sigprocmask_args
*uap
;
p
->p_sigmask
|= uap
->mask
&~ sigcantmask
;
p
->p_sigmask
&= ~uap
->mask
;
p
->p_sigmask
= uap
->mask
&~ sigcantmask
;
sigpending(p
, uap
, retval
)
struct sigpending_args
*uap
;
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
* Generalized interface signal handler, 4.3-compatible.
register struct osigvec_args
*uap
;
register struct sigacts
*ps
= p
->p_sigacts
;
register struct sigvec
*sv
;
if (sig
<= 0 || sig
>= NSIG
|| sig
== SIGKILL
|| sig
== SIGSTOP
)
*(sig_t
*)&sv
->sv_handler
= ps
->ps_sigact
[sig
];
sv
->sv_mask
= ps
->ps_catchmask
[sig
];
if ((ps
->ps_sigonstack
& bit
) != 0)
sv
->sv_flags
|= SV_ONSTACK
;
if ((ps
->ps_sigintr
& bit
) != 0)
sv
->sv_flags
|= SV_INTERRUPT
;
if (p
->p_flag
& SNOCLDSTOP
)
sv
->sv_flags
|= SA_NOCLDSTOP
;
if (error
= copyout((caddr_t
)sv
, (caddr_t
)uap
->osv
,
if (error
= copyin((caddr_t
)uap
->nsv
, (caddr_t
)sv
,
* SunOS uses this bit (4, aka SA_DISABLE) as SV_RESETHAND,
* `reset to SIG_DFL on delivery'. We have no such option
if (sv
->sv_flags
& SA_DISABLE
)
sv
->sv_flags
|= SA_USERTRAMP
;
sv
->sv_flags
^= SA_RESTART
; /* opposite of SV_INTERRUPT */
setsigvec(p
, sig
, (struct sigaction
*)sv
);
osigblock(p
, uap
, retval
)
struct osigblock_args
*uap
;
p
->p_sigmask
|= uap
->mask
&~ sigcantmask
;
struct osigsetmask_args
{
osigsetmask(p
, uap
, retval
)
struct osigsetmask_args
*uap
;
p
->p_sigmask
= uap
->mask
&~ sigcantmask
;
#endif /* COMPAT_43 || COMPAT_SUNOS */
* Suspend process until signal, providing mask to be set
* in the meantime. Note nonstandard calling convention:
* libc stub passes mask, not pointer, to save a copyin.
sigsuspend(p
, uap
, retval
)
struct sigsuspend_args
*uap
;
register struct sigacts
*ps
= p
->p_sigacts
;
* When returning from sigpause, we want
* the old mask to be restored after the
* signal handler has finished. Thus, we
* save it here and mark the sigacts structure
ps
->ps_oldmask
= p
->p_sigmask
;
ps
->ps_flags
|= SAS_OLDMASK
;
p
->p_sigmask
= uap
->mask
&~ sigcantmask
;
while (tsleep((caddr_t
) ps
, PPAUSE
|PCATCH
, "pause", 0) == 0)
/* always return EINTR rather than ERESTART... */
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
osigstack(p
, uap
, retval
)
register struct osigstack_args
*uap
;
ss
.ss_sp
= psp
->ps_sigstk
.ss_base
;
ss
.ss_onstack
= psp
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
if (uap
->oss
&& (error
= copyout((caddr_t
)&ss
, (caddr_t
)uap
->oss
,
sizeof (struct sigstack
))))
if (uap
->nss
&& (error
= copyin((caddr_t
)uap
->nss
, (caddr_t
)&ss
,
psp
->ps_sigstk
.ss_base
= ss
.ss_sp
;
psp
->ps_sigstk
.ss_size
= 0;
psp
->ps_sigstk
.ss_flags
|= ss
.ss_onstack
& SA_ONSTACK
;
psp
->ps_flags
|= SAS_ALTSTACK
;
#endif /* COMPAT_43 || COMPAT_SUNOS */
struct sigaltstack_args
{
sigaltstack(p
, uap
, retval
)
register struct sigaltstack_args
*uap
;
if ((psp
->ps_flags
& SAS_ALTSTACK
) == 0)
psp
->ps_sigstk
.ss_flags
|= SA_DISABLE
;
if (uap
->oss
&& (error
= copyout((caddr_t
)&psp
->ps_sigstk
,
(caddr_t
)uap
->oss
, sizeof (struct sigaltstack
))))
if (error
= copyin((caddr_t
)uap
->nss
, (caddr_t
)&ss
, sizeof (ss
)))
if (ss
.ss_flags
& SA_DISABLE
) {
if (psp
->ps_sigstk
.ss_flags
& SA_ONSTACK
)
psp
->ps_flags
&= ~SAS_ALTSTACK
;
psp
->ps_sigstk
.ss_flags
= ss
.ss_flags
;
if (ss
.ss_size
< MINSIGSTKSZ
)
psp
->ps_flags
|= SAS_ALTSTACK
;
register struct proc
*cp
;
register struct kill_args
*uap
;
register struct pcred
*pc
= cp
->p_cred
;
if ((unsigned) uap
->signo
>= NSIG
)
/* kill single process */
if (!CANSIGNAL(cp
, pc
, p
, uap
->signo
))
case -1: /* broadcast signal */
return (killpg1(cp
, uap
->signo
, 0, 1));
case 0: /* signal own process group */
return (killpg1(cp
, uap
->signo
, 0, 0));
default: /* negative explicit process group */
return (killpg1(cp
, uap
->signo
, -uap
->pid
, 0));
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
register struct okillpg_args
*uap
;
if ((unsigned) uap
->signo
>= NSIG
)
return (killpg1(p
, uap
->signo
, uap
->pgid
, 0));
#endif /* COMPAT_43 || COMPAT_SUNOS */
* Common code for kill process group/broadcast kill.
killpg1(cp
, signo
, pgid
, all
)
register struct proc
*cp
;
register struct pcred
*pc
= cp
->p_cred
;
for (p
= (struct proc
*)allproc
; p
!= NULL
; p
= p
->p_nxt
) {
if (p
->p_pid
<= 1 || p
->p_flag
& SSYS
||
p
== cp
|| !CANSIGNAL(cp
, pc
, p
, signo
))
* zero pgid means send to my process group.
for (p
= pgrp
->pg_mem
; p
!= NULL
; p
= p
->p_pgrpnxt
) {
if (p
->p_pid
<= 1 || p
->p_flag
& SSYS
||
p
->p_stat
== SZOMB
|| !CANSIGNAL(cp
, pc
, p
, signo
))
return (nfound
? 0 : ESRCH
);
* Send the specified signal to
* all processes with 'pgid' as
if (pgid
&& (pgrp
= pgfind(pgid
)))
* Send sig to every member of a process group.
* If checktty is 1, limit to members which have a controlling
pgsignal(pgrp
, sig
, checkctty
)
for (p
= pgrp
->pg_mem
; p
!= NULL
; p
= p
->p_pgrpnxt
)
if (checkctty
== 0 || p
->p_flag
& SCTTY
)
* Send a signal caused by a trap to the current process.
* If it will be caught immediately, deliver it with correct code.
* Otherwise, post it normally.
register struct sigacts
*ps
= p
->p_sigacts
;
if ((p
->p_flag
& STRC
) == 0 && (p
->p_sigcatch
& mask
) != 0 &&
(p
->p_sigmask
& mask
) == 0) {
p
->p_stats
->p_ru
.ru_nsignals
++;
if (KTRPOINT(p
, KTR_PSIG
))
ktrpsig(p
->p_tracep
, sig
, ps
->ps_sigact
[sig
],
sendsig(ps
->ps_sigact
[sig
], sig
, p
->p_sigmask
, code
);
p
->p_sigmask
|= ps
->ps_catchmask
[sig
] | mask
;
ps
->ps_code
= code
; /* XXX for core dump/debugger */
* Send the specified signal to the specified process.
* If the signal has an action, the action is usually performed
* by the target process rather than the caller; we simply add
* the signal to the set of pending signals for the process.
* o When a stop signal is sent to a sleeping process that takes the default
* action, the process is stopped without awakening it.
* o SIGCONT restarts stopped processes (or puts them back to sleep)
* regardless of the signal action (eg, blocked or ignored).
* Other ignored signals are discarded immediately.
if ((unsigned)sig
>= NSIG
|| sig
== 0)
* If proc is traced, always give parent a chance.
* If the signal is being ignored,
* then we forget about it immediately.
* (Note: we don't set SIGCONT in p_sigignore,
* and if it is set to SIG_IGN,
* action will be SIG_DFL here.)
if (p
->p_sigignore
& mask
)
else if (p
->p_sigcatch
& mask
)
if (p
->p_nice
> NZERO
&& action
== SIG_DFL
&& (prop
& SA_KILL
) &&
p
->p_sig
&= ~stopsigmask
;
* If sending a tty stop signal to a member of an orphaned
* process group, discard the signal here if the action
* is default; don't stop the process below if sleeping,
* and don't clear any pending SIGCONT.
if (prop
& SA_TTYSTOP
&& p
->p_pgrp
->pg_jobc
== 0 &&
p
->p_sig
&= ~contsigmask
;
* Defer further processing for signals which are held,
* except that stopped processes must be continued by SIGCONT.
if (action
== SIG_HOLD
&& ((prop
& SA_CONT
) == 0 || p
->p_stat
!= SSTOP
))
* If process is sleeping uninterruptibly
* we can't interrupt the sleep... the signal will
* be noticed when the process returns through
if ((p
->p_flag
& SSINTR
) == 0)
* Process is sleeping and traced... make it runnable
* so it can discover the signal in issig() and stop
* If SIGCONT is default (or ignored) and process is
* asleep, we are finished; the process should not
if ((prop
& SA_CONT
) && action
== SIG_DFL
) {
* When a sleeping process receives a stop
* signal, process immediately if possible.
* All other (caught or default) signals
* cause the process to run.
* If a child holding parent blocked,
* stopping could cause deadlock.
if ((p
->p_pptr
->p_flag
& SNOCLDSTOP
) == 0)
psignal(p
->p_pptr
, SIGCHLD
);
* If traced process is already stopped,
* then no further action is necessary.
* Kill signal always sets processes running.
* If SIGCONT is default (or ignored), we continue
* the process but don't leave the signal in p_sig,
* as it has no further action. If SIGCONT is held,
* continue the process and leave the signal in p_sig.
* If the process catches SIGCONT, let it handle
* the signal itself. If it isn't waiting on
* an event, then it goes back to run state.
* Otherwise, process goes back to sleep state.
* Already stopped, don't need to stop again.
* (If we did the shell could get confused.)
p
->p_sig
&= ~mask
; /* take it away */
* If process is sleeping interruptibly, then
* simulate a wakeup so that when it is continued,
* it will be made runnable and can look at the signal.
* But don't setrun the process, leave it stopped.
if (p
->p_wchan
&& p
->p_flag
& SSINTR
)
* SRUN, SIDL, SZOMB do nothing with the signal,
* other than kicking ourselves if we are running.
* It will either never be noticed, or noticed very soon.
* Raise priority to at least PUSER.
* If the current process has a signal to process (should be caught
* or cause termination, should interrupt current syscall),
* return the signal number. Stop signals with default action
* are processed immediately, then cleared; they aren't returned.
* This is checked after each entry to the system for a syscall
* or trap (though this can usually be done without actually calling
* issig by checking the pending signal masks in the CURSIG macro.)
* The normal call sequence is
* while (sig = CURSIG(curproc))
register int sig
, mask
, prop
;
mask
= p
->p_sig
&~ p
->p_sigmask
;
if (mask
== 0) /* no signal to send */
* We should see pending but ignored signals
* only if STRC was on when they were posted.
if (mask
& p
->p_sigignore
&& (p
->p_flag
& STRC
) == 0) {
if (p
->p_flag
& STRC
&& (p
->p_flag
& SPPWAIT
) == 0) {
* If traced, always stop, and stay
* stopped until released by the parent.
psignal(p
->p_pptr
, SIGCHLD
);
} while (!procxmt(p
) && p
->p_flag
& STRC
);
* If the traced bit got turned off,
* go back up to the top to rescan signals.
* This ensures that p_sig* and ps_sigact
if ((p
->p_flag
& STRC
) == 0)
* If parent wants us to take the signal,
* then it will leave it in p->p_xstat;
* otherwise we just look for signals again.
p
->p_sig
&= ~mask
; /* clear the old signal */
* Put the new signal into p_sig.
* If signal is being masked,
* look for other signals.
* Decide whether the signal should be returned.
* Return the signal's number, or fall through
* to clear it from the pending mask.
switch ((int)p
->p_sigacts
->ps_sigact
[sig
]) {
* Don't take default actions on system processes.
* Are you sure you want to ignore SIGSEGV
printf("Process (pid %d) got signal %d\n",
* If there is a pending stop signal to process
* with default action, stop here,
* then clear the signal. However,
* if process is member of an orphaned
* process group, ignore tty stop signals.
(p
->p_pgrp
->pg_jobc
== 0 &&
if ((p
->p_pptr
->p_flag
& SNOCLDSTOP
) == 0)
psignal(p
->p_pptr
, SIGCHLD
);
} else if (prop
& SA_IGNORE
) {
* Except for SIGCONT, shouldn't get here.
* Default action is to ignore; drop it.
* Masking above should prevent us ever trying
* to take action on an ignored signal other
* than SIGCONT, unless process is traced.
if ((prop
& SA_CONT
) == 0 && (p
->p_flag
& STRC
) == 0)
* This signal has an action, let
p
->p_sig
&= ~mask
; /* take the signal! */
* Put the argument process into the stopped
* state and notify the parent via wakeup.
* Signals are handled elsewhere.
* The process must not be on the run queue.
wakeup((caddr_t
)p
->p_pptr
);
* Take the action for the specified signal
* from the current set of pending signals.
register struct proc
*p
= curproc
;
register struct sigacts
*ps
= p
->p_sigacts
;
action
= ps
->ps_sigact
[sig
];
if (KTRPOINT(p
, KTR_PSIG
))
ktrpsig(p
->p_tracep
, sig
, action
, ps
->ps_flags
& SAS_OLDMASK
?
ps
->ps_oldmask
: p
->p_sigmask
, 0);
* Default action, where the default is to kill
* the process. (Other cases were ignored above.)
* If we get here, the signal must be caught.
if (action
== SIG_IGN
|| (p
->p_sigmask
& mask
))
* Set the new mask value and also defer further
* occurences of this signal.
* Special case: user has done a sigpause. Here the
* current mask is not of interest, but rather the
* mask from before the sigpause is what we want
* restored after the signal processing is completed.
if (ps
->ps_flags
& SAS_OLDMASK
) {
returnmask
= ps
->ps_oldmask
;
ps
->ps_flags
&= ~SAS_OLDMASK
;
returnmask
= p
->p_sigmask
;
p
->p_sigmask
|= ps
->ps_catchmask
[sig
] | mask
;
p
->p_stats
->p_ru
.ru_nsignals
++;
sendsig(action
, sig
, returnmask
, 0);
* Kill the current process for stated reason.
log(LOG_ERR
, "pid %d was killed: %s\n", p
->p_pid
, why
);
uprintf("sorry, pid %d was killed: %s\n", p
->p_pid
, why
);
* Force the current process to exit with the specified
* signal, dumping core if appropriate. We bypass the normal
* tests for masked and caught signals, allowing unrecoverable
* failures to terminate the process without changing signal state.
* Mark the accounting record with the signal termination.
* If dumping core, save the signal number for the debugger.
* Calls exit and does not return.
if (sigprop
[sig
] & SA_CORE
) {
p
->p_sigacts
->ps_sig
= sig
;
exit1(p
, W_EXITCODE(0, sig
));
* The file name is "core.progname".
* Core dumps are not created if the process is setuid.
register struct vnode
*vp
;
register struct pcred
*pcred
= p
->p_cred
;
register struct ucred
*cred
= pcred
->pc_ucred
;
register struct vmspace
*vm
= p
->p_vmspace
;
char name
[MAXCOMLEN
+6]; /* core.progname */
if (pcred
->p_svuid
!= pcred
->p_ruid
||
pcred
->p_svgid
!= pcred
->p_rgid
)
if (ctob(UPAGES
+ vm
->vm_dsize
+ vm
->vm_ssize
) >=
p
->p_rlimit
[RLIMIT_CORE
].rlim_cur
)
sprintf(name
, "core.%s", p
->p_comm
);
NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, name
, p
);
if (error
= vn_open(&nd
, O_CREAT
|FWRITE
, 0644))
if (vp
->v_type
!= VREG
|| VOP_GETATTR(vp
, &vattr
, cred
, p
) ||
LEASE_CHECK(vp
, p
, cred
, LEASE_WRITE
);
VOP_SETATTR(vp
, &vattr
, cred
, p
);
bcopy(p
, &p
->p_addr
->u_kproc
.kp_proc
, sizeof(struct proc
));
fill_eproc(p
, &p
->p_addr
->u_kproc
.kp_eproc
);
error
= cpu_coredump(p
, vp
, cred
);
error
= vn_rdwr(UIO_WRITE
, vp
, vm
->vm_daddr
,
(int)ctob(vm
->vm_dsize
), (off_t
)ctob(UPAGES
), UIO_USERSPACE
,
IO_NODELOCKED
|IO_UNIT
, cred
, (int *) NULL
, p
);
error
= vn_rdwr(UIO_WRITE
, vp
,
(caddr_t
) trunc_page(USRSTACK
- ctob(vm
->vm_ssize
)),
round_page(ctob(vm
->vm_ssize
)),
(off_t
)ctob(UPAGES
) + ctob(vm
->vm_dsize
), UIO_USERSPACE
,
IO_NODELOCKED
|IO_UNIT
, cred
, (int *) NULL
, p
);
error1
= vn_close(vp
, FWRITE
, cred
, p
);
* Nonexistent system call-- signal process (may want to handle it).
* Flag error in case process won't see signal immediately (blocked or ignored).