162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com> 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/livepatch.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic int pre_patch_ret; 1162306a36Sopenharmony_cimodule_param(pre_patch_ret, int, 0644); 1262306a36Sopenharmony_ciMODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)"); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic const char *const module_state[] = { 1562306a36Sopenharmony_ci [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", 1662306a36Sopenharmony_ci [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", 1762306a36Sopenharmony_ci [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", 1862306a36Sopenharmony_ci [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void callback_info(const char *callback, struct klp_object *obj) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci if (obj->mod) 2462306a36Sopenharmony_ci pr_info("%s: %s -> %s\n", callback, obj->mod->name, 2562306a36Sopenharmony_ci module_state[obj->mod->state]); 2662306a36Sopenharmony_ci else 2762306a36Sopenharmony_ci pr_info("%s: vmlinux\n", callback); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Executed on object patching (ie, patch enablement) */ 3162306a36Sopenharmony_cistatic int pre_patch_callback(struct klp_object *obj) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci callback_info(__func__, obj); 3462306a36Sopenharmony_ci return pre_patch_ret; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Executed on object unpatching (ie, patch disablement) */ 3862306a36Sopenharmony_cistatic void post_patch_callback(struct klp_object *obj) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci callback_info(__func__, obj); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Executed on object unpatching (ie, patch disablement) */ 4462306a36Sopenharmony_cistatic void pre_unpatch_callback(struct klp_object *obj) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci callback_info(__func__, obj); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* Executed on object unpatching (ie, patch disablement) */ 5062306a36Sopenharmony_cistatic void post_unpatch_callback(struct klp_object *obj) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci callback_info(__func__, obj); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void patched_work_func(struct work_struct *work) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci pr_info("%s\n", __func__); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct klp_func no_funcs[] = { 6162306a36Sopenharmony_ci {} 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic struct klp_func busymod_funcs[] = { 6562306a36Sopenharmony_ci { 6662306a36Sopenharmony_ci .old_name = "busymod_work_func", 6762306a36Sopenharmony_ci .new_func = patched_work_func, 6862306a36Sopenharmony_ci }, {} 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic struct klp_object objs[] = { 7262306a36Sopenharmony_ci { 7362306a36Sopenharmony_ci .name = NULL, /* vmlinux */ 7462306a36Sopenharmony_ci .funcs = no_funcs, 7562306a36Sopenharmony_ci .callbacks = { 7662306a36Sopenharmony_ci .pre_patch = pre_patch_callback, 7762306a36Sopenharmony_ci .post_patch = post_patch_callback, 7862306a36Sopenharmony_ci .pre_unpatch = pre_unpatch_callback, 7962306a36Sopenharmony_ci .post_unpatch = post_unpatch_callback, 8062306a36Sopenharmony_ci }, 8162306a36Sopenharmony_ci }, { 8262306a36Sopenharmony_ci .name = "test_klp_callbacks_mod", 8362306a36Sopenharmony_ci .funcs = no_funcs, 8462306a36Sopenharmony_ci .callbacks = { 8562306a36Sopenharmony_ci .pre_patch = pre_patch_callback, 8662306a36Sopenharmony_ci .post_patch = post_patch_callback, 8762306a36Sopenharmony_ci .pre_unpatch = pre_unpatch_callback, 8862306a36Sopenharmony_ci .post_unpatch = post_unpatch_callback, 8962306a36Sopenharmony_ci }, 9062306a36Sopenharmony_ci }, { 9162306a36Sopenharmony_ci .name = "test_klp_callbacks_busy", 9262306a36Sopenharmony_ci .funcs = busymod_funcs, 9362306a36Sopenharmony_ci .callbacks = { 9462306a36Sopenharmony_ci .pre_patch = pre_patch_callback, 9562306a36Sopenharmony_ci .post_patch = post_patch_callback, 9662306a36Sopenharmony_ci .pre_unpatch = pre_unpatch_callback, 9762306a36Sopenharmony_ci .post_unpatch = post_unpatch_callback, 9862306a36Sopenharmony_ci }, 9962306a36Sopenharmony_ci }, { } 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct klp_patch patch = { 10362306a36Sopenharmony_ci .mod = THIS_MODULE, 10462306a36Sopenharmony_ci .objs = objs, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int test_klp_callbacks_demo_init(void) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return klp_enable_patch(&patch); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void test_klp_callbacks_demo_exit(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cimodule_init(test_klp_callbacks_demo_init); 11762306a36Sopenharmony_cimodule_exit(test_klp_callbacks_demo_exit); 11862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 11962306a36Sopenharmony_ciMODULE_INFO(livepatch, "Y"); 12062306a36Sopenharmony_ciMODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 12162306a36Sopenharmony_ciMODULE_DESCRIPTION("Livepatch test: livepatch demo"); 122