| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * livepatch.h - Kernel Live Patching Core |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> |
|---|
| 5 | 6 | * Copyright (C) 2014 SUSE |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; either version 2 |
|---|
| 10 | | - * of the License, or (at your option) any later version. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | | - * |
|---|
| 17 | | - * You should have received a copy of the GNU General Public License |
|---|
| 18 | | - * along with this program; if not, see <http://www.gnu.org/licenses/>. |
|---|
| 19 | 7 | */ |
|---|
| 20 | 8 | |
|---|
| 21 | 9 | #ifndef _LINUX_LIVEPATCH_H_ |
|---|
| .. | .. |
|---|
| 24 | 12 | #include <linux/module.h> |
|---|
| 25 | 13 | #include <linux/ftrace.h> |
|---|
| 26 | 14 | #include <linux/completion.h> |
|---|
| 15 | +#include <linux/list.h> |
|---|
| 27 | 16 | |
|---|
| 28 | 17 | #if IS_ENABLED(CONFIG_LIVEPATCH) |
|---|
| 29 | 18 | |
|---|
| .. | .. |
|---|
| 40 | 29 | * @new_func: pointer to the patched function code |
|---|
| 41 | 30 | * @old_sympos: a hint indicating which symbol position the old function |
|---|
| 42 | 31 | * can be found (optional) |
|---|
| 43 | | - * @old_addr: the address of the function being patched |
|---|
| 32 | + * @old_func: pointer to the function being patched |
|---|
| 44 | 33 | * @kobj: kobject for sysfs resources |
|---|
| 34 | + * @node: list node for klp_object func_list |
|---|
| 45 | 35 | * @stack_node: list node for klp_ops func_stack list |
|---|
| 46 | 36 | * @old_size: size of the old function |
|---|
| 47 | 37 | * @new_size: size of the new function |
|---|
| 38 | + * @nop: temporary patch to use the original code again; dyn. allocated |
|---|
| 48 | 39 | * @patched: the func has been added to the klp_ops list |
|---|
| 49 | 40 | * @transition: the func is currently being applied or reverted |
|---|
| 50 | 41 | * |
|---|
| .. | .. |
|---|
| 77 | 68 | unsigned long old_sympos; |
|---|
| 78 | 69 | |
|---|
| 79 | 70 | /* internal */ |
|---|
| 80 | | - unsigned long old_addr; |
|---|
| 71 | + void *old_func; |
|---|
| 81 | 72 | struct kobject kobj; |
|---|
| 73 | + struct list_head node; |
|---|
| 82 | 74 | struct list_head stack_node; |
|---|
| 83 | 75 | unsigned long old_size, new_size; |
|---|
| 76 | + bool nop; |
|---|
| 84 | 77 | bool patched; |
|---|
| 85 | 78 | bool transition; |
|---|
| 86 | 79 | }; |
|---|
| .. | .. |
|---|
| 115 | 108 | * @funcs: function entries for functions to be patched in the object |
|---|
| 116 | 109 | * @callbacks: functions to be executed pre/post (un)patching |
|---|
| 117 | 110 | * @kobj: kobject for sysfs resources |
|---|
| 111 | + * @func_list: dynamic list of the function entries |
|---|
| 112 | + * @node: list node for klp_patch obj_list |
|---|
| 118 | 113 | * @mod: kernel module associated with the patched object |
|---|
| 119 | 114 | * (NULL for vmlinux) |
|---|
| 115 | + * @dynamic: temporary object for nop functions; dynamically allocated |
|---|
| 120 | 116 | * @patched: the object's funcs have been added to the klp_ops list |
|---|
| 121 | 117 | */ |
|---|
| 122 | 118 | struct klp_object { |
|---|
| .. | .. |
|---|
| 127 | 123 | |
|---|
| 128 | 124 | /* internal */ |
|---|
| 129 | 125 | struct kobject kobj; |
|---|
| 126 | + struct list_head func_list; |
|---|
| 127 | + struct list_head node; |
|---|
| 130 | 128 | struct module *mod; |
|---|
| 129 | + bool dynamic; |
|---|
| 131 | 130 | bool patched; |
|---|
| 131 | +}; |
|---|
| 132 | + |
|---|
| 133 | +/** |
|---|
| 134 | + * struct klp_state - state of the system modified by the livepatch |
|---|
| 135 | + * @id: system state identifier (non-zero) |
|---|
| 136 | + * @version: version of the change |
|---|
| 137 | + * @data: custom data |
|---|
| 138 | + */ |
|---|
| 139 | +struct klp_state { |
|---|
| 140 | + unsigned long id; |
|---|
| 141 | + unsigned int version; |
|---|
| 142 | + void *data; |
|---|
| 132 | 143 | }; |
|---|
| 133 | 144 | |
|---|
| 134 | 145 | /** |
|---|
| 135 | 146 | * struct klp_patch - patch structure for live patching |
|---|
| 136 | 147 | * @mod: reference to the live patch module |
|---|
| 137 | 148 | * @objs: object entries for kernel objects to be patched |
|---|
| 138 | | - * @list: list node for global list of registered patches |
|---|
| 149 | + * @states: system states that can get modified |
|---|
| 150 | + * @replace: replace all actively used patches |
|---|
| 151 | + * @list: list node for global list of actively used patches |
|---|
| 139 | 152 | * @kobj: kobject for sysfs resources |
|---|
| 153 | + * @obj_list: dynamic list of the object entries |
|---|
| 140 | 154 | * @enabled: the patch is enabled (but operation may be incomplete) |
|---|
| 155 | + * @forced: was involved in a forced transition |
|---|
| 156 | + * @free_work: patch cleanup from workqueue-context |
|---|
| 141 | 157 | * @finish: for waiting till it is safe to remove the patch module |
|---|
| 142 | 158 | */ |
|---|
| 143 | 159 | struct klp_patch { |
|---|
| 144 | 160 | /* external */ |
|---|
| 145 | 161 | struct module *mod; |
|---|
| 146 | 162 | struct klp_object *objs; |
|---|
| 163 | + struct klp_state *states; |
|---|
| 164 | + bool replace; |
|---|
| 147 | 165 | |
|---|
| 148 | 166 | /* internal */ |
|---|
| 149 | 167 | struct list_head list; |
|---|
| 150 | 168 | struct kobject kobj; |
|---|
| 169 | + struct list_head obj_list; |
|---|
| 151 | 170 | bool enabled; |
|---|
| 171 | + bool forced; |
|---|
| 172 | + struct work_struct free_work; |
|---|
| 152 | 173 | struct completion finish; |
|---|
| 153 | 174 | }; |
|---|
| 154 | 175 | |
|---|
| 155 | | -#define klp_for_each_object(patch, obj) \ |
|---|
| 176 | +#define klp_for_each_object_static(patch, obj) \ |
|---|
| 156 | 177 | for (obj = patch->objs; obj->funcs || obj->name; obj++) |
|---|
| 157 | 178 | |
|---|
| 158 | | -#define klp_for_each_func(obj, func) \ |
|---|
| 179 | +#define klp_for_each_object_safe(patch, obj, tmp_obj) \ |
|---|
| 180 | + list_for_each_entry_safe(obj, tmp_obj, &patch->obj_list, node) |
|---|
| 181 | + |
|---|
| 182 | +#define klp_for_each_object(patch, obj) \ |
|---|
| 183 | + list_for_each_entry(obj, &patch->obj_list, node) |
|---|
| 184 | + |
|---|
| 185 | +#define klp_for_each_func_static(obj, func) \ |
|---|
| 159 | 186 | for (func = obj->funcs; \ |
|---|
| 160 | 187 | func->old_name || func->new_func || func->old_sympos; \ |
|---|
| 161 | 188 | func++) |
|---|
| 162 | 189 | |
|---|
| 163 | | -int klp_register_patch(struct klp_patch *); |
|---|
| 164 | | -int klp_unregister_patch(struct klp_patch *); |
|---|
| 165 | | -int klp_enable_patch(struct klp_patch *); |
|---|
| 166 | | -int klp_disable_patch(struct klp_patch *); |
|---|
| 190 | +#define klp_for_each_func_safe(obj, func, tmp_func) \ |
|---|
| 191 | + list_for_each_entry_safe(func, tmp_func, &obj->func_list, node) |
|---|
| 167 | 192 | |
|---|
| 168 | | -void arch_klp_init_object_loaded(struct klp_patch *patch, |
|---|
| 169 | | - struct klp_object *obj); |
|---|
| 193 | +#define klp_for_each_func(obj, func) \ |
|---|
| 194 | + list_for_each_entry(func, &obj->func_list, node) |
|---|
| 195 | + |
|---|
| 196 | +int klp_enable_patch(struct klp_patch *); |
|---|
| 170 | 197 | |
|---|
| 171 | 198 | /* Called from the module loader during module coming/going states */ |
|---|
| 172 | 199 | int klp_module_coming(struct module *mod); |
|---|
| .. | .. |
|---|
| 201 | 228 | void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor); |
|---|
| 202 | 229 | void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor); |
|---|
| 203 | 230 | |
|---|
| 231 | +struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id); |
|---|
| 232 | +struct klp_state *klp_get_prev_state(unsigned long id); |
|---|
| 233 | + |
|---|
| 234 | +int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, |
|---|
| 235 | + const char *shstrtab, const char *strtab, |
|---|
| 236 | + unsigned int symindex, unsigned int secindex, |
|---|
| 237 | + const char *objname); |
|---|
| 238 | + |
|---|
| 204 | 239 | #else /* !CONFIG_LIVEPATCH */ |
|---|
| 205 | 240 | |
|---|
| 206 | 241 | static inline int klp_module_coming(struct module *mod) { return 0; } |
|---|
| .. | .. |
|---|
| 209 | 244 | static inline void klp_update_patch_state(struct task_struct *task) {} |
|---|
| 210 | 245 | static inline void klp_copy_process(struct task_struct *child) {} |
|---|
| 211 | 246 | |
|---|
| 247 | +static inline |
|---|
| 248 | +int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, |
|---|
| 249 | + const char *shstrtab, const char *strtab, |
|---|
| 250 | + unsigned int symindex, unsigned int secindex, |
|---|
| 251 | + const char *objname) |
|---|
| 252 | +{ |
|---|
| 253 | + return 0; |
|---|
| 254 | +} |
|---|
| 255 | + |
|---|
| 212 | 256 | #endif /* CONFIG_LIVEPATCH */ |
|---|
| 213 | 257 | |
|---|
| 214 | 258 | #endif /* _LINUX_LIVEPATCH_H_ */ |
|---|