diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-23 17:07:26 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-23 17:07:26 -0400 |
| commit | 0faef837e431b4984652f4a14d2075bed108a04d (patch) | |
| tree | 8fae7d48b875190487b94878e55d34be447392b7 | |
| parent | 67db8a8086e9b865533348954f5547f1e433101e (diff) | |
| parent | 110c146645140636995c3cf6c6d782008ff67ce8 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching fixes from Jiri Kosina:
- symbol lookup locking fix, from Miroslav Benes
- error handling improvements in case of failure of the module coming
notifier, from Minfei Huang
- we were too pessimistic when kASLR has been enabled on x86 and were
dropping address hints on the floor unnecessarily in such case. Fix
from Jiri Kosina
- a few other small fixes and cleanups
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
livepatch: add module locking around kallsyms calls
livepatch: annotate klp_init() with __init
livepatch: introduce patch/func-walking helpers
livepatch: make kobject in klp_object statically allocated
livepatch: Prevent patch inconsistencies if the coming module notifier fails
livepatch: match return value to function signature
x86: kaslr: fix build due to missing ALIGN definition
livepatch: x86: make kASLR logic more accurate
x86: introduce kaslr_offset()
| -rw-r--r-- | arch/x86/include/asm/livepatch.h | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/setup.h | 7 | ||||
| -rw-r--r-- | arch/x86/kernel/machine_kexec_64.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/setup.c | 2 | ||||
| -rw-r--r-- | include/linux/livepatch.h | 8 | ||||
| -rw-r--r-- | kernel/livepatch/core.c | 96 |
6 files changed, 79 insertions, 38 deletions
diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h index 2d29197bd2fb..19c099afa861 100644 --- a/arch/x86/include/asm/livepatch.h +++ b/arch/x86/include/asm/livepatch.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #ifndef _ASM_X86_LIVEPATCH_H | 21 | #ifndef _ASM_X86_LIVEPATCH_H |
| 22 | #define _ASM_X86_LIVEPATCH_H | 22 | #define _ASM_X86_LIVEPATCH_H |
| 23 | 23 | ||
| 24 | #include <asm/setup.h> | ||
| 24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 25 | #include <linux/ftrace.h> | 26 | #include <linux/ftrace.h> |
| 26 | 27 | ||
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index f69e06b283fb..11af24e09c8a 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h | |||
| @@ -60,17 +60,24 @@ static inline void x86_ce4100_early_setup(void) { } | |||
| 60 | #ifndef _SETUP | 60 | #ifndef _SETUP |
| 61 | 61 | ||
| 62 | #include <asm/espfix.h> | 62 | #include <asm/espfix.h> |
| 63 | #include <linux/kernel.h> | ||
| 63 | 64 | ||
| 64 | /* | 65 | /* |
| 65 | * This is set up by the setup-routine at boot-time | 66 | * This is set up by the setup-routine at boot-time |
| 66 | */ | 67 | */ |
| 67 | extern struct boot_params boot_params; | 68 | extern struct boot_params boot_params; |
| 69 | extern char _text[]; | ||
| 68 | 70 | ||
| 69 | static inline bool kaslr_enabled(void) | 71 | static inline bool kaslr_enabled(void) |
| 70 | { | 72 | { |
| 71 | return !!(boot_params.hdr.loadflags & KASLR_FLAG); | 73 | return !!(boot_params.hdr.loadflags & KASLR_FLAG); |
| 72 | } | 74 | } |
| 73 | 75 | ||
| 76 | static inline unsigned long kaslr_offset(void) | ||
| 77 | { | ||
| 78 | return (unsigned long)&_text - __START_KERNEL; | ||
| 79 | } | ||
| 80 | |||
| 74 | /* | 81 | /* |
| 75 | * Do NOT EVER look at the BIOS memory size location. | 82 | * Do NOT EVER look at the BIOS memory size location. |
| 76 | * It does not work on many machines. | 83 | * It does not work on many machines. |
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 11546b462fa6..819ab3f9c9c7 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <asm/io_apic.h> | 26 | #include <asm/io_apic.h> |
| 27 | #include <asm/debugreg.h> | 27 | #include <asm/debugreg.h> |
| 28 | #include <asm/kexec-bzimage64.h> | 28 | #include <asm/kexec-bzimage64.h> |
| 29 | #include <asm/setup.h> | ||
| 29 | 30 | ||
| 30 | #ifdef CONFIG_KEXEC_FILE | 31 | #ifdef CONFIG_KEXEC_FILE |
| 31 | static struct kexec_file_ops *kexec_file_loaders[] = { | 32 | static struct kexec_file_ops *kexec_file_loaders[] = { |
| @@ -335,7 +336,7 @@ void arch_crash_save_vmcoreinfo(void) | |||
| 335 | VMCOREINFO_LENGTH(node_data, MAX_NUMNODES); | 336 | VMCOREINFO_LENGTH(node_data, MAX_NUMNODES); |
| 336 | #endif | 337 | #endif |
| 337 | vmcoreinfo_append_str("KERNELOFFSET=%lx\n", | 338 | vmcoreinfo_append_str("KERNELOFFSET=%lx\n", |
| 338 | (unsigned long)&_text - __START_KERNEL); | 339 | kaslr_offset()); |
| 339 | } | 340 | } |
| 340 | 341 | ||
| 341 | /* arch-dependent functionality related to kexec file-based syscall */ | 342 | /* arch-dependent functionality related to kexec file-based syscall */ |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 265a6fdea8b7..39ca113676fe 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
| @@ -836,7 +836,7 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p) | |||
| 836 | { | 836 | { |
| 837 | if (kaslr_enabled()) { | 837 | if (kaslr_enabled()) { |
| 838 | pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n", | 838 | pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n", |
| 839 | (unsigned long)&_text - __START_KERNEL, | 839 | kaslr_offset(), |
| 840 | __START_KERNEL, | 840 | __START_KERNEL, |
| 841 | __START_KERNEL_map, | 841 | __START_KERNEL_map, |
| 842 | MODULES_VADDR-1); | 842 | MODULES_VADDR-1); |
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index ee6dbb39a809..31db7a05dd36 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h | |||
| @@ -99,7 +99,7 @@ struct klp_object { | |||
| 99 | struct klp_func *funcs; | 99 | struct klp_func *funcs; |
| 100 | 100 | ||
| 101 | /* internal */ | 101 | /* internal */ |
| 102 | struct kobject *kobj; | 102 | struct kobject kobj; |
| 103 | struct module *mod; | 103 | struct module *mod; |
| 104 | enum klp_state state; | 104 | enum klp_state state; |
| 105 | }; | 105 | }; |
| @@ -123,6 +123,12 @@ struct klp_patch { | |||
| 123 | enum klp_state state; | 123 | enum klp_state state; |
| 124 | }; | 124 | }; |
| 125 | 125 | ||
| 126 | #define klp_for_each_object(patch, obj) \ | ||
| 127 | for (obj = patch->objs; obj->funcs; obj++) | ||
| 128 | |||
| 129 | #define klp_for_each_func(obj, func) \ | ||
| 130 | for (func = obj->funcs; func->old_name; func++) | ||
| 131 | |||
| 126 | int klp_register_patch(struct klp_patch *); | 132 | int klp_register_patch(struct klp_patch *); |
| 127 | int klp_unregister_patch(struct klp_patch *); | 133 | int klp_unregister_patch(struct klp_patch *); |
| 128 | int klp_enable_patch(struct klp_patch *); | 134 | int klp_enable_patch(struct klp_patch *); |
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 284e2691e380..c40ebcca0495 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
| @@ -128,7 +128,7 @@ static bool klp_is_patch_registered(struct klp_patch *patch) | |||
| 128 | 128 | ||
| 129 | static bool klp_initialized(void) | 129 | static bool klp_initialized(void) |
| 130 | { | 130 | { |
| 131 | return klp_root_kobj; | 131 | return !!klp_root_kobj; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | struct klp_find_arg { | 134 | struct klp_find_arg { |
| @@ -179,7 +179,9 @@ static int klp_find_object_symbol(const char *objname, const char *name, | |||
| 179 | .count = 0 | 179 | .count = 0 |
| 180 | }; | 180 | }; |
| 181 | 181 | ||
| 182 | mutex_lock(&module_mutex); | ||
| 182 | kallsyms_on_each_symbol(klp_find_callback, &args); | 183 | kallsyms_on_each_symbol(klp_find_callback, &args); |
| 184 | mutex_unlock(&module_mutex); | ||
| 183 | 185 | ||
| 184 | if (args.count == 0) | 186 | if (args.count == 0) |
| 185 | pr_err("symbol '%s' not found in symbol table\n", name); | 187 | pr_err("symbol '%s' not found in symbol table\n", name); |
| @@ -219,13 +221,19 @@ static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr) | |||
| 219 | .name = name, | 221 | .name = name, |
| 220 | .addr = addr, | 222 | .addr = addr, |
| 221 | }; | 223 | }; |
| 224 | int ret; | ||
| 222 | 225 | ||
| 223 | if (kallsyms_on_each_symbol(klp_verify_callback, &args)) | 226 | mutex_lock(&module_mutex); |
| 224 | return 0; | 227 | ret = kallsyms_on_each_symbol(klp_verify_callback, &args); |
| 228 | mutex_unlock(&module_mutex); | ||
| 225 | 229 | ||
| 226 | pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n", | 230 | if (!ret) { |
| 227 | name, addr); | 231 | pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n", |
| 228 | return -EINVAL; | 232 | name, addr); |
| 233 | return -EINVAL; | ||
| 234 | } | ||
| 235 | |||
| 236 | return 0; | ||
| 229 | } | 237 | } |
| 230 | 238 | ||
| 231 | static int klp_find_verify_func_addr(struct klp_object *obj, | 239 | static int klp_find_verify_func_addr(struct klp_object *obj, |
| @@ -234,8 +242,9 @@ static int klp_find_verify_func_addr(struct klp_object *obj, | |||
| 234 | int ret; | 242 | int ret; |
| 235 | 243 | ||
| 236 | #if defined(CONFIG_RANDOMIZE_BASE) | 244 | #if defined(CONFIG_RANDOMIZE_BASE) |
| 237 | /* KASLR is enabled, disregard old_addr from user */ | 245 | /* If KASLR has been enabled, adjust old_addr accordingly */ |
| 238 | func->old_addr = 0; | 246 | if (kaslr_enabled() && func->old_addr) |
| 247 | func->old_addr += kaslr_offset(); | ||
| 239 | #endif | 248 | #endif |
| 240 | 249 | ||
| 241 | if (!func->old_addr || klp_is_module(obj)) | 250 | if (!func->old_addr || klp_is_module(obj)) |
| @@ -422,7 +431,7 @@ static void klp_disable_object(struct klp_object *obj) | |||
| 422 | { | 431 | { |
| 423 | struct klp_func *func; | 432 | struct klp_func *func; |
| 424 | 433 | ||
| 425 | for (func = obj->funcs; func->old_name; func++) | 434 | klp_for_each_func(obj, func) |
| 426 | if (func->state == KLP_ENABLED) | 435 | if (func->state == KLP_ENABLED) |
| 427 | klp_disable_func(func); | 436 | klp_disable_func(func); |
| 428 | 437 | ||
| @@ -440,7 +449,7 @@ static int klp_enable_object(struct klp_object *obj) | |||
| 440 | if (WARN_ON(!klp_is_object_loaded(obj))) | 449 | if (WARN_ON(!klp_is_object_loaded(obj))) |
| 441 | return -EINVAL; | 450 | return -EINVAL; |
| 442 | 451 | ||
| 443 | for (func = obj->funcs; func->old_name; func++) { | 452 | klp_for_each_func(obj, func) { |
| 444 | ret = klp_enable_func(func); | 453 | ret = klp_enable_func(func); |
| 445 | if (ret) { | 454 | if (ret) { |
| 446 | klp_disable_object(obj); | 455 | klp_disable_object(obj); |
| @@ -463,7 +472,7 @@ static int __klp_disable_patch(struct klp_patch *patch) | |||
| 463 | 472 | ||
| 464 | pr_notice("disabling patch '%s'\n", patch->mod->name); | 473 | pr_notice("disabling patch '%s'\n", patch->mod->name); |
| 465 | 474 | ||
| 466 | for (obj = patch->objs; obj->funcs; obj++) { | 475 | klp_for_each_object(patch, obj) { |
| 467 | if (obj->state == KLP_ENABLED) | 476 | if (obj->state == KLP_ENABLED) |
| 468 | klp_disable_object(obj); | 477 | klp_disable_object(obj); |
| 469 | } | 478 | } |
| @@ -523,7 +532,7 @@ static int __klp_enable_patch(struct klp_patch *patch) | |||
| 523 | 532 | ||
| 524 | pr_notice("enabling patch '%s'\n", patch->mod->name); | 533 | pr_notice("enabling patch '%s'\n", patch->mod->name); |
| 525 | 534 | ||
| 526 | for (obj = patch->objs; obj->funcs; obj++) { | 535 | klp_for_each_object(patch, obj) { |
| 527 | if (!klp_is_object_loaded(obj)) | 536 | if (!klp_is_object_loaded(obj)) |
| 528 | continue; | 537 | continue; |
| 529 | 538 | ||
| @@ -651,6 +660,15 @@ static struct kobj_type klp_ktype_patch = { | |||
| 651 | .default_attrs = klp_patch_attrs, | 660 | .default_attrs = klp_patch_attrs, |
| 652 | }; | 661 | }; |
| 653 | 662 | ||
| 663 | static void klp_kobj_release_object(struct kobject *kobj) | ||
| 664 | { | ||
| 665 | } | ||
| 666 | |||
| 667 | static struct kobj_type klp_ktype_object = { | ||
| 668 | .release = klp_kobj_release_object, | ||
| 669 | .sysfs_ops = &kobj_sysfs_ops, | ||
| 670 | }; | ||
| 671 | |||
| 654 | static void klp_kobj_release_func(struct kobject *kobj) | 672 | static void klp_kobj_release_func(struct kobject *kobj) |
| 655 | { | 673 | { |
| 656 | } | 674 | } |
| @@ -680,7 +698,7 @@ static void klp_free_object_loaded(struct klp_object *obj) | |||
| 680 | 698 | ||
| 681 | obj->mod = NULL; | 699 | obj->mod = NULL; |
| 682 | 700 | ||
| 683 | for (func = obj->funcs; func->old_name; func++) | 701 | klp_for_each_func(obj, func) |
| 684 | func->old_addr = 0; | 702 | func->old_addr = 0; |
| 685 | } | 703 | } |
| 686 | 704 | ||
| @@ -695,7 +713,7 @@ static void klp_free_objects_limited(struct klp_patch *patch, | |||
| 695 | 713 | ||
| 696 | for (obj = patch->objs; obj->funcs && obj != limit; obj++) { | 714 | for (obj = patch->objs; obj->funcs && obj != limit; obj++) { |
| 697 | klp_free_funcs_limited(obj, NULL); | 715 | klp_free_funcs_limited(obj, NULL); |
| 698 | kobject_put(obj->kobj); | 716 | kobject_put(&obj->kobj); |
| 699 | } | 717 | } |
| 700 | } | 718 | } |
| 701 | 719 | ||
| @@ -713,7 +731,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) | |||
| 713 | func->state = KLP_DISABLED; | 731 | func->state = KLP_DISABLED; |
| 714 | 732 | ||
| 715 | return kobject_init_and_add(&func->kobj, &klp_ktype_func, | 733 | return kobject_init_and_add(&func->kobj, &klp_ktype_func, |
| 716 | obj->kobj, "%s", func->old_name); | 734 | &obj->kobj, "%s", func->old_name); |
| 717 | } | 735 | } |
| 718 | 736 | ||
| 719 | /* parts of the initialization that is done only when the object is loaded */ | 737 | /* parts of the initialization that is done only when the object is loaded */ |
| @@ -729,7 +747,7 @@ static int klp_init_object_loaded(struct klp_patch *patch, | |||
| 729 | return ret; | 747 | return ret; |
| 730 | } | 748 | } |
| 731 | 749 | ||
| 732 | for (func = obj->funcs; func->old_name; func++) { | 750 | klp_for_each_func(obj, func) { |
| 733 | ret = klp_find_verify_func_addr(obj, func); | 751 | ret = klp_find_verify_func_addr(obj, func); |
| 734 | if (ret) | 752 | if (ret) |
| 735 | return ret; | 753 | return ret; |
| @@ -753,11 +771,12 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) | |||
| 753 | klp_find_object_module(obj); | 771 | klp_find_object_module(obj); |
| 754 | 772 | ||
| 755 | name = klp_is_module(obj) ? obj->name : "vmlinux"; | 773 | name = klp_is_module(obj) ? obj->name : "vmlinux"; |
| 756 | obj->kobj = kobject_create_and_add(name, &patch->kobj); | 774 | ret = kobject_init_and_add(&obj->kobj, &klp_ktype_object, |
| 757 | if (!obj->kobj) | 775 | &patch->kobj, "%s", name); |
| 758 | return -ENOMEM; | 776 | if (ret) |
| 777 | return ret; | ||
| 759 | 778 | ||
| 760 | for (func = obj->funcs; func->old_name; func++) { | 779 | klp_for_each_func(obj, func) { |
| 761 | ret = klp_init_func(obj, func); | 780 | ret = klp_init_func(obj, func); |
| 762 | if (ret) | 781 | if (ret) |
| 763 | goto free; | 782 | goto free; |
| @@ -773,7 +792,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) | |||
| 773 | 792 | ||
| 774 | free: | 793 | free: |
| 775 | klp_free_funcs_limited(obj, func); | 794 | klp_free_funcs_limited(obj, func); |
| 776 | kobject_put(obj->kobj); | 795 | kobject_put(&obj->kobj); |
| 777 | return ret; | 796 | return ret; |
| 778 | } | 797 | } |
| 779 | 798 | ||
| @@ -794,7 +813,7 @@ static int klp_init_patch(struct klp_patch *patch) | |||
| 794 | if (ret) | 813 | if (ret) |
| 795 | goto unlock; | 814 | goto unlock; |
| 796 | 815 | ||
| 797 | for (obj = patch->objs; obj->funcs; obj++) { | 816 | klp_for_each_object(patch, obj) { |
| 798 | ret = klp_init_object(patch, obj); | 817 | ret = klp_init_object(patch, obj); |
| 799 | if (ret) | 818 | if (ret) |
| 800 | goto free; | 819 | goto free; |
| @@ -883,7 +902,7 @@ int klp_register_patch(struct klp_patch *patch) | |||
| 883 | } | 902 | } |
| 884 | EXPORT_SYMBOL_GPL(klp_register_patch); | 903 | EXPORT_SYMBOL_GPL(klp_register_patch); |
| 885 | 904 | ||
| 886 | static void klp_module_notify_coming(struct klp_patch *patch, | 905 | static int klp_module_notify_coming(struct klp_patch *patch, |
| 887 | struct klp_object *obj) | 906 | struct klp_object *obj) |
| 888 | { | 907 | { |
| 889 | struct module *pmod = patch->mod; | 908 | struct module *pmod = patch->mod; |
| @@ -891,22 +910,23 @@ static void klp_module_notify_coming(struct klp_patch *patch, | |||
| 891 | int ret; | 910 | int ret; |
| 892 | 911 | ||
| 893 | ret = klp_init_object_loaded(patch, obj); | 912 | ret = klp_init_object_loaded(patch, obj); |
| 894 | if (ret) | 913 | if (ret) { |
| 895 | goto err; | 914 | pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n", |
| 915 | pmod->name, mod->name, ret); | ||
| 916 | return ret; | ||
| 917 | } | ||
| 896 | 918 | ||
| 897 | if (patch->state == KLP_DISABLED) | 919 | if (patch->state == KLP_DISABLED) |
| 898 | return; | 920 | return 0; |
| 899 | 921 | ||
| 900 | pr_notice("applying patch '%s' to loading module '%s'\n", | 922 | pr_notice("applying patch '%s' to loading module '%s'\n", |
| 901 | pmod->name, mod->name); | 923 | pmod->name, mod->name); |
| 902 | 924 | ||
| 903 | ret = klp_enable_object(obj); | 925 | ret = klp_enable_object(obj); |
| 904 | if (!ret) | 926 | if (ret) |
| 905 | return; | 927 | pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", |
| 906 | 928 | pmod->name, mod->name, ret); | |
| 907 | err: | 929 | return ret; |
| 908 | pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", | ||
| 909 | pmod->name, mod->name, ret); | ||
| 910 | } | 930 | } |
| 911 | 931 | ||
| 912 | static void klp_module_notify_going(struct klp_patch *patch, | 932 | static void klp_module_notify_going(struct klp_patch *patch, |
| @@ -930,6 +950,7 @@ disabled: | |||
| 930 | static int klp_module_notify(struct notifier_block *nb, unsigned long action, | 950 | static int klp_module_notify(struct notifier_block *nb, unsigned long action, |
| 931 | void *data) | 951 | void *data) |
| 932 | { | 952 | { |
| 953 | int ret; | ||
| 933 | struct module *mod = data; | 954 | struct module *mod = data; |
| 934 | struct klp_patch *patch; | 955 | struct klp_patch *patch; |
| 935 | struct klp_object *obj; | 956 | struct klp_object *obj; |
| @@ -949,13 +970,18 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action, | |||
| 949 | mod->klp_alive = false; | 970 | mod->klp_alive = false; |
| 950 | 971 | ||
| 951 | list_for_each_entry(patch, &klp_patches, list) { | 972 | list_for_each_entry(patch, &klp_patches, list) { |
| 952 | for (obj = patch->objs; obj->funcs; obj++) { | 973 | klp_for_each_object(patch, obj) { |
| 953 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) | 974 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) |
| 954 | continue; | 975 | continue; |
| 955 | 976 | ||
| 956 | if (action == MODULE_STATE_COMING) { | 977 | if (action == MODULE_STATE_COMING) { |
| 957 | obj->mod = mod; | 978 | obj->mod = mod; |
| 958 | klp_module_notify_coming(patch, obj); | 979 | ret = klp_module_notify_coming(patch, obj); |
| 980 | if (ret) { | ||
| 981 | obj->mod = NULL; | ||
| 982 | pr_warn("patch '%s' is in an inconsistent state!\n", | ||
| 983 | patch->mod->name); | ||
| 984 | } | ||
| 959 | } else /* MODULE_STATE_GOING */ | 985 | } else /* MODULE_STATE_GOING */ |
| 960 | klp_module_notify_going(patch, obj); | 986 | klp_module_notify_going(patch, obj); |
| 961 | 987 | ||
| @@ -973,7 +999,7 @@ static struct notifier_block klp_module_nb = { | |||
| 973 | .priority = INT_MIN+1, /* called late but before ftrace notifier */ | 999 | .priority = INT_MIN+1, /* called late but before ftrace notifier */ |
| 974 | }; | 1000 | }; |
| 975 | 1001 | ||
| 976 | static int klp_init(void) | 1002 | static int __init klp_init(void) |
| 977 | { | 1003 | { |
| 978 | int ret; | 1004 | int ret; |
| 979 | 1005 | ||
