diff options
author | kib <kib@FreeBSD.org> | 2009-11-17 11:39:15 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-11-17 11:39:15 +0000 |
commit | 2d08f816e13d4eca3a96eb24f578541791a335e7 (patch) | |
tree | c59c7fddba5c77496f61d018fe1c5c004cf33224 /sys | |
parent | 45887d4e283c9ac9f5830e01dd3a82881571fded (diff) | |
download | FreeBSD-src-2d08f816e13d4eca3a96eb24f578541791a335e7.zip FreeBSD-src-2d08f816e13d4eca3a96eb24f578541791a335e7.tar.gz |
Among signal generation syscalls, only sigqueue(2) is allowed by POSIX
to fail due to lack of resources to queue siginfo. Add KSI_SIGQ flag
that allows sigqueue_add() to fail while trying to allocate memory for
new siginfo. When the flag is not set, behaviour is the same as for
KSI_TRAP: if memory cannot be allocated, set bit in sq_kill. KSI_TRAP is
kept to preserve KBI.
Add SI_KERNEL si_code, to be used in siginfo.si_code when signal is
generated by kernel. Deliver siginfo when signal is generated by kill(2)
family of syscalls (SI_USER with properly filled si_uid and si_pid), or
by kernel (SI_KERNEL, mostly job control or SIGIO). Since KSI_SIGQ flag
is not set for the ksi, low memory condition cause old behaviour.
Keep psignal(9) KBI intact, but modify it to generate SI_KERNEL
si_code. Pgsignal(9) and gsignal(9) now take ksi explicitely. Add
pksignal(9) that behaves like psignal but takes ksi, and ddb kill
command implemented as pksignal(..., ksi = NULL) to not do allocation
while in debugger.
While there, remove some register specifiers and use ANSI C prototypes.
Reviewed by: davidxu
MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ddb/db_command.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 82 | ||||
-rw-r--r-- | sys/kern/tty.c | 16 | ||||
-rw-r--r-- | sys/sys/signal.h | 1 | ||||
-rw-r--r-- | sys/sys/signalvar.h | 8 |
5 files changed, 74 insertions, 35 deletions
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index 1e34016..73de0c5 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -652,7 +652,7 @@ db_kill(dummy1, dummy2, dummy3, dummy4) if (PROC_TRYLOCK(p) == 0) DB_ERROR(("Can't lock process with pid %ld\n", (long) pid)); else { - psignal(p, sig); + pksignal(p, sig, NULL); PROC_UNLOCK(p); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 412e00d..2973725 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -99,7 +99,8 @@ SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 2, "int"); static int coredump(struct thread *); static char *expand_name(const char *, uid_t, pid_t); -static int killpg1(struct thread *td, int sig, int pgid, int all); +static int killpg1(struct thread *td, int sig, int pgid, int all, + ksiginfo_t *ksi); static int issignal(struct thread *td, int stop_allowed); static int sigprop(int sig); static void tdsigwakeup(struct thread *, int, sig_t, int); @@ -381,7 +382,8 @@ sigqueue_add(sigqueue_t *sq, int signo, ksiginfo_t *si) ksi->ksi_sigq = sq; } - if ((si->ksi_flags & KSI_TRAP) != 0) { + if ((si->ksi_flags & KSI_TRAP) != 0 || + (si->ksi_flags & KSI_SIGQ) == 0) { if (ret != 0) SIGADDSET(sq->sq_kill, signo); ret = 0; @@ -1611,11 +1613,9 @@ kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss) * cp is calling process. */ static int -killpg1(td, sig, pgid, all) - register struct thread *td; - int sig, pgid, all; +killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi) { - register struct proc *p; + struct proc *p; struct pgrp *pgrp; int nfound = 0; @@ -1634,7 +1634,7 @@ killpg1(td, sig, pgid, all) if (p_cansignal(td, p, sig) == 0) { nfound++; if (sig) - psignal(p, sig); + pksignal(p, sig, ksi); } PROC_UNLOCK(p); } @@ -1665,7 +1665,7 @@ killpg1(td, sig, pgid, all) if (p_cansignal(td, p, sig) == 0) { nfound++; if (sig) - psignal(p, sig); + pksignal(p, sig, ksi); } PROC_UNLOCK(p); } @@ -1682,11 +1682,10 @@ struct kill_args { #endif /* ARGSUSED */ int -kill(td, uap) - register struct thread *td; - register struct kill_args *uap; +kill(struct thread *td, struct kill_args *uap) { - register struct proc *p; + ksiginfo_t ksi; + struct proc *p; int error; AUDIT_ARG_SIGNUM(uap->signum); @@ -1694,6 +1693,12 @@ kill(td, uap) if ((u_int)uap->signum > _SIG_MAXSIG) return (EINVAL); + ksiginfo_init(&ksi); + ksi.ksi_signo = uap->signum; + ksi.ksi_code = SI_USER; + ksi.ksi_pid = td->td_proc->p_pid; + ksi.ksi_uid = td->td_ucred->cr_ruid; + if (uap->pid > 0) { /* kill single process */ if ((p = pfind(uap->pid)) == NULL) { @@ -1703,17 +1708,17 @@ kill(td, uap) AUDIT_ARG_PROCESS(p); error = p_cansignal(td, p, uap->signum); if (error == 0 && uap->signum) - psignal(p, uap->signum); + pksignal(p, uap->signum, &ksi); PROC_UNLOCK(p); return (error); } switch (uap->pid) { case -1: /* broadcast signal */ - return (killpg1(td, uap->signum, 0, 1)); + return (killpg1(td, uap->signum, 0, 1, &ksi)); case 0: /* signal own process group */ - return (killpg1(td, uap->signum, 0, 0)); + return (killpg1(td, uap->signum, 0, 0, &ksi)); default: /* negative explicit process group */ - return (killpg1(td, uap->signum, -uap->pid, 0)); + return (killpg1(td, uap->signum, -uap->pid, 0, &ksi)); } /* NOTREACHED */ } @@ -1727,17 +1732,21 @@ struct okillpg_args { #endif /* ARGSUSED */ int -okillpg(td, uap) - struct thread *td; - register struct okillpg_args *uap; +okillpg(struct thread *td, struct okillpg_args *uap) { + ksiginfo_t ksi; AUDIT_ARG_SIGNUM(uap->signum); AUDIT_ARG_PID(uap->pgid); if ((u_int)uap->signum > _SIG_MAXSIG) return (EINVAL); - return (killpg1(td, uap->signum, uap->pgid, 0)); + ksiginfo_init(&ksi); + ksi.ksi_signo = uap->signum; + ksi.ksi_code = SI_USER; + ksi.ksi_pid = td->td_proc->p_pid; + ksi.ksi_uid = td->td_ucred->cr_ruid; + return (killpg1(td, uap->signum, uap->pgid, 0, &ksi)); } #endif /* COMPAT_43 */ @@ -1772,6 +1781,7 @@ sigqueue(struct thread *td, struct sigqueue_args *uap) error = p_cansignal(td, p, uap->signum); if (error == 0 && uap->signum != 0) { ksiginfo_init(&ksi); + ksi.ksi_flags = KSI_SIGQ; ksi.ksi_signo = uap->signum; ksi.ksi_code = SI_QUEUE; ksi.ksi_pid = td->td_proc->p_pid; @@ -1787,8 +1797,7 @@ sigqueue(struct thread *td, struct sigqueue_args *uap) * Send a signal to a process group. */ void -gsignal(pgid, sig) - int pgid, sig; +gsignal(int pgid, int sig, ksiginfo_t *ksi) { struct pgrp *pgrp; @@ -1797,7 +1806,7 @@ gsignal(pgid, sig) pgrp = pgfind(pgid); sx_sunlock(&proctree_lock); if (pgrp != NULL) { - pgsignal(pgrp, sig, 0); + pgsignal(pgrp, sig, 0, ksi); PGRP_UNLOCK(pgrp); } } @@ -1808,18 +1817,16 @@ gsignal(pgid, sig) * limit to members which have a controlling terminal. */ void -pgsignal(pgrp, sig, checkctty) - struct pgrp *pgrp; - int sig, checkctty; +pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi) { - register struct proc *p; + struct proc *p; if (pgrp) { PGRP_LOCK_ASSERT(pgrp, MA_OWNED); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (checkctty == 0 || p->p_flag & P_CONTROLT) - psignal(p, sig); + pksignal(p, sig, ksi); PROC_UNLOCK(p); } } @@ -1940,7 +1947,19 @@ sigtd(struct proc *p, int sig, int prop) void psignal(struct proc *p, int sig) { - (void) tdsignal(p, NULL, sig, NULL); + ksiginfo_t ksi; + + ksiginfo_init(&ksi); + ksi.ksi_signo = sig; + ksi.ksi_code = SI_KERNEL; + (void) tdsignal(p, NULL, sig, &ksi); +} + +void +pksignal(struct proc *p, int sig, ksiginfo_t *ksi) +{ + + (void) tdsignal(p, NULL, sig, ksi); } int @@ -3143,8 +3162,13 @@ pgsigio(sigiop, sig, checkctty) struct sigio **sigiop; int sig, checkctty; { + ksiginfo_t ksi; struct sigio *sigio; + ksiginfo_init(&ksi); + ksi.ksi_signo = sig; + ksi.ksi_code = SI_KERNEL; + SIGIO_LOCK(); sigio = *sigiop; if (sigio == NULL) { diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 81f6741..7e6cf00 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -355,6 +355,7 @@ tty_wait_background(struct tty *tp, struct thread *td, int sig) { struct proc *p = td->td_proc; struct pgrp *pg; + ksiginfo_t ksi; int error; MPASS(sig == SIGTTIN || sig == SIGTTOU); @@ -396,8 +397,14 @@ tty_wait_background(struct tty *tp, struct thread *td, int sig) * Send the signal and sleep until we're the new * foreground process group. */ + if (sig != 0) { + ksiginfo_init(&ksi); + ksi.ksi_code = SI_KERNEL; + ksi.ksi_signo = sig; + sig = 0; + } PGRP_LOCK(pg); - pgsignal(pg, sig, 1); + pgsignal(pg, ksi.ksi_signo, 1, &ksi); PGRP_UNLOCK(pg); error = tty_wait(tp, &tp->t_bgwait); @@ -1240,6 +1247,8 @@ tty_signal_sessleader(struct tty *tp, int sig) void tty_signal_pgrp(struct tty *tp, int sig) { + ksiginfo_t ksi; + tty_lock_assert(tp, MA_OWNED); MPASS(sig >= 1 && sig < NSIG); @@ -1249,8 +1258,11 @@ tty_signal_pgrp(struct tty *tp, int sig) if (sig == SIGINFO && !(tp->t_termios.c_lflag & NOKERNINFO)) tty_info(tp); if (tp->t_pgrp != NULL) { + ksiginfo_init(&ksi); + ksi.ksi_signo = sig; + ksi.ksi_code = SI_KERNEL; PGRP_LOCK(tp->t_pgrp); - pgsignal(tp->t_pgrp, sig, 1); + pgsignal(tp->t_pgrp, sig, 1, &ksi); PGRP_UNLOCK(tp->t_pgrp); } } diff --git a/sys/sys/signal.h b/sys/sys/signal.h index e90b107..81d45a9 100644 --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -338,6 +338,7 @@ struct sigaction { /* an asynchronous I/O request.*/ #define SI_MESGQ 0x10005 /* Signal generated by arrival of a */ /* message on an empty message queue. */ +#define SI_KERNEL 0x10006 #endif #if __BSD_VISIBLE #define SI_UNDEFINED 0 diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 65d9cf5..fd0fac3 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -233,7 +233,8 @@ typedef struct ksiginfo { #define KSI_TRAP 0x01 /* Generated by trap. */ #define KSI_EXT 0x02 /* Externally managed ksi. */ #define KSI_INS 0x04 /* Directly insert ksi, not the copy */ -#define KSI_COPYMASK KSI_TRAP +#define KSI_SIGQ 0x08 /* Generated by sigqueue, might ret EGAIN. */ +#define KSI_COPYMASK (KSI_TRAP|KSI_SIGQ) #define KSI_ONQ(ksi) ((ksi)->ksi_sigq != NULL) @@ -326,10 +327,11 @@ extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */ */ int cursig(struct thread *td, int stop_allowed); void execsigs(struct proc *p); -void gsignal(int pgid, int sig); +void gsignal(int pgid, int sig, ksiginfo_t *ksi); void killproc(struct proc *p, char *why); +void pksignal(struct proc *p, int sig, ksiginfo_t *ksi); void pgsigio(struct sigio **, int signum, int checkctty); -void pgsignal(struct pgrp *pgrp, int sig, int checkctty); +void pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi); int postsig(int sig); void psignal(struct proc *p, int sig); int psignal_event(struct proc *p, struct sigevent *, ksiginfo_t *); |