How to disable the 'kill' command on Linux

9,948

Solution 1

"Disabling" kill for root, even if it was possible, would most likely have unwanted side-effects, like system scripts malfunctioning, and in the worst (but likely) scenario it would prevent your computer from starting up properly (or even shutting down properly).

For a user, too, it would cause issues. I have, for example, scripts that I run as an unprivileged user, that checks to see if certain processes are running using kill -0 $pid. Those scripts would stop working.

For yourself, you could alias the kill command to something else, like echo "kill":

$ alias kill='echo "kill"'

That would prevent kill from doing anything useful on the command line at least:

$ kill -s HUP $$
kill -s HUP 11985

Solution 2

Use this kernel module to disable the kill system call on amd64.
Use at your own risk. Devastating side effects are expected.

#include <linux/module.h>

MODULE_LICENSE("GPL");

int __init init(void) __attribute__((noreturn))
{
     unsigned long long cr0 = read_cr0();
     write_cr0(cr0 & ~(1 << 16));  /* Clear Write Protection (WP) bit */
     *(unsigned char *)sys_kill = 0xc3;  /* opcode for "ret" */
     write_cr0(cr0);

     /* This makes sure that delete_module below won't complain */
     __this_module.refcnt = 1;
     __this_module.state = MODULE_STATE_LIVE;

     asm volatile
     (
          "mov %0, %%rsp\n\t" /* It seems GCC refuses to mess with the stack pointer */
          "jmp sys_delete_module\n\t"  /* call delete_module(name, flags) */
          :: "r"(current->stack + THREAD_SIZE - sizeof(struct pt_regs) - 8), "D"(__this_module.name), "S"(0) :
     );
}

void __exit exit(void)
{
    return;
}

Compile it like you would any other module. Then use insmod on it.

Solution 3

You should not disable it system-wide, because it's used in system scripts (e.g., in /etc/init.d/functions in the initscripts package).

You can disable it for the login shell (and its subshells) by alias'ing it to, say, true/false (or something like kill_disabled if you wish to get an error rather than a no-op).

Note that this way is not fool-proof: it will only affect commands executed directly (not those inside scripts). And the user will be able to remove the alias with unalias.


To do this, run the following command

alias kill=kill_disabled

or add it to an appropriate bash startup file to run it at every login.

Now, running kill interactively will produce:

$ kill 9999
-bash: kill_disabled: command not found

As I said, the above way is easily subverted. If you need a fool-proof way, the only solution is to run the entire login shell session in a chroot environment. It will still only disable the stock command, not a direct syscall, however done. The latter cannot be disabled, because it's essential for normal operation (e.g., every Ctrl + C sends SIGINT, pipes require SIGPIPE, and background processes are controlled with more than five different signals). Setting up a chroot environment is an advanced task and it's generally inconvenient if the user needs to access the entire filesystem.

Solution 4

If you want the users to be able to use kill normally except for when they try to kill your specific program, you can define a kill function in the .bashrc of the user profile and within this function, check if the user is trying to kill your program. If not, you can call the kill utility from within your function itself.

As an example, I wrote a small kill function which will not kill the sleep utility but will function as a normal kill utility for any other parameter provided to it.

function kill() {
    process=$(ps -p "${@: -1}" | awk 'END{print $(NF)}');
    if [[ $process == "sleep"]]
    then
        echo "Killing $process is not allowed"
    else
        /bin/kill $@
    fi
}
Share:
9,948

Related videos on Youtube

xxlali
Author by

xxlali

I am a Software Engineer. I generally use Java for back-end and Javascript (AngularJS) for front-end. I am responsible for an inside framework's development, improvement and bug fixes.

Updated on September 18, 2022

Comments

  • xxlali
    xxlali almost 2 years

    I want to disable all kill commands (including root user). I have tried to change permissions, but it still can be executed. Is there a way to do that?

    • Digital Chris
      Digital Chris about 8 years
      I hate that @xxlali refuses to tell us why this is needed.
    • Siyuan Ren
      Siyuan Ren about 8 years
      Except for the kernel module that disables the syscall, the user can always write his/her own kill executable by calling the c function kill.
    • Conspicuous Compiler
      Conspicuous Compiler about 8 years
      Could you explain why you want to disable kill on your system? Do you have processes being terminated by people with root privileges which you don't want being terminated?
    • Lenne
      Lenne about 8 years
      Which kill? You can send different signals with kill: 1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS 8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM 15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN 22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH 29 POLL 30 PWR 31 SYS
    • miroxlav
      miroxlav about 8 years
      9 upvotes and 9 downvotes... this deserves a special badge.
    • xxlali
      xxlali about 8 years
      @DigitalChris I have a program. There is another way to stop this program, but some users prefer the stop this program using 'kill -9 %pid%' which causes unwanted results. So, I want to force users to use normal way stop. This is why I want to disable kill command usage. (Please don't hate me :) )
    • ivan_pozdeev
      ivan_pozdeev over 7 years
      @xxlali you can e.g. deny solving a problem for a user if you find it has been caused by force killing. A better way is to find out and solve the root UX problem causing them to do this. Maybe the way you provided to stop your program is too inconvenient or nonstandard. Or the program is prone to hanging or something (e.g. if it's GUI and shutdown is slow, you can remove its window so it doesn't nag the user during the process).
    • forresthopkinsa
      forresthopkinsa over 6 years
      Sounds to me like xxlali is trying to write malware
    • joaquin
      joaquin almost 6 years
      If you run a process, only people with the same UID, or with elevated privileges (think root) can send signals to your process — see POSIX kill(). So, if people using the machine where you run the code make the effort to login as root to kill your program, maybe your program isn't behaving well (it is consuming too many of the shared resources on the system). It's also probable that there are too many people with root privilege on the machine. Should you make 'another way to stop the program' better known?
    • Nullpointer
      Nullpointer about 5 years
      Can we kill root progress, if root user is disabled
  • xxlali
    xxlali about 8 years
    Well, how can I do that. I am not an advanced linux user.
  • ivan_pozdeev
    ivan_pozdeev about 8 years
    @xxlali see the update
  • Peter Cordes
    Peter Cordes about 8 years
    Disabling kill only for interactive use is the only sane answer, so +1. If you do want to use it from an interactive shell with this alias, just run /bin/kill ..., or builtin kill ... or command kill to suppress function/alias lookup. Bash has keywords to override the default command lookup. The normal use-case is in wrapper functions, e.g. cd(){ command cd "$@"; pwd > /tmp/here.$$; }
  • Andrew Henle
    Andrew Henle about 8 years
    @PeterCordes \kill will bypass the alias too.
  • Kamil Maciorowski
    Kamil Maciorowski about 8 years
    It's amazing how you can count on people to hand you multiple guns to shoot yourself in the foot if you ask for it. Including kernel module. :D
  • cat
    cat about 8 years
    This is my favourite Stack Exchange answer.
  • Peter Cordes
    Peter Cordes about 8 years
    @AndrewHenle: Oh right, I used to use \rm fairly often when I had it aliased to rm -i (instead of my current choice of rm -I).
  • Random832
    Random832 about 8 years
    Hopefully at least anyone who knows how to "compile it like you would any other module" knows how much of a bad idea this is.
  • David Richerby
    David Richerby about 8 years
    @PeterCordes If you somehow disabled kill for interactive use, the trivial work-around would be to invoke kill via a wrapper script.
  • Peter Cordes
    Peter Cordes about 8 years
    Interesting, I guess you modify %rsp before tail-calling sys_delete_module so the return address is outside the deleted function. Anyway, always use constraints to ask for your data in the right register, instead of using mov instructions. e.g. use "D"(__this_module.name) to ask for it in %rdi in the first place. A mov at the start or end of an inline asm block of code is almost always sub-optimal, and better left to the compiler. I don't think there's a constraint for %rsp, though, and I know there aren't constraints for any of %r8 through %r15.
  • Peter Cordes
    Peter Cordes about 8 years
  • Flexo
    Flexo about 8 years
    Uh if you run it in a chroot nothing stops you making the kill syscall directly from e.g. another application, which could even be one you compiled and uploaded into the chroot. (Byte by byte if you cared enough). Chroot is nowhere near foolproof. Short of hobbling the system call inside the kernel nothing can stop it completely.
  • Daniel McLaury
    Daniel McLaury about 8 years
    Can someone please insert this module in a VM and post a recording of what happens on YouTube?
  • ivan_pozdeev
    ivan_pozdeev about 8 years
    @Flexo we're talking about disabling the stock application here (the title is "disable the kill command"). I never said it would work for a direct syscall. The expression "fool-proof" can be understood to imply that, I must agree.
  • Lekensteyn
    Lekensteyn about 8 years
    Can someone please explain why ET has to be cleared (it seems hard-wired to 1 according to the AMD64 manual) and why the stack has to be prepared in this way? Where does THREAD_SIZE come from? In arch/x86/entry/entry_64.S it can be seen that a number of registers are pushed to the stack (sizeof(struct pt_regs) to be precise), this (and that the return address for call (-8)) are ignored. What is following this stack? Kind of disappointing that this answer gets such high upvotes with no explanation...
  • David
    David about 8 years
    @xxlali What are you trying to do? The fact that you are not an advanced user makes it even more likely that disabling kill is not what you should actually be doing to solve the problem you're having...
  • xxlali
    xxlali about 8 years
    @DavidYoung I have a program. There is another way to stop this program, but some users prefer the stop this program using 'kill -9 %pid%' which causes unwanted results. So, I want to force users to use normal way stop. This is why I want to disable kill command usage.
  • cat
    cat almost 8 years
    $process and $@ should be "double quoted"
  • user69874
    user69874 almost 8 years
    @Lekensteyn the stack is set up so after the call to delete_module it returns directly to the syscall handler and exits kernel mode. Extension Type was just my sloppiness :(
  • Lekensteyn
    Lekensteyn almost 8 years
    @user69874 So, mov %0, %%rsp sets the SP to (current->stack + ...) (based on the GCC Extended Asm manual, why this value though?). "D"(..) and "S"(...) seem to be constraints to put the values in the rdi and rsi registers, respectively for the first and second argument (name, flags), correct?
  • user69874
    user69874 almost 8 years
    @Lekensteyn THREAD_SIZE is the size of the stack. current->stack + THREAD_SIZE is the highest address in the stack. After the struct pt_regs is constructed on the struct there is a call *sys_call_table(, %rax, 8) which pushes the return address immediately after the pt_regs. (current->stack + ...) is to make sure the ret at the end of delete_module goes to that address.You are correct in that rdi and rsi are the arguments to delete_module. Also what do you mean by "ignored" in your previous comment?
  • Lekensteyn
    Lekensteyn almost 8 years
    @user69874 Thanks for the clarifications, could you edit these into your post? By "ignored" I mean that the the return address from the call instruction is removed from the stack (supposedly). Also, Peter Cordes' comment is more helpful than the current GCC comment, maybe it also worth adding it in?
  • user69874
    user69874 almost 8 years
    @Lekensteyn which call do you mean?
  • Lekensteyn
    Lekensteyn almost 8 years
    @user69874 The one in entry_64.S, call *sys_call_table(, %rax, 8). I could be mistaken though.
  • user69874
    user69874 almost 8 years
    @Lekensteyn No, the call instruction in the syscall handler only invokes sys_init_module which in turn invokes our init function. The return address is in fact used by the system call to later return to the handler. The code above doesn't remove it from the stack, but rather moves the stack pointer right in front of it so sys_delete_module will return to the syscall handler.