summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sig.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-11-17 11:39:15 +0000
committerkib <kib@FreeBSD.org>2009-11-17 11:39:15 +0000
commit2d08f816e13d4eca3a96eb24f578541791a335e7 (patch)
treec59c7fddba5c77496f61d018fe1c5c004cf33224 /sys/kern/kern_sig.c
parent45887d4e283c9ac9f5830e01dd3a82881571fded (diff)
downloadFreeBSD-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/kern/kern_sig.c')
-rw-r--r--sys/kern/kern_sig.c82
1 files changed, 53 insertions, 29 deletions
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) {
OpenPOWER on IntegriCloud