Skip to content

Commit 0dade9f

Browse files
jpoimboeJiri Kosina
authored andcommitted
livepatch: separate enabled and patched states
Once we have a consistency model, patches and their objects will be enabled and disabled at different times. For example, when a patch is disabled, its loaded objects' funcs can remain registered with ftrace indefinitely until the unpatching operation is complete and they're no longer in use. It's less confusing if we give them different names: patches can be enabled or disabled; objects (and their funcs) can be patched or unpatched: - Enabled means that a patch is logically enabled (but not necessarily fully applied). - Patched means that an object's funcs are registered with ftrace and added to the klp_ops func stack. Also, since these states are binary, represent them with booleans instead of ints. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Reviewed-by: Petr Mladek <pmladek@suse.com> Reviewed-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 2f09ca6 commit 0dade9f

2 files changed

Lines changed: 42 additions & 47 deletions

File tree

include/linux/livepatch.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@
2828

2929
#include <asm/livepatch.h>
3030

31-
enum klp_state {
32-
KLP_DISABLED,
33-
KLP_ENABLED
34-
};
35-
3631
/**
3732
* struct klp_func - function structure for live patching
3833
* @old_name: name of the function to be patched
@@ -41,8 +36,8 @@ enum klp_state {
4136
* can be found (optional)
4237
* @old_addr: the address of the function being patched
4338
* @kobj: kobject for sysfs resources
44-
* @state: tracks function-level patch application state
4539
* @stack_node: list node for klp_ops func_stack list
40+
* @patched: the func has been added to the klp_ops list
4641
*/
4742
struct klp_func {
4843
/* external */
@@ -60,8 +55,8 @@ struct klp_func {
6055
/* internal */
6156
unsigned long old_addr;
6257
struct kobject kobj;
63-
enum klp_state state;
6458
struct list_head stack_node;
59+
bool patched;
6560
};
6661

6762
/**
@@ -71,7 +66,7 @@ struct klp_func {
7166
* @kobj: kobject for sysfs resources
7267
* @mod: kernel module associated with the patched object
7368
* (NULL for vmlinux)
74-
* @state: tracks object-level patch application state
69+
* @patched: the object's funcs have been added to the klp_ops list
7570
*/
7671
struct klp_object {
7772
/* external */
@@ -81,7 +76,7 @@ struct klp_object {
8176
/* internal */
8277
struct kobject kobj;
8378
struct module *mod;
84-
enum klp_state state;
79+
bool patched;
8580
};
8681

8782
/**
@@ -90,7 +85,7 @@ struct klp_object {
9085
* @objs: object entries for kernel objects to be patched
9186
* @list: list node for global list of registered patches
9287
* @kobj: kobject for sysfs resources
93-
* @state: tracks patch-level application state
88+
* @enabled: the patch is enabled (but operation may be incomplete)
9489
*/
9590
struct klp_patch {
9691
/* external */
@@ -100,7 +95,7 @@ struct klp_patch {
10095
/* internal */
10196
struct list_head list;
10297
struct kobject kobj;
103-
enum klp_state state;
98+
bool enabled;
10499
};
105100

106101
#define klp_for_each_object(patch, obj) \

kernel/livepatch/core.c

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,11 @@ static unsigned long klp_get_ftrace_location(unsigned long faddr)
348348
}
349349
#endif
350350

351-
static void klp_disable_func(struct klp_func *func)
351+
static void klp_unpatch_func(struct klp_func *func)
352352
{
353353
struct klp_ops *ops;
354354

355-
if (WARN_ON(func->state != KLP_ENABLED))
355+
if (WARN_ON(!func->patched))
356356
return;
357357
if (WARN_ON(!func->old_addr))
358358
return;
@@ -378,18 +378,18 @@ static void klp_disable_func(struct klp_func *func)
378378
list_del_rcu(&func->stack_node);
379379
}
380380

381-
func->state = KLP_DISABLED;
381+
func->patched = false;
382382
}
383383

384-
static int klp_enable_func(struct klp_func *func)
384+
static int klp_patch_func(struct klp_func *func)
385385
{
386386
struct klp_ops *ops;
387387
int ret;
388388

389389
if (WARN_ON(!func->old_addr))
390390
return -EINVAL;
391391

392-
if (WARN_ON(func->state != KLP_DISABLED))
392+
if (WARN_ON(func->patched))
393393
return -EINVAL;
394394

395395
ops = klp_find_ops(func->old_addr);
@@ -437,7 +437,7 @@ static int klp_enable_func(struct klp_func *func)
437437
list_add_rcu(&func->stack_node, &ops->func_stack);
438438
}
439439

440-
func->state = KLP_ENABLED;
440+
func->patched = true;
441441

442442
return 0;
443443

@@ -448,36 +448,36 @@ static int klp_enable_func(struct klp_func *func)
448448
return ret;
449449
}
450450

451-
static void klp_disable_object(struct klp_object *obj)
451+
static void klp_unpatch_object(struct klp_object *obj)
452452
{
453453
struct klp_func *func;
454454

455455
klp_for_each_func(obj, func)
456-
if (func->state == KLP_ENABLED)
457-
klp_disable_func(func);
456+
if (func->patched)
457+
klp_unpatch_func(func);
458458

459-
obj->state = KLP_DISABLED;
459+
obj->patched = false;
460460
}
461461

462-
static int klp_enable_object(struct klp_object *obj)
462+
static int klp_patch_object(struct klp_object *obj)
463463
{
464464
struct klp_func *func;
465465
int ret;
466466

467-
if (WARN_ON(obj->state != KLP_DISABLED))
467+
if (WARN_ON(obj->patched))
468468
return -EINVAL;
469469

470470
if (WARN_ON(!klp_is_object_loaded(obj)))
471471
return -EINVAL;
472472

473473
klp_for_each_func(obj, func) {
474-
ret = klp_enable_func(func);
474+
ret = klp_patch_func(func);
475475
if (ret) {
476-
klp_disable_object(obj);
476+
klp_unpatch_object(obj);
477477
return ret;
478478
}
479479
}
480-
obj->state = KLP_ENABLED;
480+
obj->patched = true;
481481

482482
return 0;
483483
}
@@ -488,17 +488,17 @@ static int __klp_disable_patch(struct klp_patch *patch)
488488

489489
/* enforce stacking: only the last enabled patch can be disabled */
490490
if (!list_is_last(&patch->list, &klp_patches) &&
491-
list_next_entry(patch, list)->state == KLP_ENABLED)
491+
list_next_entry(patch, list)->enabled)
492492
return -EBUSY;
493493

494494
pr_notice("disabling patch '%s'\n", patch->mod->name);
495495

496496
klp_for_each_object(patch, obj) {
497-
if (obj->state == KLP_ENABLED)
498-
klp_disable_object(obj);
497+
if (obj->patched)
498+
klp_unpatch_object(obj);
499499
}
500500

501-
patch->state = KLP_DISABLED;
501+
patch->enabled = false;
502502

503503
return 0;
504504
}
@@ -522,7 +522,7 @@ int klp_disable_patch(struct klp_patch *patch)
522522
goto err;
523523
}
524524

525-
if (patch->state == KLP_DISABLED) {
525+
if (!patch->enabled) {
526526
ret = -EINVAL;
527527
goto err;
528528
}
@@ -540,12 +540,12 @@ static int __klp_enable_patch(struct klp_patch *patch)
540540
struct klp_object *obj;
541541
int ret;
542542

543-
if (WARN_ON(patch->state != KLP_DISABLED))
543+
if (WARN_ON(patch->enabled))
544544
return -EINVAL;
545545

546546
/* enforce stacking: only the first disabled patch can be enabled */
547547
if (patch->list.prev != &klp_patches &&
548-
list_prev_entry(patch, list)->state == KLP_DISABLED)
548+
!list_prev_entry(patch, list)->enabled)
549549
return -EBUSY;
550550

551551
pr_notice("enabling patch '%s'\n", patch->mod->name);
@@ -554,12 +554,12 @@ static int __klp_enable_patch(struct klp_patch *patch)
554554
if (!klp_is_object_loaded(obj))
555555
continue;
556556

557-
ret = klp_enable_object(obj);
557+
ret = klp_patch_object(obj);
558558
if (ret)
559559
goto unregister;
560560
}
561561

562-
patch->state = KLP_ENABLED;
562+
patch->enabled = true;
563563

564564
return 0;
565565

@@ -617,20 +617,20 @@ static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
617617
if (ret)
618618
return -EINVAL;
619619

620-
if (val != KLP_DISABLED && val != KLP_ENABLED)
620+
if (val > 1)
621621
return -EINVAL;
622622

623623
patch = container_of(kobj, struct klp_patch, kobj);
624624

625625
mutex_lock(&klp_mutex);
626626

627-
if (val == patch->state) {
627+
if (patch->enabled == val) {
628628
/* already in requested state */
629629
ret = -EINVAL;
630630
goto err;
631631
}
632632

633-
if (val == KLP_ENABLED) {
633+
if (val) {
634634
ret = __klp_enable_patch(patch);
635635
if (ret)
636636
goto err;
@@ -655,7 +655,7 @@ static ssize_t enabled_show(struct kobject *kobj,
655655
struct klp_patch *patch;
656656

657657
patch = container_of(kobj, struct klp_patch, kobj);
658-
return snprintf(buf, PAGE_SIZE-1, "%d\n", patch->state);
658+
return snprintf(buf, PAGE_SIZE-1, "%d\n", patch->enabled);
659659
}
660660

661661
static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
@@ -749,7 +749,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
749749
return -EINVAL;
750750

751751
INIT_LIST_HEAD(&func->stack_node);
752-
func->state = KLP_DISABLED;
752+
func->patched = false;
753753

754754
/* The format for the sysfs directory is <function,sympos> where sympos
755755
* is the nth occurrence of this symbol in kallsyms for the patched
@@ -804,7 +804,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
804804
if (!obj->funcs)
805805
return -EINVAL;
806806

807-
obj->state = KLP_DISABLED;
807+
obj->patched = false;
808808
obj->mod = NULL;
809809

810810
klp_find_object_module(obj);
@@ -845,7 +845,7 @@ static int klp_init_patch(struct klp_patch *patch)
845845

846846
mutex_lock(&klp_mutex);
847847

848-
patch->state = KLP_DISABLED;
848+
patch->enabled = false;
849849

850850
ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch,
851851
klp_root_kobj, "%s", patch->mod->name);
@@ -891,7 +891,7 @@ int klp_unregister_patch(struct klp_patch *patch)
891891
goto out;
892892
}
893893

894-
if (patch->state == KLP_ENABLED) {
894+
if (patch->enabled) {
895895
ret = -EBUSY;
896896
goto out;
897897
}
@@ -978,13 +978,13 @@ int klp_module_coming(struct module *mod)
978978
goto err;
979979
}
980980

981-
if (patch->state == KLP_DISABLED)
981+
if (!patch->enabled)
982982
break;
983983

984984
pr_notice("applying patch '%s' to loading module '%s'\n",
985985
patch->mod->name, obj->mod->name);
986986

987-
ret = klp_enable_object(obj);
987+
ret = klp_patch_object(obj);
988988
if (ret) {
989989
pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
990990
patch->mod->name, obj->mod->name, ret);
@@ -1035,10 +1035,10 @@ void klp_module_going(struct module *mod)
10351035
if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
10361036
continue;
10371037

1038-
if (patch->state != KLP_DISABLED) {
1038+
if (patch->enabled) {
10391039
pr_notice("reverting patch '%s' on unloading module '%s'\n",
10401040
patch->mod->name, obj->mod->name);
1041-
klp_disable_object(obj);
1041+
klp_unpatch_object(obj);
10421042
}
10431043

10441044
klp_free_object_loaded(obj);

0 commit comments

Comments
 (0)