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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 11 Aug 2023 17:16:18 -0500
From:   "Eric W. Biederman" <ebiederm@...ssion.com>
To:     Petr Skocik <pskocik@...il.com>
Cc:     Kees Cook <keescook@...omium.org>, 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: [PATCH] signal: Fix the error return of kill -1


I dug through posix[1], the FreeBSD version of kill(2), and the Illumos
version of kill(2).  Common sense, the documentation and the other
implemnetations of kill(2) agree that an error should be returned if no
signal is delivered.

What is up in the air is which error code should be returned.  FreeBSD
uses ESRCH for all errors.  Illumos will return EPERM for some errors,
and ESRCH for others.  According to the rationale POSIX allows both.

The current Linux behavior of reporting success even when no signal
was delivered dates back to Linux 0.1 with the introduction of
returning ESRCH when there were no processes being added in Linux 1.0.

Since the current behavior is buggy and user-space cares[2][3] change
the behavior to match the behavior when Linux sends signals to process
groups.

Petr Skocik <pskocik@...il.com> wrote:
> The code sample below demonstrates the problem, which gets fixed by the
> patch:
>
>     #define _GNU_SOURCE
>     #include <assert.h>
>     #include <errno.h>
>     #include <signal.h>
>     #include <stdio.h>
>     #include <sys/wait.h>
>     #include <unistd.h>
>     #define VICTIM_UID 4200 //check these are safe to use on your system!
>     #define UNUSED_UID 4300
>     int main(){
>         uid_t r,e,s;
>         if(geteuid()) return 1; //requires root privileges
>
>         //pipe to let the parent know when the child has changed ids
>         int fds[2]; if(0>pipe(fds)) return 1;
>         pid_t pid;
>         if(0>(pid=fork())) return 1;
>         else if(0==pid){
>             setreuid(VICTIM_UID,VICTIM_UID);
>             getresuid(&r,&e,&s); printf("child: %u %u %u\n", r,e,s);
>             close(fds[0]); close(fds[1]); //let the parent continue
>             for(;;) pause();
>         }
>         close(fds[1]);
>         read(fds[0],&(char){0},1); //wait for uid change in the child
>
>         #if 1
>         setreuid(VICTIM_UID,(uid_t)-1); seteuid(VICTIM_UID);
>         #else
>         setresuid(UNUSED_UID,VICTIM_UID,0);
>         #endif
>         getresuid(&r,&e,&s); printf("parent: %u %u %u\n", r,e,s); //4200 4200 0
>
>         int err = kill(-1,-111); (void)err; //test -EINVAL
>         assert(err < 0 &&  errno == EINVAL);
>
>         int rc = kill(-1,SIGTERM); //test 0
>         if(rc>=0) wait(0);
>         int rc2 = kill(-1,SIGTERM); //test -ESCHR
>         printf("1st kill ok==%d; 2nd kill ESRCH==%d\n", rc==0, rc2<0&& errno==ESRCH);
>     }

[1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
[2] https://lkml.kernel.org/r/336ae9be-c66c-d87f-61fe-b916e9f04ffc@gmail.com
[3] https://lkml.kernel.org/r/20221122161240.137570-1-pskocik@gmail.com
Reported-by: Petr Skocik <pskocik@...il.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@...ssion.com>
---
 kernel/signal.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/kernel/signal.c b/kernel/signal.c
index b5370fe5c198..731c6e3b351d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1582,8 +1582,9 @@ EXPORT_SYMBOL_GPL(kill_pid_usb_asyncio);
 /*
  * kill_something_info() interprets pid in interesting ways just like kill(2).
  *
- * POSIX specifies that kill(-1,sig) is unspecified, but what we have
- * is probably wrong.  Should make it like BSD or SYSV.
+ * POSIX allows the error codes EPERM and ESRCH when kill(-1,sig) does
+ * not deliver a signal to any process.  For consistency use the same
+ * logic in kill_something_info and __kill_pgrp_info.
  */
 
 static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid)
@@ -1602,7 +1603,8 @@ static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid)
 		ret = __kill_pgrp_info(sig, info,
 				pid ? find_vpid(-pid) : task_pgrp(current));
 	} else {
-		int retval = 0, count = 0;
+		bool found = false, success = false;
+		int retval = 0;
 		struct task_struct * p;
 
 		for_each_process(p) {
@@ -1610,12 +1612,12 @@ 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)
-					retval = err;
+				found = true;
+				success |= !err;
+				retval = err;
 			}
 		}
-		ret = count ? retval : -ESRCH;
+		ret = success ? 0 : (found ? retval : -ESRCH);
 	}
 	read_unlock(&tasklist_lock);
 
-- 
2.35.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ