Home

Awesome

kunkillable

kunkillable is an LKM (loadable kernel module) that makes userland processes unkillable.

TL;DR

kunkillable adds the flag SIGNAL_UNKILLABLE to the signal flags of task_struct hence making it unkillable.

When the module is unloaded, the flag is removed and the process becomes killable again.

How It Works

In order to understand the MO of the module, lets see first what happens when we send a user-mode signal to a process:

    -----------------
    | kill -9 25327 |
    -----------------
        |
        |   user runs kill command to send a signal for a process, intiating a 
        |   call to sys_kill() system call
        |
    --------------
    | sys_kill() |
    --------------
        |
        |   sys_kill() is called, initiating a sequence of internal functions calls 
        |
    -------------------------     -------------------     -------------------------
    | kill_something_info() | --> | kill_pid_info() | --> | group_send_sig_info() | 
    -------------------------     -------------------     -------------------------
                                                                |
                                                                |
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
        |
    ----------------------        -----------------       -------------------
    | do_send_sig_info() | -----> | send_signal() |  ---> | __send_signal() |
    ----------------------        -----------------       -------------------
                                                                |
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
        |   
        |   evantually, __send_signal() is called.
        |   __send_signal is the last function in the chain whose responsible for 
        |   the actual send of the signal.
        |
    --------------------
    | prepare_signal() |
    --------------------
        |
        |   as part of the signal prepartion, prepare_signal() is called and in 
        |   turns calls two interesting function!
        |
    -----------------
    | sig_ignored() |
    -----------------
        |
        |
        |
    ----------------------
    | sig_task_ignored() |
    ----------------------

            sig_task_ignored() is the function responsible for checking if the 
            process should ignore the signal that we want to send, according to 
            its task_struct's flags.

Let's take a look at the function sig_task_ignored():

NOTE: you can find the rest of the screenshots under docs/ directory.

Alt text

SIGNAL_UNKILLABLE

As we can see in line 85, the kernel reads the task_struct's signal flags to find if SIGNAL_UNKILLABLE is defined. If so - ___true is returned, and the signal is being ignored - hence our process becomes unkillable.

All we need to do - is to find the task_struct of the process we want to turn unkillable, and add SIGNAL_UNKILLABLE flag to it.