Arguments in syscall intercept using loadable kernel module seem to be broken

人走茶凉 提交于 2020-01-29 13:25:06

问题


First post so I apologize for the possibly low quality explanation.

I was trying to write a loadable kernel module that does nothing but intercept syscalls to SYS_open, print the arguments to KERN_INFO and then forward the arguments to the real syscall. The forwarding part seems to be working just fine, but I'm having issues with the printing, arguments seem to be broken, from the syscall interceptor function's perspective.

Following are the pointer to the real open syscall as well as the interceptor definition.

asmlinkage int (*real_open) (const char __user *, int, umode_t);

asmlinkage int fake_open(const char __user *filename, int flags, umode_t mode)
{
    printk(KERN_INFO "interceptor: open() with flags = %d\n", flags);

    return real_open(filename, flags, mode);
}

This is the syscall I'm testing:

syscall(SYS_open, argv[1], 3187236);

Which leads to the following call, according to strace:

open("test", O_RDONLY|O_TRUNC|__O_SYNC|O_LARGEFILE|O_PATH|FASYNC|0x24) = -1 ENOENT (No such file or directory)

And the information printed by the interceptor:

[18191.407899] interceptor: open() with flags = 0

As you can see, the flags argument is equal to 0, even though I passed 3187236 as flags. What's even weirder, the real open syscall seems to have no issue in dealing with the arguments.

Any kind of help is appreciated since I'm pretty much stuck here.

Here's the full module code in case it's of any help:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/futex.h>

#include <linux/highmem.h>
#include <asm/unistd.h>
#include <linux/slab.h>

/*

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

*/

unsigned long long *sys_call_table = (unsigned long long*) 0xffffffffaf800260;    //sudo cat /proc/kallsyms | grep sys_call_table         (/boot/System.map)

asmlinkage int (*real_open) (const char __user *, int, umode_t);

asmlinkage int fake_open(const char __user *filename, int flags, umode_t mode)
{
    printk("interceptor: open() with flags = %d\n", flags);

    return real_open(filename, flags, mode);
}


//make the memory page writable
int make_rw(unsigned long long address)
{
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);

    if(pte->pte & ~_PAGE_RW)
        pte->pte |= _PAGE_RW;

    return 0;   
}

//make the memory page read only
int make_ro(unsigned long long address)
{
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);

    pte->pte &= ~_PAGE_RW;

    return 0;
}


static int __init init(void)
{
    printk(KERN_INFO "Attempting to install hook.\n");

    make_rw((unsigned long long) sys_call_table);

    real_open = (void*) sys_call_table[__NR_open];
    sys_call_table[__NR_open] = (unsigned long long) fake_open;

    make_ro((unsigned long long) sys_call_table);

    return 0;   //no error
}

static void __exit clean(void)
{
    printk(KERN_INFO "Uninstalling hook.\n");

    make_rw((unsigned long long) sys_call_table);

    sys_call_table[__NR_open] = (unsigned long long) real_open;

    make_ro((unsigned long long) sys_call_table);
}

module_init(init);
module_exit(clean);
MODULE_LICENSE("GPL");

回答1:


UPDATE: Kernel version 4.17 and up requires parameters to be passed through a pt_regs struct. Previous code was good up to 4.16.

asmlinkage long (*real_open) (const struct pt_regs *);

asmlinkage long fake_open(const struct pt_regs *regs)
{
    printk("interceptor: open() with flags = %ld\n", regs->si);

    return real_open(regs);
}

More information: https://github.com/milabs/khook/issues/3

Thanks for everyone who contributed in the comments!



来源:https://stackoverflow.com/questions/59346208/arguments-in-syscall-intercept-using-loadable-kernel-module-seem-to-be-broken

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!