lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 9 Aug 2023 14:27:27 +0200
From:   Petr Skocik <pskocik@...il.com>
To:     Kees Cook <keescook@...omium.org>
Cc:     "Eric W. Biederman" <ebiederm@...ssion.com>,
        Oleg Nesterov <oleg@...hat.com>,
        Thomas Gleixner <tglx@...utronix.de>,
        Peter Zijlstra <peterz@...radead.org>,
        Marco Elver <elver@...gle.com>, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 0/1] *** Fix kill(-1,s) returning 0 on 0 kills ***

Hi.

Is there anything else I can do to help get this (or some other 
equivalent change that results in kill(-1,s) returning -ESRCH when it 
has nothing to kill (like it does on the BSDs),
as opposed to the current return value of 0 in that case) incorporated 
into mainline Linux?

It would rather help some of the user software I'm developing, and the 
slightly new semantics are IMO definitely reasonable (BSDs have them).

Basically, the current code:
         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 kill attempts at non-1, other-process pids  and sets hardcoded 
-ESRCH only if no such attempts are made, which will almost never happen

for a nonroot EUID, because there will typically be non-pid-1 processes 
unkillable by the nonroot EUID, but the code will still count those kill 
attempts, and thus not return the hardcoded -ESRCH even if ALL of those 
kill attemtpts return -EPERM, in which case -ESRCH would be in order 
too, because there were no processes that the current EUID had 
permission to kill (BDSs indeed return ESRCH in such a case).

(The kernel shouldn't need to concern itself with possible racy creation 
of new EUID-killable processes during the kill(-1,s) walk. Either the 
system can be known not to have running superuser code that could racily 
create such EUID-killable processes and then such a kill-returned -ESRCH 
would be useful, or it cannot be known not to have such running 
superuser code, in which case the -ESRCH is transient and should be 
droped by the user).

The current code also implicitly assumes either all non-EPERM kill 
attempts return -EINVAL (invalid signal) or they
all return 0 (success). This assumption should be valid because either 
the signal number is invalid and stays invalid, or it is valid and
the only possible error is -EPERM (this isn't sigqueue so the kill 
shouldn't ever fail with -ENOMEM). If the assumption were not valid,
then the current code could overshadow a previous failed attempt with a 
later succesful one, returning success even if there were some non-EPERM 
failures.

My change proposes:

         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);
                 if (err != -EPERM)
                     ret = err; /*either all 0 or all -EINVAL*/
             }
         }

i.e., start with -ESRCH (nothing to kill) and any non-EPERM kill 
attempts change it to the last return value
--either all 0 or all -EINVAL as per the implicit assumption of the 
original code.

It passes the tests put forth by Kees Cook.

More defensively, the implicit assumption of the original code could be 
made explicit:


         struct task_struct * p;
         int has_last_err = 0;

         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);
                 if (err != -EPERM){
                     if (has_last_err)
                         BUG_ON(ret != err); /*either all 0 or all -EINVAL*/
                     has_last_err = 1;
                     ret = err;
                 }
             }
         }

or dropped;

         struct task_struct * p;
         int has_last_err = 0;

         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);
                 if (err != -EPERM){
                     if (has_last_err){
                         if (err >= 0)
                             continue; /*don't mask previous failure 
with later success*/
                     }
                     has_last_err = 1;
                     ret = err;
                 }
             }
         }

Thanks again for consideration. Criticism welcome.

Regards,
Petr Skocik


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?
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ