diff options
Diffstat (limited to 'kernel/livepatch')
| -rw-r--r-- | kernel/livepatch/core.c | 80 | ||||
| -rw-r--r-- | kernel/livepatch/transition.c | 37 |
2 files changed, 84 insertions, 33 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 3dc3c9049690..6844c1213df8 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/livepatch.h> | 29 | #include <linux/livepatch.h> |
| 30 | #include <linux/elf.h> | 30 | #include <linux/elf.h> |
| 31 | #include <linux/moduleloader.h> | 31 | #include <linux/moduleloader.h> |
| 32 | #include <linux/completion.h> | ||
| 32 | #include <asm/cacheflush.h> | 33 | #include <asm/cacheflush.h> |
| 33 | #include "patch.h" | 34 | #include "patch.h" |
| 34 | #include "transition.h" | 35 | #include "transition.h" |
| @@ -354,6 +355,18 @@ static int __klp_enable_patch(struct klp_patch *patch) | |||
| 354 | !list_prev_entry(patch, list)->enabled) | 355 | !list_prev_entry(patch, list)->enabled) |
| 355 | return -EBUSY; | 356 | return -EBUSY; |
| 356 | 357 | ||
| 358 | /* | ||
| 359 | * A reference is taken on the patch module to prevent it from being | ||
| 360 | * unloaded. | ||
| 361 | * | ||
| 362 | * Note: For immediate (no consistency model) patches we don't allow | ||
| 363 | * patch modules to unload since there is no safe/sane method to | ||
| 364 | * determine if a thread is still running in the patched code contained | ||
| 365 | * in the patch module once the ftrace registration is successful. | ||
| 366 | */ | ||
| 367 | if (!try_module_get(patch->mod)) | ||
| 368 | return -ENODEV; | ||
| 369 | |||
| 357 | pr_notice("enabling patch '%s'\n", patch->mod->name); | 370 | pr_notice("enabling patch '%s'\n", patch->mod->name); |
| 358 | 371 | ||
| 359 | klp_init_transition(patch, KLP_PATCHED); | 372 | klp_init_transition(patch, KLP_PATCHED); |
| @@ -442,6 +455,15 @@ static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
| 442 | 455 | ||
| 443 | mutex_lock(&klp_mutex); | 456 | mutex_lock(&klp_mutex); |
| 444 | 457 | ||
| 458 | if (!klp_is_patch_registered(patch)) { | ||
| 459 | /* | ||
| 460 | * Module with the patch could either disappear meanwhile or is | ||
| 461 | * not properly initialized yet. | ||
| 462 | */ | ||
| 463 | ret = -EINVAL; | ||
| 464 | goto err; | ||
| 465 | } | ||
| 466 | |||
| 445 | if (patch->enabled == enabled) { | 467 | if (patch->enabled == enabled) { |
| 446 | /* already in requested state */ | 468 | /* already in requested state */ |
| 447 | ret = -EINVAL; | 469 | ret = -EINVAL; |
| @@ -498,10 +520,10 @@ static struct attribute *klp_patch_attrs[] = { | |||
| 498 | 520 | ||
| 499 | static void klp_kobj_release_patch(struct kobject *kobj) | 521 | static void klp_kobj_release_patch(struct kobject *kobj) |
| 500 | { | 522 | { |
| 501 | /* | 523 | struct klp_patch *patch; |
| 502 | * Once we have a consistency model we'll need to module_put() the | 524 | |
| 503 | * patch module here. See klp_register_patch() for more details. | 525 | patch = container_of(kobj, struct klp_patch, kobj); |
| 504 | */ | 526 | complete(&patch->finish); |
| 505 | } | 527 | } |
| 506 | 528 | ||
| 507 | static struct kobj_type klp_ktype_patch = { | 529 | static struct kobj_type klp_ktype_patch = { |
| @@ -572,7 +594,6 @@ static void klp_free_patch(struct klp_patch *patch) | |||
| 572 | klp_free_objects_limited(patch, NULL); | 594 | klp_free_objects_limited(patch, NULL); |
| 573 | if (!list_empty(&patch->list)) | 595 | if (!list_empty(&patch->list)) |
| 574 | list_del(&patch->list); | 596 | list_del(&patch->list); |
| 575 | kobject_put(&patch->kobj); | ||
| 576 | } | 597 | } |
| 577 | 598 | ||
| 578 | static int klp_init_func(struct klp_object *obj, struct klp_func *func) | 599 | static int klp_init_func(struct klp_object *obj, struct klp_func *func) |
| @@ -695,11 +716,14 @@ static int klp_init_patch(struct klp_patch *patch) | |||
| 695 | mutex_lock(&klp_mutex); | 716 | mutex_lock(&klp_mutex); |
| 696 | 717 | ||
| 697 | patch->enabled = false; | 718 | patch->enabled = false; |
| 719 | init_completion(&patch->finish); | ||
| 698 | 720 | ||
| 699 | ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch, | 721 | ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch, |
| 700 | klp_root_kobj, "%s", patch->mod->name); | 722 | klp_root_kobj, "%s", patch->mod->name); |
| 701 | if (ret) | 723 | if (ret) { |
| 702 | goto unlock; | 724 | mutex_unlock(&klp_mutex); |
| 725 | return ret; | ||
| 726 | } | ||
| 703 | 727 | ||
| 704 | klp_for_each_object(patch, obj) { | 728 | klp_for_each_object(patch, obj) { |
| 705 | ret = klp_init_object(patch, obj); | 729 | ret = klp_init_object(patch, obj); |
| @@ -715,9 +739,12 @@ static int klp_init_patch(struct klp_patch *patch) | |||
| 715 | 739 | ||
| 716 | free: | 740 | free: |
| 717 | klp_free_objects_limited(patch, obj); | 741 | klp_free_objects_limited(patch, obj); |
| 718 | kobject_put(&patch->kobj); | 742 | |
| 719 | unlock: | ||
| 720 | mutex_unlock(&klp_mutex); | 743 | mutex_unlock(&klp_mutex); |
| 744 | |||
| 745 | kobject_put(&patch->kobj); | ||
| 746 | wait_for_completion(&patch->finish); | ||
| 747 | |||
| 721 | return ret; | 748 | return ret; |
| 722 | } | 749 | } |
| 723 | 750 | ||
| @@ -731,23 +758,29 @@ unlock: | |||
| 731 | */ | 758 | */ |
| 732 | int klp_unregister_patch(struct klp_patch *patch) | 759 | int klp_unregister_patch(struct klp_patch *patch) |
| 733 | { | 760 | { |
| 734 | int ret = 0; | 761 | int ret; |
| 735 | 762 | ||
| 736 | mutex_lock(&klp_mutex); | 763 | mutex_lock(&klp_mutex); |
| 737 | 764 | ||
| 738 | if (!klp_is_patch_registered(patch)) { | 765 | if (!klp_is_patch_registered(patch)) { |
| 739 | ret = -EINVAL; | 766 | ret = -EINVAL; |
| 740 | goto out; | 767 | goto err; |
| 741 | } | 768 | } |
| 742 | 769 | ||
| 743 | if (patch->enabled) { | 770 | if (patch->enabled) { |
| 744 | ret = -EBUSY; | 771 | ret = -EBUSY; |
| 745 | goto out; | 772 | goto err; |
| 746 | } | 773 | } |
| 747 | 774 | ||
| 748 | klp_free_patch(patch); | 775 | klp_free_patch(patch); |
| 749 | 776 | ||
| 750 | out: | 777 | mutex_unlock(&klp_mutex); |
| 778 | |||
| 779 | kobject_put(&patch->kobj); | ||
| 780 | wait_for_completion(&patch->finish); | ||
| 781 | |||
| 782 | return 0; | ||
| 783 | err: | ||
| 751 | mutex_unlock(&klp_mutex); | 784 | mutex_unlock(&klp_mutex); |
| 752 | return ret; | 785 | return ret; |
| 753 | } | 786 | } |
| @@ -760,12 +793,13 @@ EXPORT_SYMBOL_GPL(klp_unregister_patch); | |||
| 760 | * Initializes the data structure associated with the patch and | 793 | * Initializes the data structure associated with the patch and |
| 761 | * creates the sysfs interface. | 794 | * creates the sysfs interface. |
| 762 | * | 795 | * |
| 796 | * There is no need to take the reference on the patch module here. It is done | ||
| 797 | * later when the patch is enabled. | ||
| 798 | * | ||
| 763 | * Return: 0 on success, otherwise error | 799 | * Return: 0 on success, otherwise error |
| 764 | */ | 800 | */ |
| 765 | int klp_register_patch(struct klp_patch *patch) | 801 | int klp_register_patch(struct klp_patch *patch) |
| 766 | { | 802 | { |
| 767 | int ret; | ||
| 768 | |||
| 769 | if (!patch || !patch->mod) | 803 | if (!patch || !patch->mod) |
| 770 | return -EINVAL; | 804 | return -EINVAL; |
| 771 | 805 | ||
| @@ -788,21 +822,7 @@ int klp_register_patch(struct klp_patch *patch) | |||
| 788 | return -ENOSYS; | 822 | return -ENOSYS; |
| 789 | } | 823 | } |
| 790 | 824 | ||
| 791 | /* | 825 | return klp_init_patch(patch); |
| 792 | * A reference is taken on the patch module to prevent it from being | ||
| 793 | * unloaded. Right now, we don't allow patch modules to unload since | ||
| 794 | * there is currently no method to determine if a thread is still | ||
| 795 | * running in the patched code contained in the patch module once | ||
| 796 | * the ftrace registration is successful. | ||
| 797 | */ | ||
| 798 | if (!try_module_get(patch->mod)) | ||
| 799 | return -ENODEV; | ||
| 800 | |||
| 801 | ret = klp_init_patch(patch); | ||
| 802 | if (ret) | ||
| 803 | module_put(patch->mod); | ||
| 804 | |||
| 805 | return ret; | ||
| 806 | } | 826 | } |
| 807 | EXPORT_SYMBOL_GPL(klp_register_patch); | 827 | EXPORT_SYMBOL_GPL(klp_register_patch); |
| 808 | 828 | ||
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index 428533ec51b5..0ab7abd53b0b 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c | |||
| @@ -59,6 +59,7 @@ static void klp_complete_transition(void) | |||
| 59 | struct klp_func *func; | 59 | struct klp_func *func; |
| 60 | struct task_struct *g, *task; | 60 | struct task_struct *g, *task; |
| 61 | unsigned int cpu; | 61 | unsigned int cpu; |
| 62 | bool immediate_func = false; | ||
| 62 | 63 | ||
| 63 | if (klp_target_state == KLP_UNPATCHED) { | 64 | if (klp_target_state == KLP_UNPATCHED) { |
| 64 | /* | 65 | /* |
| @@ -79,9 +80,16 @@ static void klp_complete_transition(void) | |||
| 79 | if (klp_transition_patch->immediate) | 80 | if (klp_transition_patch->immediate) |
| 80 | goto done; | 81 | goto done; |
| 81 | 82 | ||
| 82 | klp_for_each_object(klp_transition_patch, obj) | 83 | klp_for_each_object(klp_transition_patch, obj) { |
| 83 | klp_for_each_func(obj, func) | 84 | klp_for_each_func(obj, func) { |
| 84 | func->transition = false; | 85 | func->transition = false; |
| 86 | if (func->immediate) | ||
| 87 | immediate_func = true; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | if (klp_target_state == KLP_UNPATCHED && !immediate_func) | ||
| 92 | module_put(klp_transition_patch->mod); | ||
| 85 | 93 | ||
| 86 | /* Prevent klp_ftrace_handler() from seeing KLP_UNDEFINED state */ | 94 | /* Prevent klp_ftrace_handler() from seeing KLP_UNDEFINED state */ |
| 87 | if (klp_target_state == KLP_PATCHED) | 95 | if (klp_target_state == KLP_PATCHED) |
| @@ -113,8 +121,31 @@ done: | |||
| 113 | */ | 121 | */ |
| 114 | void klp_cancel_transition(void) | 122 | void klp_cancel_transition(void) |
| 115 | { | 123 | { |
| 116 | klp_target_state = !klp_target_state; | 124 | struct klp_patch *patch = klp_transition_patch; |
| 125 | struct klp_object *obj; | ||
| 126 | struct klp_func *func; | ||
| 127 | bool immediate_func = false; | ||
| 128 | |||
| 129 | if (WARN_ON_ONCE(klp_target_state != KLP_PATCHED)) | ||
| 130 | return; | ||
| 131 | |||
| 132 | klp_target_state = KLP_UNPATCHED; | ||
| 117 | klp_complete_transition(); | 133 | klp_complete_transition(); |
| 134 | |||
| 135 | /* | ||
| 136 | * In the enable error path, even immediate patches can be safely | ||
| 137 | * removed because the transition hasn't been started yet. | ||
| 138 | * | ||
| 139 | * klp_complete_transition() doesn't have a module_put() for immediate | ||
| 140 | * patches, so do it here. | ||
| 141 | */ | ||
| 142 | klp_for_each_object(patch, obj) | ||
| 143 | klp_for_each_func(obj, func) | ||
| 144 | if (func->immediate) | ||
| 145 | immediate_func = true; | ||
| 146 | |||
| 147 | if (patch->immediate || immediate_func) | ||
| 148 | module_put(patch->mod); | ||
| 118 | } | 149 | } |
| 119 | 150 | ||
| 120 | /* | 151 | /* |
