Kill sends signal to wrong process group with job control enabled

Ben Ashton <[email protected]>
Newsgroups gmane.comp.shells.bash.bugs
Message-ID <[email protected]>
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=x86-64 -mtune=generic -O2 -pipe -fno-plt 
-fexceptions         -Wp,-D_FORTIFY_SOURCE=3 -Wformat 
-Werror=format-security         -fstack-clash-protection 
-fcf-protection         -fno-omit-frame-pointer 
-mno-omit-leaf-frame-pointer -g 
-ffile-prefix-map=/build/bash/src=/usr/src/debug/bash -flto=auto 
-DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/bin' 
-DSTANDARD_UTILS_PATH='/usr/bin' -DSYS_BASHRC='/etc/bash.bashrc' 
-DSYS_BASH_LOGOUT='/etc/bash.bash_logout' -DNON_INTERACTIVE_LOGIN_SHELLS 
-std=gnu17
uname output: Linux ben-laptop 6.18.9-arch1-2 #1 SMP PREEMPT_DYNAMIC 
Mon, 09 Feb 2026 17:16:33 +0000 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu

Bash Version: 5.3
Patch Level: 9
Release Status: release

Description:
     In the following script, we create a subshell that traps SIGINT and 
SIGTERM
     and then uses setsid to run sleep    in a separate process group. 
We then wait
     for sleep to finish (note setsid won't fork and immediately exit 
because job
     control isn't inherited by the subshell so it doesn't start out as 
a process
     group leader, instead it just calls setsid and execs sleep). We now 
have
     sleep running as a child of the subshell as a process group leader. 
However
     in certain, somewhat contrived, circumstances, bash's builtin kill 
will send
     the signal to the WRONG process group. See the following strace 
output when
     running the script below:

     > Sending SIGTERM to process group: 5710 (kill -TERM -5710)
     [pid  5709] kill(-5709, SIGTERM)        = 0

     As you can see we ran `kill -TERM -5710`, but bash actually sent it to
     process group 5709 (the subshell itself). If you don't use the 
builtin kill
     then it works as expected (note the syntax for killing process 
groups with
     kill binaries seems to vary a lot. It seems like with procps-ng 
kill you need
     to do    `/bin/kill -TERM -- -PGID` instead)

     I also tested the following script with Dash/BusyBox/Zsh and it worked
     correctly. However it misbehaves in every version of Bash that I tested
     (POSIX mode or otherwise).

Repeat-By:
     Here is the script to reproduce the issue:

     #!/usr/bin/env sh
     set -u

     # Only happens with job control enabled
     set -m

     (
       echo "> In subshell"
       trap 'echo "> SIGTERM received in subshell SHOULD NOT HAPPEN!"' TERM
       trap 'echo "> SIGINT received in subshell"' INT

       setsid sleep 10 &
       pid=$!
       echo "> Started new process group $pid"
       # Wait for for sleep, SIGINT from main process will interrupt this
       wait "$pid"
       echo "> Sending SIGTERM to process group: $pid (kill -TERM -$pid)"
       kill -TERM -$pid
       wait "$pid"
     ) &
     subshell_pid=$!
     echo "Subshell pid $subshell_pid"

     sleep 5
     echo "Sending SIGINT to subshell $subshell_pid"
     kill -INT "$subshell_pid"
     wait "$subshell_pid"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.