1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * Copyright (C) 2017 Joe Lawrence <joe.lawren 3 * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com> 4 */ 4 */ 5 5 6 /* 6 /* 7 * livepatch-callbacks-demo.c - (un)patching c 7 * livepatch-callbacks-demo.c - (un)patching callbacks livepatch demo 8 * 8 * 9 * 9 * 10 * Purpose 10 * Purpose 11 * ------- 11 * ------- 12 * 12 * 13 * Demonstration of registering livepatch (un) 13 * Demonstration of registering livepatch (un)patching callbacks. 14 * 14 * 15 * 15 * 16 * Usage 16 * Usage 17 * ----- 17 * ----- 18 * 18 * 19 * Step 1 - load the simple module 19 * Step 1 - load the simple module 20 * 20 * 21 * insmod samples/livepatch/livepatch-callba 21 * insmod samples/livepatch/livepatch-callbacks-mod.ko 22 * 22 * 23 * 23 * 24 * Step 2 - load the demonstration livepatch ( 24 * Step 2 - load the demonstration livepatch (with callbacks) 25 * 25 * 26 * insmod samples/livepatch/livepatch-callba 26 * insmod samples/livepatch/livepatch-callbacks-demo.ko 27 * 27 * 28 * 28 * 29 * Step 3 - cleanup 29 * Step 3 - cleanup 30 * 30 * 31 * echo 0 > /sys/kernel/livepatch/livepatch_ 31 * echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 32 * rmmod livepatch_callbacks_demo 32 * rmmod livepatch_callbacks_demo 33 * rmmod livepatch_callbacks_mod 33 * rmmod livepatch_callbacks_mod 34 * 34 * 35 * Watch dmesg output to see livepatch enablem 35 * Watch dmesg output to see livepatch enablement, callback execution 36 * and patching operations for both vmlinux an 36 * and patching operations for both vmlinux and module targets. 37 * 37 * 38 * NOTE: swap the insmod order of livepatch-ca 38 * NOTE: swap the insmod order of livepatch-callbacks-mod.ko and 39 * livepatch-callbacks-demo.ko to observ 39 * livepatch-callbacks-demo.ko to observe what happens when a 40 * target module is loaded after a livep 40 * target module is loaded after a livepatch with callbacks. 41 * 41 * 42 * NOTE: 'pre_patch_ret' is a module parameter 42 * NOTE: 'pre_patch_ret' is a module parameter that sets the pre-patch 43 * callback return status. Try setting 43 * callback return status. Try setting up a non-zero status 44 * such as -19 (-ENODEV): 44 * such as -19 (-ENODEV): 45 * 45 * 46 * # Load demo livepatch, vmlinux is pat 46 * # Load demo livepatch, vmlinux is patched 47 * insmod samples/livepatch/livepatch-ca 47 * insmod samples/livepatch/livepatch-callbacks-demo.ko 48 * 48 * 49 * # Setup next pre-patch callback to re 49 * # Setup next pre-patch callback to return -ENODEV 50 * echo -19 > /sys/module/livepatch_call 50 * echo -19 > /sys/module/livepatch_callbacks_demo/parameters/pre_patch_ret 51 * 51 * 52 * # Module loader refuses to load the t 52 * # Module loader refuses to load the target module 53 * insmod samples/livepatch/livepatch-ca 53 * insmod samples/livepatch/livepatch-callbacks-mod.ko 54 * insmod: ERROR: could not insert modul 54 * insmod: ERROR: could not insert module samples/livepatch/livepatch-callbacks-mod.ko: No such device 55 * 55 * 56 * NOTE: There is a second target module, 56 * NOTE: There is a second target module, 57 * livepatch-callbacks-busymod.ko, avail 57 * livepatch-callbacks-busymod.ko, available for experimenting 58 * with livepatch (un)patch callbacks. 58 * with livepatch (un)patch callbacks. This module contains 59 * a 'sleep_secs' parameter that parks t 59 * a 'sleep_secs' parameter that parks the module on one of the 60 * functions that the livepatch demo mod 60 * functions that the livepatch demo module wants to patch. 61 * Modifying this value and tweaking the 61 * Modifying this value and tweaking the order of module loads can 62 * effectively demonstrate stalled patch 62 * effectively demonstrate stalled patch transitions: 63 * 63 * 64 * # Load a target module, let it park o 64 * # Load a target module, let it park on 'busymod_work_func' for 65 * # thirty seconds 65 * # thirty seconds 66 * insmod samples/livepatch/livepatch-ca 66 * insmod samples/livepatch/livepatch-callbacks-busymod.ko sleep_secs=30 67 * 67 * 68 * # Meanwhile load the livepatch 68 * # Meanwhile load the livepatch 69 * insmod samples/livepatch/livepatch-ca 69 * insmod samples/livepatch/livepatch-callbacks-demo.ko 70 * 70 * 71 * # ... then load and unload another ta 71 * # ... then load and unload another target module while the 72 * # transition is in progress 72 * # transition is in progress 73 * insmod samples/livepatch/livepatch-ca 73 * insmod samples/livepatch/livepatch-callbacks-mod.ko 74 * rmmod samples/livepatch/livepatch-cal 74 * rmmod samples/livepatch/livepatch-callbacks-mod.ko 75 * 75 * 76 * # Finally cleanup 76 * # Finally cleanup 77 * echo 0 > /sys/kernel/livepatch/livepa 77 * echo 0 > /sys/kernel/livepatch/livepatch_callbacks_demo/enabled 78 * rmmod samples/livepatch/livepatch-cal 78 * rmmod samples/livepatch/livepatch-callbacks-demo.ko 79 */ 79 */ 80 80 81 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 81 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 82 82 83 #include <linux/module.h> 83 #include <linux/module.h> 84 #include <linux/kernel.h> 84 #include <linux/kernel.h> 85 #include <linux/livepatch.h> 85 #include <linux/livepatch.h> 86 86 87 static int pre_patch_ret; 87 static int pre_patch_ret; 88 module_param(pre_patch_ret, int, 0644); 88 module_param(pre_patch_ret, int, 0644); 89 MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret 89 MODULE_PARM_DESC(pre_patch_ret, "pre_patch_ret (default=0)"); 90 90 91 static const char *const module_state[] = { 91 static const char *const module_state[] = { 92 [MODULE_STATE_LIVE] = "[MODULE_STA 92 [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", 93 [MODULE_STATE_COMING] = "[MODULE_STA 93 [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", 94 [MODULE_STATE_GOING] = "[MODULE_STA 94 [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", 95 [MODULE_STATE_UNFORMED] = "[MODULE_STA 95 [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", 96 }; 96 }; 97 97 98 static void callback_info(const char *callback 98 static void callback_info(const char *callback, struct klp_object *obj) 99 { 99 { 100 if (obj->mod) 100 if (obj->mod) 101 pr_info("%s: %s -> %s\n", call 101 pr_info("%s: %s -> %s\n", callback, obj->mod->name, 102 module_state[obj->mod- 102 module_state[obj->mod->state]); 103 else 103 else 104 pr_info("%s: vmlinux\n", callb 104 pr_info("%s: vmlinux\n", callback); 105 } 105 } 106 106 107 /* Executed on object patching (ie, patch enab 107 /* Executed on object patching (ie, patch enablement) */ 108 static int pre_patch_callback(struct klp_objec 108 static int pre_patch_callback(struct klp_object *obj) 109 { 109 { 110 callback_info(__func__, obj); 110 callback_info(__func__, obj); 111 return pre_patch_ret; 111 return pre_patch_ret; 112 } 112 } 113 113 114 /* Executed on object unpatching (ie, patch di 114 /* Executed on object unpatching (ie, patch disablement) */ 115 static void post_patch_callback(struct klp_obj 115 static void post_patch_callback(struct klp_object *obj) 116 { 116 { 117 callback_info(__func__, obj); 117 callback_info(__func__, obj); 118 } 118 } 119 119 120 /* Executed on object unpatching (ie, patch di 120 /* Executed on object unpatching (ie, patch disablement) */ 121 static void pre_unpatch_callback(struct klp_ob 121 static void pre_unpatch_callback(struct klp_object *obj) 122 { 122 { 123 callback_info(__func__, obj); 123 callback_info(__func__, obj); 124 } 124 } 125 125 126 /* Executed on object unpatching (ie, patch di 126 /* Executed on object unpatching (ie, patch disablement) */ 127 static void post_unpatch_callback(struct klp_o 127 static void post_unpatch_callback(struct klp_object *obj) 128 { 128 { 129 callback_info(__func__, obj); 129 callback_info(__func__, obj); 130 } 130 } 131 131 132 static void patched_work_func(struct work_stru 132 static void patched_work_func(struct work_struct *work) 133 { 133 { 134 pr_info("%s\n", __func__); 134 pr_info("%s\n", __func__); 135 } 135 } 136 136 137 static struct klp_func no_funcs[] = { 137 static struct klp_func no_funcs[] = { 138 { } 138 { } 139 }; 139 }; 140 140 141 static struct klp_func busymod_funcs[] = { 141 static struct klp_func busymod_funcs[] = { 142 { 142 { 143 .old_name = "busymod_work_func 143 .old_name = "busymod_work_func", 144 .new_func = patched_work_func, 144 .new_func = patched_work_func, 145 }, { } 145 }, { } 146 }; 146 }; 147 147 148 static struct klp_object objs[] = { 148 static struct klp_object objs[] = { 149 { 149 { 150 .name = NULL, /* vmlinux */ 150 .name = NULL, /* vmlinux */ 151 .funcs = no_funcs, 151 .funcs = no_funcs, 152 .callbacks = { 152 .callbacks = { 153 .pre_patch = pre_patch 153 .pre_patch = pre_patch_callback, 154 .post_patch = post_pat 154 .post_patch = post_patch_callback, 155 .pre_unpatch = pre_unp 155 .pre_unpatch = pre_unpatch_callback, 156 .post_unpatch = post_u 156 .post_unpatch = post_unpatch_callback, 157 }, 157 }, 158 }, { 158 }, { 159 .name = "livepatch_callbacks_m 159 .name = "livepatch_callbacks_mod", 160 .funcs = no_funcs, 160 .funcs = no_funcs, 161 .callbacks = { 161 .callbacks = { 162 .pre_patch = pre_patch 162 .pre_patch = pre_patch_callback, 163 .post_patch = post_pat 163 .post_patch = post_patch_callback, 164 .pre_unpatch = pre_unp 164 .pre_unpatch = pre_unpatch_callback, 165 .post_unpatch = post_u 165 .post_unpatch = post_unpatch_callback, 166 }, 166 }, 167 }, { 167 }, { 168 .name = "livepatch_callbacks_b 168 .name = "livepatch_callbacks_busymod", 169 .funcs = busymod_funcs, 169 .funcs = busymod_funcs, 170 .callbacks = { 170 .callbacks = { 171 .pre_patch = pre_patch 171 .pre_patch = pre_patch_callback, 172 .post_patch = post_pat 172 .post_patch = post_patch_callback, 173 .pre_unpatch = pre_unp 173 .pre_unpatch = pre_unpatch_callback, 174 .post_unpatch = post_u 174 .post_unpatch = post_unpatch_callback, 175 }, 175 }, 176 }, { } 176 }, { } 177 }; 177 }; 178 178 179 static struct klp_patch patch = { 179 static struct klp_patch patch = { 180 .mod = THIS_MODULE, 180 .mod = THIS_MODULE, 181 .objs = objs, 181 .objs = objs, 182 }; 182 }; 183 183 184 static int livepatch_callbacks_demo_init(void) 184 static int livepatch_callbacks_demo_init(void) 185 { 185 { 186 return klp_enable_patch(&patch); 186 return klp_enable_patch(&patch); 187 } 187 } 188 188 189 static void livepatch_callbacks_demo_exit(void 189 static void livepatch_callbacks_demo_exit(void) 190 { 190 { 191 } 191 } 192 192 193 module_init(livepatch_callbacks_demo_init); 193 module_init(livepatch_callbacks_demo_init); 194 module_exit(livepatch_callbacks_demo_exit); 194 module_exit(livepatch_callbacks_demo_exit); 195 MODULE_LICENSE("GPL"); 195 MODULE_LICENSE("GPL"); 196 MODULE_INFO(livepatch, "Y"); 196 MODULE_INFO(livepatch, "Y"); 197 197
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.