Skip to content

Possible to hook sys_kill(pid, signal)? #3

Closed

Description

@alichtman

Just wanted to start out by saying this is an awesome project! Nice work!


I'm having a problem hooking sys_kill, and I was hoping you'd be able to help me out.

sys_kill is defined here in linux/syscalls.h.

I have been trying to hook this function for a while and can not get anything to compile. I was able to hook kill_pid, however, that did not hook the kill syscall.

// BUG: COMPILES BUT DOESN'T HOOK KILL.
KHOOK(kill_pid);
static int khook_kill_pid(struct pid *pid, int sig, int priv) {
	if (pid->numbers->nr == MAGIC_NUM) {
		return do_the_thing();
	} else {
		return KHOOK_ORIGIN(kill_pid, pid, sig, priv);
	}
}

Is there a way to hook the actual kill syscall? Or can it not be done since the syscall table is no longer exported, post-Kernel 2.6?

Activity

  1. milabs commented on Apr 8, 2019

    @milabs
    Owner

    Hey, thank you for using KHOOK.

    As for hooking system calls you have to hook sys_XXX symbols like sys_kill. See the example below:

    KHOOK_EXT(long, sys_kill, long, long);
    static long khook_sys_kill(long pid, long sig) {
            printk("sys_kill -- %s pid %ld sig %ld\n", current->comm, pid, sig);
            return KHOOK_ORIGIN(sys_kill, pid, sig);
    }
    

    Just use the right prototype for this sys_kill...

  2. alichtman commented on Apr 8, 2019

    @alichtman
    Author

    Oh, whoops. My brain was not working correctly last night. Thanks for the help!

    However, the example did not work for me. When I run $ kill <some_pid> in bash, this debug statement isn't printed.

    I tried changing the first parameter to a pid_t type, and that did not solve the problem either.

    I'm pretty sure that $ kill calls sys_kill(), but I'm not sure if that's true.

  3. milabs commented on Apr 8, 2019

    @milabs
    Owner

    It's weird. I've tried to kill -9 1 and the dmesg shows me:
    [ 4630.052329] sys_kill -- bash pid 1 sig 9

    By the way, my kernel is 4.8.0-53-generic

  4. alichtman commented on Apr 8, 2019

    @alichtman
    Author

    I'm working on 4.18.0-17-generic. Still not seeing the same behavior you're describing. Hmm.

  5. milabs commented on Apr 9, 2019

    @milabs
    Owner

    OK, it makes sense then. From some point they changed syscalls notation and argument passing. So, now you have to look for __x64_sys_kill with long (*)(const struct pt_regs *) proto instead of sys_kill. The code may look like this (didn't test):

    KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
    static long khook___x64_sys_kill(const struct pt_regs *regs) {
            printk("sys_kill -- %s pid %ld sig %ld\n", current->comm, regs->di, regs->si);
            return KHOOK_ORIGIN(__x64_sys_kill, regs);
    }
    
  6. alichtman commented on Apr 10, 2019

    @alichtman
    Author

    Oh, alright, cool! I'll try this out when I have a minute.

  7. alichtman commented on Apr 13, 2019

    @alichtman
    Author

    Worked perfectly. Thanks for the help!

  8. milabs commented on Apr 15, 2019

    @milabs
    Owner

    Updated the README with this example. Thank you for the question.

  9. alichtman commented on Apr 16, 2019

    @alichtman
    Author

    Can you explain where you found this new function signature?

    KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
    static long khook___x64_sys_kill(const struct pt_regs *regs)

    I'm having trouble reproducing this with other syscalls.

    For example, I have this hook for msgctl, and it's not being tripped.

    KHOOK_EXT(long, __x64_ksys_msgctl, int, int, struct msqid_ds __user *);
    static long khook___x64_ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)

    Here is a relevant LKML email: https://lore.kernel.org/lkml/tip-d5a00528b58cdb2c71206e18bd021e34c4eab878@git.kernel.org/

    But I can't figure out where you found the prototype for the updated sys_kill function. As far as I can tell, it's not in the source code. But I also know that can't be right, so I'm a little stuck. Google has turned up nothing so far.

    Edit: I found this: https://github.com/torvalds/linux/blob/618d919cae2fcaadc752f27ddac8b939da8b441a/arch/x86/include/asm/syscall_wrapper.h#L125

    and updated my code to:

    KHOOK_EXT(long, __x64_ksys_msgctl, const struct pt_regs *);
    static long khook___x64_ksys_msgctl(const struct pt_regs * regs) {
    	// int msqid, int cmd, struct msqid_ds __user *buf
    	action_task* task;
    	// Read first two arguments
    	if (regs->di == -1 && regs->si == -1) {
    		if (condition) { 
    			printk(KERN_EMERG "sys_msgctl -- preparing...\n");
    			...
    			return 0;
    		} else {
    			printk(KERN_EMERG "sys_msgctl\n");
    			task = (action_task*) regs->dx;
    			...
    			return 0;
    		}
    	} else {
    		return KHOOK_ORIGIN(__x64_ksys_msgctl, regs);
    	}
    }

    However, this still does not hook msgctl calls.

  10. milabs commented on Apr 16, 2019

    @milabs
    Owner

    TLDR: __x64_ksys_msgctl -> __x64_sys_msgctl

    https://elixir.bootlin.com/linux/latest/source/ipc/msg.c#L614

    SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
    {
    	return ksys_msgctl(msqid, cmd, buf);
    }
    

    You could ether hook ksys_msgctl(int, int, struct msqid_ds *) as a kernel function (in case if it is exported as a ksym with name -- check by grepping /proc/kallsyms) or hook __x64_sys_msgctl/sys_msgctl as a system call handler.

  11. alichtman commented on Apr 16, 2019

    @alichtman
    Author

    ksys_msgctl does appear in /proc/kallsyms, and I've made this change: __x64_ksys_msgctl -> __x64_sys_msgctl.

    It's still not being hooked properly.

    The syscall definition you pasted in was the reason I initially had sys_msgctl hooked like this:

    KHOOK_EXT(long, __x64_ksys_msgctl, int, int, struct msqid_ds __user *);
    static long khook___x64_ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)

    Should I change that ^ to __x64_sys_msgctl?

    I feel like I’m missing some core understanding of what I’m doing. Do you have any recommendations for topics I should read up on?

  12. milabs commented on Apr 16, 2019

    @milabs
    Owner

    Should I change that ^ to __x64_sys_msgctl?

    YES (but I didn't test it)

  13. milabs commented on Apr 16, 2019

    @milabs
    Owner

    This works well for me:

    KHOOK_EXT(long, __x64_sys_msgctl, const struct pt_regs *);
    static long khook___x64_sys_msgctl(const struct pt_regs *regs)
    {
    	printk("%s -- msqid:%ld cmd:%ld ptr:%p\n", current->comm, regs->di, regs->si, (void *)regs->dx);
    	return KHOOK_ORIGIN(__x64_sys_msgctl, regs);
    }
    

    main.c

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    int main(int argc, const char *argv[])
    {
    	msgctl(100, 200, (void *)300);
    	return 0;
    }
    

    $ dmesg
    [108112.452874] a.out -- msqid:100 cmd:200 ptr:000000008b1f8f3d

  14. 1 remaining item

  15. KTalinki commented on May 3, 2019

    @KTalinki

    hi,
    I am trying to hook sys_open and some other syscalls to intercept the file system activity, on kernel 4.17/4.18 on x86_64.

    /proc/kallsyms shows __x64_sys_open, but not ksys_open.
    Not sure if I need to hook ksys_open or __x64_sys_open
    I am getting compilation error of 'undelcared identifier' for sys_open & __x64_sys_open.

    What are the right headers I need to include ?

    Along with sys_open, I need to hook sys_creat, sys_openat, sys_execve, sys_truncate, sys_ftruncate, sys_write, etc...

    Before kernel 4.17, I was able to find the symbol for sys_xyz, but from Kernel 4.17 onward, I am not sure if I need to hook __x64_sys_xyz or ksys_xyz or sys_xyz.

    In syscalls.h Some system call are declared with /__ARCH_WANT_SYSCALL_DEPRECATED/

    Please help,
    thank you,
    Kumar T

  16. milabs commented on May 3, 2019

    @milabs
    Owner

    @KTalinki Use the following code for every "modern" syscall handler (replace XXX with open or so):

    KHOOK_EXT(long, __x64_sys_XXX, const struct pt_regs *);
    static long khook___x64_sys_XXX(const struct pt_regs *regs)
    {
    	// do the job
    	return KHOOK_ORIGIN(__x64_sys_XXX, regs);
    }
    
  17. KTalinki commented on May 3, 2019

    @KTalinki

    Thank you milabs.

    If I were to use hook in a traditional way of finding a specific syscall table address and hook it,
    which specific syscall API to hook
    sys_open or __x64_sys_open or ksys_open
    sys_open or __x64_sys_creat or ksys_creat
    sys_openat or __x64_sys_openat or ksys_openat
    sys_execve or __x64_sys_exeeve or ksys_execve
    etc ...

    and what are the header files __x64_sys_creat or __x64_sys_openat are declared ?

    It will be great if someone can share a sample with what is needed to hook syscalls on kernels from 4.17 onward.

    thank you,
    Kumar T

  18. milabs commented on May 3, 2019

    @milabs
    Owner

    Dear @KTalinki, you don't need to have headers to hook __x64_sys_XXX as they all have the same prototype (like I shown before). As for the ksys_xxx() symbols I'd suggest you to look for the Linux kernel source code to see how they are used. Finally, you're the kernel developer and you have to be able to dig the source code.

  19. KTalinki commented on May 7, 2019

    @KTalinki

    thank you @milabs , the way our existing code is structured, it uses the declaration of the syscalls from .../include/linux/syscalls.h
    But on kernel 4.17 with __x64_sys_open, is not declared in <syscalls.h>
    And <arch/x85/include/generated/asm/syscalls_64.h> has the declaration something like
    __SYSCALL_64(2, __X64_sys_open,)

    The issue I am running in to is compilation errors for __x64_sys_open and __SYSCALL_64.
    Including <arch/x85/include/generated/asm/syscalls_64.h> is not helping.

    Any help is appreciated,
    thank you,
    Kumar

  20. milabs commented on May 8, 2019

    @milabs
    Owner

    @KTalinki Again, you don't have to include ANY header to hook __x64_XXX, just use the KHOOK_EXT macro:

    KHOOK_EXT(long, __x64_sys_XXX, const struct pt_regs *);
    static long khook___x64_sys_XXX(const struct pt_regs *regs)
    {
    	// do the job
    	return KHOOK_ORIGIN(__x64_sys_XXX, regs);
    }
    

    Which is the error with using this code?

  21. wbt165 commented on May 12, 2020

    @wbt165

    @milabs hello,I want to hook sys_exevce. I'm using the KHOOK_EXT macro,which work well on the 64-bit machines,for example Redhat6.8 x86_64 or CentOS8 x86_64.The code is as follows:
    Linux Redhat6.8 2.6.32-642.el6.x86_64:

    KHOOK_EXT(long, sys_execve, char __user *, char __user * __user *, char __user * __user *, struct pt_regs *);
    static long khook_sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs)
    {
    	long ret = 0;
    	ret = KHOOK_ORIGIN(sys_execve, name, argv, envp, regs);
    	return ret;
    }
    

    CentOS8 x86_64:

    KHOOK_EXT(long, __x64_sys_execve, const struct pt_regs *);
    static long khook___x64_sys_execve(const struct pt_regs *regs)
    {
    	long ret = 0;
    	ret = KHOOK_ORIGIN(__x64_sys_execve, regs);
    	return ret;
    }
    

    BUT,I have a problem on the 32-bit machine. I test it on Linux Redhat 6.8 2.6.32-642.el6.i686.The code is as follows:

    KHOOK_EXT(int, sys_execve, struct pt_regs *);
    static int khook_sys_execve(struct pt_regs *regs)
    {
    	int ret = 0;
    	ret = KHOOK_ORIGIN(sys_execve, regs);
    	return ret;
    }
    

    I Found the sys_execve() symbols from the source code as follow:
    image

    After I insmod, I execute "ls" or any other commands. ERROR as following:
    image

    I suspect there is a problem with this code executing on a 32-bit machine.I hope you can take a look in your busy schedule.
    Thanks for your help!

  22. milabs commented on May 12, 2020

    @milabs
    Owner

    @wbt165 I'd recommend you to hook do_execve instead of sys_execve for exec case. Could you try to hook it that way?

  23. wbt165 commented on May 13, 2020

    @wbt165

    @milabs Thanks for your response!
    I test do_execve,and the results as follows:

    • [do_execve work well on Linux Redhat6.8 2.6.32-642.el6.x86_64 ]
    #include <linux/sched.h>
    KHOOK(do_execve);
    static int khook_do_execve(const char * filename,
    	char __user *__user *argv,
    	char __user *__user *envp,
    	struct pt_regs * regs)
    {
    	int ret = 0;
    	ret = KHOOK_ORIGIN(do_execve, filename, argv, envp, regs);
    	pr_info("%s - Pass %s = %d\n", __func__, filename, ret);
    	return ret;
    }
    
    • [do_execve CANNOT hook on CentOS8 4.18.0-147.8.1.el8_1.x86_64, because the debug info is not printed out]
    #include <linux/binfmts.h>
    KHOOK(do_execve);
    static int khook_do_execve(struct filename *filename,
    	const char __user *const __user *__argv,
    	const char __user *const __user *__envp)
    {
    	int ret = 0;
    	ret = KHOOK_ORIGIN(do_execve, filename, __argv, __envp);
    	pr_info("%s - Pass %s = %d\n", __func__, filename->name, ret);
    	return ret;
    }
    
    • [ do_execve CANNOT work on Linux Redhat6.8 2.6.32-642.el6.i686]
    #include <linux/sched.h>
    KHOOK(do_execve);
    static int khook_do_execve(const char * filename,
    	char __user *__user *argv,
    	char __user *__user *envp,
    	struct pt_regs * regs)
    {
    	int ret = 0;
    	ret = KHOOK_ORIGIN(do_execve, filename, argv, envp, regs);
    	pr_info("%s - Pass %s = %d\n", __func__, filename, ret);
    	return ret;
    }
    

    After I insmod, I execute "ls" or any other commands. ERROR as following:
    image
    The debug info is as follow:
    image

    Thanks for your help!

  24. milabs commented on May 15, 2020

    @milabs
    Owner

    @wbt165 Unfortunately, 32-bit stub is not implemented as I never had such requirement for myself (see https://github.com/milabs/khook/blob/master/khook/x86/stub.S#L24). It would be great if you'll try to implement missing part of the macro.

  25. milabs commented on May 15, 2020

    @milabs
    Owner

    If you could test that code on 32-bit system?

    .macro CALL_COPY_N_ARGS n
    	sub $(\n * 4), %esp
    	.set i, 0
    	.rept \n
    		mov ((\n + i + 1) * 4)(%esp), %eax
    		mov %eax, (i * 4)(%esp)
    		.set i, i + 1
    	.endr
    	mov $0xcacacaca, %eax
    	call *%eax
    	add $(\n * 4), %esp
    .endm
    
  26. wbt165 commented on May 18, 2020

    @wbt165

    If you could test that code on 32-bit system?

    .macro CALL_COPY_N_ARGS n
    	sub $(\n * 4), %esp
    	.set i, 0
    	.rept \n
    		mov ((\n + i + 1) * 4)(%esp), %eax
    		mov %eax, (i * 4)(%esp)
    		.set i, i + 1
    	.endr
    	mov $0xcacacaca, %eax
    	call *%eax
    	add $(\n * 4), %esp
    .endm
    

    @milabs Unfortunately,this code has NO effect……

  27. milabs commented on May 18, 2020

    @milabs
    Owner

    @milabs Unfortunately,this code has NO effect……

    Made a branch for you to test:
    https://github.com/milabs/khook/tree/i686-fix
    Could you please test it?

  28. wbt165 commented on May 19, 2020

    @wbt165

    @milabs Thank you for creating a branch! I tested it on Linux Redhat6.8 2.6.32-642.el6.i686, but it didn't work. The code is as follow:

    #include <linux/uaccess.h>
    #include <linux/slab.h>
    static char *duplicate_filename(const char __user *filename)
    {
    	char *kernel_filename;
    	int nRet;
    
    	kernel_filename = kmalloc(4096, GFP_KERNEL);
    	if (!kernel_filename)
    	{
    		pr_info("%s - NULL!\n", __func__);
    		return NULL;
    	}
    
    	nRet = strncpy_from_user(kernel_filename, filename, 4096);
    	if (nRet < 0) {
    		pr_info("%s - nRet = %d!\n", __func__, nRet);
    		kfree(kernel_filename);
    		return NULL;
    	}
    
    	return kernel_filename;
    }
    
    KHOOK_EXT(int, sys_execve, struct pt_regs *);
    static int khook_sys_execve(struct pt_regs *regs)
    {
    	int ret = 0;
    	char *filename;
    
    	filename = duplicate_filename((char __user *)regs->bx);
    	pr_info("%s - %s!\n", __func__, filename);
    
    	ret = KHOOK_ORIGIN(sys_execve, regs);
    	pr_info("%s ret = %d\n", __func__, ret);
    
    	kfree(filename);
    
    	return ret;
    }
    

    After I insmod, I execute "ls" or any other commands. ERROR as following:
    image
    The debug info is as follow:
    image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions