Can I replace a Linux kernel function with a module?

前端 未结 4 761
执念已碎
执念已碎 2020-12-24 10:08

Im getting into kernel work for a bit of my summer research. We are looking to make modifications to the TCP, in specific RTT calculations. What I would like to do is repl

相关标签:
4条回答
  • 2020-12-24 10:33

    I'm not sure that'll work - I believe the symbol resolution for the internal calls to the function you want to replace will have already been done by the time your module loads.

    Instead, you could change the code by renaming the existing function, then creating a global function pointer with the original name of the function. Initialise the function pointer to the address of the internal function, so the existing code will work unmodified. Export the symbol of the global function pointer, then your module can just change its value by assignment at module load and unload time.

    0 讨论(0)
  • 2020-12-24 10:33

    I think what you want is Kprobe.

    Another way that caf has mentioned is to add a hook to the original routine, and register/unregister hook in the module.

    0 讨论(0)
  • 2020-12-24 10:41

    You can try using ksplice - you don't even need to make it non static.

    0 讨论(0)
  • 2020-12-24 10:44

    I once made a proof of concept of a hijack module that inserted it's own function in place of kernel function. I just so happens that the new kernel tacing architecture uses a very similar system.

    I injected my own function in the kernel by overwriting the first couple of bytes of code with a jump pointing to my custom function. As soon as the real function gets called, it jumps instead to my function that after it had done it's work called the original function.

    
    #include <linux/module.h>
    #include <linux/kernel.h>
    
    #define CODESIZE 12
    
    static unsigned char original_code[CODESIZE];
    static unsigned char jump_code[CODESIZE] =
        "\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00" /* movq $0, %rax */
        "\xff\xe0"                                          /* jump *%rax */
            ;
    /* FILL THIS IN YOURSELF */
    int (*real_printk)( char * fmt, ... ) = (int (*)(char *,...) )0xffffffff805e5f6e;
    
    int hijack_start(void);
    void hijack_stop(void);
    void intercept_init(void);
    void intercept_start(void);
    void intercept_stop(void);
    int fake_printk(char *, ... );
    
    
    int hijack_start()
    {
        real_printk(KERN_INFO "I can haz hijack?\n" );
        intercept_init();
        intercept_start();
    
        return 0;
    }
    
    void hijack_stop()
    {
        intercept_stop();
        return;
    }
    
    void intercept_init()
    {
        *(long *)&jump_code[2] = (long)fake_printk;
        memcpy( original_code, real_printk, CODESIZE );
    
        return;
    }
    
    void intercept_start()
    {
        memcpy( real_printk, jump_code, CODESIZE );
    }
    
    void intercept_stop()
    {
        memcpy( real_printk, original_code, CODESIZE );
    }
    
    int fake_printk( char *fmt, ... )
    {
        int ret;
        intercept_stop();
        ret = real_printk(KERN_INFO "Someone called printk\n");
        intercept_start();
        return ret;
    }
    
    module_init( hijack_start );
    module_exit( hijack_stop );
    

    I'm warning you, when you're going to experiment with these kind of things, watch out for kernel panics and other disastrous events. I would advise you to do this in a virtualised environment. This is a proof-of-concept code I wrote a while ago, I'm not sure it still works.

    It's a really easy principle, but very effective. Of course, a real solution would use locks to make sure nobody would call the function while you're overwriting it.

    Have fun!

    0 讨论(0)
提交回复
热议问题