Re: [PATCH 0/1] *** Fix kill(-1,s) returning 0 on 0 kills ***
From: Petr Skocik
Date: Tue Nov 22 2022 - 18:02:24 EST
On 11/22/22 18:15, Kees Cook wrote:
On Tue, Nov 22, 2022 at 05:12:40PM +0100, Petr Skocik wrote:
Hi. I've never sent a kernel patch before but this one seemed trivial,
so I thought I'd give it a shot.
My issue: kill(-1,s) on Linux doesn't return -ESCHR when it has nothing
to kill.
It looks like LTP already tests for this, and gets -ESRCH?
https://github.com/linux-test-project/ltp/blob/master/testcases/kernel/containers/pidns/pidns10.c
Does it still pass with your change?
I went ahead and ran it and it does pass with the change.
But it should be obvious from the code alone too. It's only a few
(and fewer after the patch) simple lines of code.
The original:
int retval = 0, count = 0;
struct task_struct * p;
for_each_process(p) {
if (task_pid_vnr(p) > 1 &&
!same_thread_group(p, current)) {
int err = group_send_sig_info(sig, info, p,
PIDTYPE_MAX);
++count;
if (err != -EPERM)
retval = err;
}
}
ret = count ? retval : -ESRCH;
counts kills made after the `task_pid_vnr(p) > 1 &&
!same_thread_group(p, current)` check.
Some, and possibly all, of those kills fail with -EPERM, but the the
final line only sets -ESRCH
if the count is zero (i.e., the initial check fails). It should be
counting only kill attempts that
have _not_ returned -EPERM (if all returned -EPERM, then no suitable
target was found and
a -ESRCH is would be in order -- but it won't be set with the original
code!).
So the change can be as minor as
diff --git a/kernel/signal.c b/kernel/signal.c
index d140672185a4..e42076e2332b 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1608,9 +1608,10 @@ static int kill_something_info(int sig,
struct kernel_siginfo *info, pid_t pid)
!same_thread_group(p, current)) {
int err = group_send_sig_info(sig, info, p,
PIDTYPE_MAX);
- ++count;
- if (err != -EPERM)
+ if (err != -EPERM){
+ ++count;
retval = err;
+ }
}
}
ret = count ? retval : -ESRCH;
But since the count variable isn't used other than for the zeroness
check, I simplified it further
into
- int retval = 0, count = 0;
struct task_struct * p;
+ ret = -ESRCH;
for_each_process(p) {
if (task_pid_vnr(p) > 1 &&
!same_thread_group(p, current)) {
int err = group_send_sig_info(sig, info, p,
PIDTYPE_MAX);
- ++count;
if (err != -EPERM)
- retval = err;
+ ret = err; /*either all 0 or all -EINVAL*/
}
}
- ret = count ? retval : -ESRCH;
adding a comment explaining the apparent implicit assumption of the
original code that
the non-EPERM returns from group_send_sig_info in this context must be
either all -EINVAL
(bad signal number) or all 0, i.e., there can't be a signal allocation
failure
(that would be susceptible to being overshadowed by a 0 returned from a
later kill)
because none of those kills in this context (kill not sigqueue) should
require any memory allocation.
It's a tiny patch.
Cheers,
Petr Skocik
P.S.: Apologies if the code formatting is off. Sent this one with
Thunderbird. Need to work on my
CLI mailsending skills.