How to call the original function within a livepatch?

43 Views Asked by At

I want to modify the parameters passed to a kernel function through livepatches, but without changing the function's logic. Referring to the livepatch sample, assume that the original function is func_old(int a) and the new function is func_new(int a).

If I call the old function directly in the new function, like this:

void func_new(int a){
    int b = a+1;
    func_old(b);
}

Will infinite recursive calls occur? How should this situation be avoided?

func_old is not visible to the patch and will raise an error of 'implicit declaration of function'. How could this be avoided?

I tried with the following method, but the system hang after I call cat /proc/cmdline.

#include <linux/seq_file.h>

static int (*real_cmdline_proc_show)(struct seq_file *m, void *v);
                

static int fh_cmdline_proc_show(struct seq_file *m, void *v)
{
    int ret;
    
    seq_printf(m, "%s\n", "this has been ftrace hooked");

    ret = real_cmdline_proc_show(m, v);

    pr_debug("cmdline_proc_show() returns: %ld\n", ret);
    
    return ret;
}


static struct klp_func funcs[] = {
    {
        .old_name = "cmdline_proc_show",
        .new_func = fh_cmdline_proc_show,
    }, { }
};

static struct klp_object objs[] = {
    {
        /* name being NULL means vmlinux */
        .funcs = funcs,
    }, { }
};

static struct klp_patch patch = {
    .mod = THIS_MODULE,
    .objs = objs,
};

static int livepatch_init(void)
{
    int result = klp_enable_patch(&patch);
    int (*real_cmdline_proc_show)(struct seq_file *m, void *v) = funcs[0].old_func;
    return result
}

static void livepatch_exit(void)
{
}

module_init(livepatch_init);
module_exit(livepatch_exit);
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
1

There are 1 best solutions below

0
sray On

It is possible to call a non-exported and private function, but you might need some extra tools.

In the current kernel implementation, you can call the original function, e.x. cmdline_proc_show, at runtime with some special ELF relocations and symbols. You can find more details here: https://docs.kernel.org/livepatch/module-elf-format.html

To generate these relocations and symbols is not trivial. You might need to have some tools to perform this ELF editing.

One of the existing tool is kpatch (https://github.com/dynup/kpatch).

It would NOT help you to implement code as

void func_new(int a){
    int b = a+1;
    func_old(b);
}

To implement a similar fix, you need to re-write the function as

void func_old(int a){
    a = a+1;
    // copy the rest of the code from func_old
}

kpatch will help you handle the rest of the relocation/symbol work.

Another example from kpatch: https://github.com/dynup/kpatch/blob/master/examples/cmdline-string.patch