diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2019-12-07 18:07:49 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2019-12-07 18:07:49 +0000 |
commit | 0cc9fb7551f53d52ec1e45c983f4646a1c1f089b (patch) | |
tree | 35a9643ae466940c0de0def1757fdaf0184cb507 /sys/kern/kern_sig.c | |
parent | 624e87b673064ae228b79cde11b82f1ad7502bc3 (diff) | |
download | src-0cc9fb7551f53d52ec1e45c983f4646a1c1f089b.tar.gz src-0cc9fb7551f53d52ec1e45c983f4646a1c1f089b.zip |
Only return EPERM from kill(-pid) when no process was signalled.
As mandated by POSIX. Also clarify the kill(2) manpage.
While there, restructure the code in killpg1() to use helper which
keeps overall state of the process list iteration in the killpg1_ctx
structued, later used to infer the error returned.
Reported by: amdmi3
Reviewed by: jilles
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Differential revision: https://reviews.freebsd.org/D22621
Notes
Notes:
svn path=/head/; revision=355500
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r-- | sys/kern/kern_sig.c | 78 |
1 files changed, 44 insertions, 34 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 1401b3e58180..dc97c0388d17 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1679,6 +1679,36 @@ kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss) return (0); } +struct killpg1_ctx { + struct thread *td; + ksiginfo_t *ksi; + int sig; + bool sent; + bool found; + int ret; +}; + +static void +killpg1_sendsig(struct proc *p, bool notself, struct killpg1_ctx *arg) +{ + int err; + + if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || + (notself && p == arg->td->td_proc) || p->p_state == PRS_NEW) + return; + PROC_LOCK(p); + err = p_cansignal(arg->td, p, arg->sig); + if (err == 0 && arg->sig != 0) + pksignal(p, arg->sig, arg->ksi); + PROC_UNLOCK(p); + if (err != ESRCH) + arg->found = true; + if (err == 0) + arg->sent = true; + else if (arg->ret == 0 && err != ESRCH && err != EPERM) + arg->ret = err; +} + /* * Common code for kill process group/broadcast kill. * cp is calling process. @@ -1688,30 +1718,21 @@ killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi) { struct proc *p; struct pgrp *pgrp; - int err; - int ret; - - ret = ESRCH; + struct killpg1_ctx arg; + + arg.td = td; + arg.ksi = ksi; + arg.sig = sig; + arg.sent = false; + arg.found = false; + arg.ret = 0; if (all) { /* * broadcast */ sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { - if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || - p == td->td_proc || p->p_state == PRS_NEW) { - continue; - } - PROC_LOCK(p); - err = p_cansignal(td, p, sig); - if (err == 0) { - if (sig) - pksignal(p, sig, ksi); - ret = err; - } - else if (ret == ESRCH) - ret = err; - PROC_UNLOCK(p); + killpg1_sendsig(p, true, &arg); } sx_sunlock(&allproc_lock); } else { @@ -1731,25 +1752,14 @@ killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi) } sx_sunlock(&proctree_lock); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { - PROC_LOCK(p); - if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || - p->p_state == PRS_NEW) { - PROC_UNLOCK(p); - continue; - } - err = p_cansignal(td, p, sig); - if (err == 0) { - if (sig) - pksignal(p, sig, ksi); - ret = err; - } - else if (ret == ESRCH) - ret = err; - PROC_UNLOCK(p); + killpg1_sendsig(p, false, &arg); } PGRP_UNLOCK(pgrp); } - return (ret); + MPASS(arg.ret != 0 || arg.found || !arg.sent); + if (arg.ret == 0 && !arg.sent) + arg.ret = arg.found ? EPERM : ESRCH; + return (arg.ret); } #ifndef _SYS_SYSPROTO_H_ |