root/scripts/livepatch/init.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Init code for a livepatch kernel module
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/livepatch.h>

static struct klp_patch *patch;

static int __init livepatch_mod_init(void)
{
        struct klp_object_ext *obj_exts;
        size_t obj_exts_sec_size;
        struct klp_object *objs;
        unsigned int nr_objs;
        int ret;

        obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects",
                                            &obj_exts_sec_size);
        nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
        if (!nr_objs) {
                pr_err("nothing to patch!\n");
                ret = -EINVAL;
                goto err;
        }

        patch = kzalloc_obj(*patch);
        if (!patch) {
                ret = -ENOMEM;
                goto err;
        }

        objs = kzalloc(sizeof(struct klp_object) * (nr_objs + 1),  GFP_KERNEL);
        if (!objs) {
                ret = -ENOMEM;
                goto err_free_patch;
        }

        for (int i = 0; i < nr_objs; i++) {
                struct klp_object_ext *obj_ext = obj_exts + i;
                struct klp_func_ext *funcs_ext = obj_ext->funcs;
                unsigned int nr_funcs = obj_ext->nr_funcs;
                struct klp_func *funcs = objs[i].funcs;
                struct klp_object *obj = objs + i;

                funcs = kzalloc(sizeof(struct klp_func) * (nr_funcs + 1), GFP_KERNEL);
                if (!funcs) {
                        ret = -ENOMEM;
                        for (int j = 0; j < i; j++)
                                kfree(objs[i].funcs);
                        goto err_free_objs;
                }

                for (int j = 0; j < nr_funcs; j++) {
                        funcs[j].old_name   = funcs_ext[j].old_name;
                        funcs[j].new_func   = funcs_ext[j].new_func;
                        funcs[j].old_sympos = funcs_ext[j].sympos;
                }

                obj->name = obj_ext->name;
                obj->funcs = funcs;

                memcpy(&obj->callbacks, &obj_ext->callbacks, sizeof(struct klp_callbacks));
        }

        patch->mod = THIS_MODULE;
        patch->objs = objs;

        /* TODO patch->states */

#ifdef KLP_NO_REPLACE
        patch->replace = false;
#else
        patch->replace = true;
#endif

        return klp_enable_patch(patch);

err_free_objs:
        kfree(objs);
err_free_patch:
        kfree(patch);
err:
        return ret;
}

static void __exit livepatch_mod_exit(void)
{
        struct klp_object *obj;

        klp_for_each_object_static(patch, obj)
                kfree(obj->funcs);

        kfree(patch->objs);
        kfree(patch);
}

module_init(livepatch_mod_init);
module_exit(livepatch_mod_exit);
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
MODULE_DESCRIPTION("Livepatch module");