2

Say I'm running some script that just sleeps, and another user with admin rights tries to kill my script using pkill. How can I catch which user sent that signal to my process, if such a thing is possible?

I know that something like kill -9 <my_script> won't allow me to catch anything, as we can't catch or do anything with SIGKILL.

  • Do you have admin (root) access to the machine? Is the machine running linux? – icarus Dec 18 '18 at 16:52
  • Root access? No. Running linux? Yes. – blacksite Dec 18 '18 at 17:32
  • OK, then my solution monitoring the system calls with ftrace will not work. – icarus Dec 18 '18 at 18:12
3

Yes, this is possible, albeit perhaps not from a script. For this to work, you need to set your signal handler up using sigaction with the SA_SIGINFO flag, and provide a handler with a signature identical to

void handler(int sig, siginfo_t *info, void *ucontext)

When it is invoked to handle a signal, the siginfo_t pointer it receives as its second argument will contain, among other pieces of information, the process identifier of the sending process (info->si_pid), and the read user identifier of the sending process (info->si_uid). These are filled in for signals sent using kill or sigqueue.

Implementing this in Python would require a fair amount of work, since the signal module doesn’t provide a way of accessing the siginfo_t structure.

  • Hmmm. I see how this could get tricky for a shell script with many processes created therein... So I'd have to add this logic to each process, basically? How could I do this handler logic in just the "runner" shell script itself? I'm fairly sure I could figure out how to handle this in Python (all of my processes in this shell script are from Python), but want to catch anyone trying to kill my topmost shell script. – blacksite Dec 18 '18 at 16:35
  • Ah yes, I got a bit carried away and forgot this was for a script. I imagine this is possible from Python, but I don’t think it is from a shell script. – Stephen Kitt Dec 18 '18 at 16:38
2

bash + ctypes.sh

Just for fun, using @StephenKitt 's solution, here's an example in bash, using the bash plugin ctypes.sh (which must be be compiled and installed in /usr/local for this example).

Sadly, both structures sigaction and siginfo_t are too complex for ctypes.sh's builtin struct command to work. Those structures have thus to be manually defined. This is a quite annoying chore, and it's non-portable (both for OS and for architecture). This example assumes Linux >= 4.6 (because of info->si_pkey) on x86_64 architecture.

#!/bin/bash

. /usr/local/bin/ctypes.sh || exit 2

handler () {
    local -a info=(int int int int uint32 uint32 int int64 int64 int64 int pointer int int pointer long int short pointer pointer int pointer int unsigned)
    unpack $3 info

    echo ''
    echo "handler($2, info={${info[@]}}, $4);"
    echo -- handling signal $2 --
    echo "info->si_pid=${info[4]}"
    echo "info->si_uid=${info[5]}"
    return
}
callback -n handler handler void int pointer pointer

SIGUSR2=12
SA_SIGINFO=4

act=(
    $handler
    long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0
    int:$SA_SIGINFO
    pointer:0
)
sizeof_act=$(( 8 + 16 * 8 + 4 + 8 ))

dlcall -n pact -r pointer malloc $sizeof_act
[ $pact != pointer:0 ] || exit 1
pack $pact act

dlcall -n ret -r int sigaction int:$SIGUSR2 $pact pointer:0
[ $ret = int:0 ] || exit 1

echo "sigaction(SIGUSR2, act={${act[@]}}, NULL) = $ret"

echo ''
echo run this: kill -$SIGUSR2 $$
sleep 99

Execution:

term1:

$ ./siginfo.bash 
sigaction(SIGUSR2, act={pointer:0x7ff26f0d3010 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 long:0 int:4 pointer:0}, NULL) = int:0

run this: kill -12 24250

term2:

$ echo $$
21864
$ id -u
1000
$ kill -12 24250
$ 

result in term1:

handler(int:12, info={int:12 int:0 int:0 int:0 uint32:21864 uint32:1000 int:0 int64:0 int64:0 int64:0 int:0 pointer:0 int:0 int:0 pointer:0 long:0 int:0 short:0 pointer:0 pointer:0 int:0 pointer:0 int:0 unsigned:0}, pointer:0x7fff4583a500);
-- handling signal int:12 --
info->si_pid=uint32:21864
info->si_uid=uint32:1000

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.