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