diff options
Diffstat (limited to 'kernel/livepatch/core.c')
| -rw-r--r-- | kernel/livepatch/core.c | 99 |
1 files changed, 43 insertions, 56 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 01ca08804f51..284e2691e380 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
| @@ -89,16 +89,28 @@ static bool klp_is_object_loaded(struct klp_object *obj) | |||
| 89 | /* sets obj->mod if object is not vmlinux and module is found */ | 89 | /* sets obj->mod if object is not vmlinux and module is found */ |
| 90 | static void klp_find_object_module(struct klp_object *obj) | 90 | static void klp_find_object_module(struct klp_object *obj) |
| 91 | { | 91 | { |
| 92 | struct module *mod; | ||
| 93 | |||
| 92 | if (!klp_is_module(obj)) | 94 | if (!klp_is_module(obj)) |
| 93 | return; | 95 | return; |
| 94 | 96 | ||
| 95 | mutex_lock(&module_mutex); | 97 | mutex_lock(&module_mutex); |
| 96 | /* | 98 | /* |
| 97 | * We don't need to take a reference on the module here because we have | 99 | * We do not want to block removal of patched modules and therefore |
| 98 | * the klp_mutex, which is also taken by the module notifier. This | 100 | * we do not take a reference here. The patches are removed by |
| 99 | * prevents any module from unloading until we release the klp_mutex. | 101 | * a going module handler instead. |
| 102 | */ | ||
| 103 | mod = find_module(obj->name); | ||
| 104 | /* | ||
| 105 | * Do not mess work of the module coming and going notifiers. | ||
| 106 | * Note that the patch might still be needed before the going handler | ||
| 107 | * is called. Module functions can be called even in the GOING state | ||
| 108 | * until mod->exit() finishes. This is especially important for | ||
| 109 | * patches that modify semantic of the functions. | ||
| 100 | */ | 110 | */ |
| 101 | obj->mod = find_module(obj->name); | 111 | if (mod && mod->klp_alive) |
| 112 | obj->mod = mod; | ||
| 113 | |||
| 102 | mutex_unlock(&module_mutex); | 114 | mutex_unlock(&module_mutex); |
| 103 | } | 115 | } |
| 104 | 116 | ||
| @@ -323,32 +335,20 @@ unlock: | |||
| 323 | rcu_read_unlock(); | 335 | rcu_read_unlock(); |
| 324 | } | 336 | } |
| 325 | 337 | ||
| 326 | static int klp_disable_func(struct klp_func *func) | 338 | static void klp_disable_func(struct klp_func *func) |
| 327 | { | 339 | { |
| 328 | struct klp_ops *ops; | 340 | struct klp_ops *ops; |
| 329 | int ret; | ||
| 330 | 341 | ||
| 331 | if (WARN_ON(func->state != KLP_ENABLED)) | 342 | WARN_ON(func->state != KLP_ENABLED); |
| 332 | return -EINVAL; | 343 | WARN_ON(!func->old_addr); |
| 333 | |||
| 334 | if (WARN_ON(!func->old_addr)) | ||
| 335 | return -EINVAL; | ||
| 336 | 344 | ||
| 337 | ops = klp_find_ops(func->old_addr); | 345 | ops = klp_find_ops(func->old_addr); |
| 338 | if (WARN_ON(!ops)) | 346 | if (WARN_ON(!ops)) |
| 339 | return -EINVAL; | 347 | return; |
| 340 | 348 | ||
| 341 | if (list_is_singular(&ops->func_stack)) { | 349 | if (list_is_singular(&ops->func_stack)) { |
| 342 | ret = unregister_ftrace_function(&ops->fops); | 350 | WARN_ON(unregister_ftrace_function(&ops->fops)); |
| 343 | if (ret) { | 351 | WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0)); |
| 344 | pr_err("failed to unregister ftrace handler for function '%s' (%d)\n", | ||
| 345 | func->old_name, ret); | ||
| 346 | return ret; | ||
| 347 | } | ||
| 348 | |||
| 349 | ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0); | ||
| 350 | if (ret) | ||
| 351 | pr_warn("function unregister succeeded but failed to clear the filter\n"); | ||
| 352 | 352 | ||
| 353 | list_del_rcu(&func->stack_node); | 353 | list_del_rcu(&func->stack_node); |
| 354 | list_del(&ops->node); | 354 | list_del(&ops->node); |
| @@ -358,8 +358,6 @@ static int klp_disable_func(struct klp_func *func) | |||
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | func->state = KLP_DISABLED; | 360 | func->state = KLP_DISABLED; |
| 361 | |||
| 362 | return 0; | ||
| 363 | } | 361 | } |
| 364 | 362 | ||
| 365 | static int klp_enable_func(struct klp_func *func) | 363 | static int klp_enable_func(struct klp_func *func) |
| @@ -420,23 +418,15 @@ err: | |||
| 420 | return ret; | 418 | return ret; |
| 421 | } | 419 | } |
| 422 | 420 | ||
| 423 | static int klp_disable_object(struct klp_object *obj) | 421 | static void klp_disable_object(struct klp_object *obj) |
| 424 | { | 422 | { |
| 425 | struct klp_func *func; | 423 | struct klp_func *func; |
| 426 | int ret; | ||
| 427 | |||
| 428 | for (func = obj->funcs; func->old_name; func++) { | ||
| 429 | if (func->state != KLP_ENABLED) | ||
| 430 | continue; | ||
| 431 | 424 | ||
| 432 | ret = klp_disable_func(func); | 425 | for (func = obj->funcs; func->old_name; func++) |
| 433 | if (ret) | 426 | if (func->state == KLP_ENABLED) |
| 434 | return ret; | 427 | klp_disable_func(func); |
| 435 | } | ||
| 436 | 428 | ||
| 437 | obj->state = KLP_DISABLED; | 429 | obj->state = KLP_DISABLED; |
| 438 | |||
| 439 | return 0; | ||
| 440 | } | 430 | } |
| 441 | 431 | ||
| 442 | static int klp_enable_object(struct klp_object *obj) | 432 | static int klp_enable_object(struct klp_object *obj) |
| @@ -452,22 +442,19 @@ static int klp_enable_object(struct klp_object *obj) | |||
| 452 | 442 | ||
| 453 | for (func = obj->funcs; func->old_name; func++) { | 443 | for (func = obj->funcs; func->old_name; func++) { |
| 454 | ret = klp_enable_func(func); | 444 | ret = klp_enable_func(func); |
| 455 | if (ret) | 445 | if (ret) { |
| 456 | goto unregister; | 446 | klp_disable_object(obj); |
| 447 | return ret; | ||
| 448 | } | ||
| 457 | } | 449 | } |
| 458 | obj->state = KLP_ENABLED; | 450 | obj->state = KLP_ENABLED; |
| 459 | 451 | ||
| 460 | return 0; | 452 | return 0; |
| 461 | |||
| 462 | unregister: | ||
| 463 | WARN_ON(klp_disable_object(obj)); | ||
| 464 | return ret; | ||
| 465 | } | 453 | } |
| 466 | 454 | ||
| 467 | static int __klp_disable_patch(struct klp_patch *patch) | 455 | static int __klp_disable_patch(struct klp_patch *patch) |
| 468 | { | 456 | { |
| 469 | struct klp_object *obj; | 457 | struct klp_object *obj; |
| 470 | int ret; | ||
| 471 | 458 | ||
| 472 | /* enforce stacking: only the last enabled patch can be disabled */ | 459 | /* enforce stacking: only the last enabled patch can be disabled */ |
| 473 | if (!list_is_last(&patch->list, &klp_patches) && | 460 | if (!list_is_last(&patch->list, &klp_patches) && |
| @@ -477,12 +464,8 @@ static int __klp_disable_patch(struct klp_patch *patch) | |||
| 477 | pr_notice("disabling patch '%s'\n", patch->mod->name); | 464 | pr_notice("disabling patch '%s'\n", patch->mod->name); |
| 478 | 465 | ||
| 479 | for (obj = patch->objs; obj->funcs; obj++) { | 466 | for (obj = patch->objs; obj->funcs; obj++) { |
| 480 | if (obj->state != KLP_ENABLED) | 467 | if (obj->state == KLP_ENABLED) |
| 481 | continue; | 468 | klp_disable_object(obj); |
| 482 | |||
| 483 | ret = klp_disable_object(obj); | ||
| 484 | if (ret) | ||
| 485 | return ret; | ||
| 486 | } | 469 | } |
| 487 | 470 | ||
| 488 | patch->state = KLP_DISABLED; | 471 | patch->state = KLP_DISABLED; |
| @@ -541,8 +524,6 @@ static int __klp_enable_patch(struct klp_patch *patch) | |||
| 541 | pr_notice("enabling patch '%s'\n", patch->mod->name); | 524 | pr_notice("enabling patch '%s'\n", patch->mod->name); |
| 542 | 525 | ||
| 543 | for (obj = patch->objs; obj->funcs; obj++) { | 526 | for (obj = patch->objs; obj->funcs; obj++) { |
| 544 | klp_find_object_module(obj); | ||
| 545 | |||
| 546 | if (!klp_is_object_loaded(obj)) | 527 | if (!klp_is_object_loaded(obj)) |
| 547 | continue; | 528 | continue; |
| 548 | 529 | ||
| @@ -767,6 +748,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) | |||
| 767 | return -EINVAL; | 748 | return -EINVAL; |
| 768 | 749 | ||
| 769 | obj->state = KLP_DISABLED; | 750 | obj->state = KLP_DISABLED; |
| 751 | obj->mod = NULL; | ||
| 770 | 752 | ||
| 771 | klp_find_object_module(obj); | 753 | klp_find_object_module(obj); |
| 772 | 754 | ||
| @@ -932,7 +914,6 @@ static void klp_module_notify_going(struct klp_patch *patch, | |||
| 932 | { | 914 | { |
| 933 | struct module *pmod = patch->mod; | 915 | struct module *pmod = patch->mod; |
| 934 | struct module *mod = obj->mod; | 916 | struct module *mod = obj->mod; |
| 935 | int ret; | ||
| 936 | 917 | ||
| 937 | if (patch->state == KLP_DISABLED) | 918 | if (patch->state == KLP_DISABLED) |
| 938 | goto disabled; | 919 | goto disabled; |
| @@ -940,10 +921,7 @@ static void klp_module_notify_going(struct klp_patch *patch, | |||
| 940 | pr_notice("reverting patch '%s' on unloading module '%s'\n", | 921 | pr_notice("reverting patch '%s' on unloading module '%s'\n", |
| 941 | pmod->name, mod->name); | 922 | pmod->name, mod->name); |
| 942 | 923 | ||
| 943 | ret = klp_disable_object(obj); | 924 | klp_disable_object(obj); |
| 944 | if (ret) | ||
| 945 | pr_warn("failed to revert patch '%s' on module '%s' (%d)\n", | ||
| 946 | pmod->name, mod->name, ret); | ||
| 947 | 925 | ||
| 948 | disabled: | 926 | disabled: |
| 949 | klp_free_object_loaded(obj); | 927 | klp_free_object_loaded(obj); |
| @@ -961,6 +939,15 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action, | |||
| 961 | 939 | ||
| 962 | mutex_lock(&klp_mutex); | 940 | mutex_lock(&klp_mutex); |
| 963 | 941 | ||
| 942 | /* | ||
| 943 | * Each module has to know that the notifier has been called. | ||
| 944 | * We never know what module will get patched by a new patch. | ||
| 945 | */ | ||
| 946 | if (action == MODULE_STATE_COMING) | ||
| 947 | mod->klp_alive = true; | ||
| 948 | else /* MODULE_STATE_GOING */ | ||
| 949 | mod->klp_alive = false; | ||
| 950 | |||
| 964 | list_for_each_entry(patch, &klp_patches, list) { | 951 | list_for_each_entry(patch, &klp_patches, list) { |
| 965 | for (obj = patch->objs; obj->funcs; obj++) { | 952 | for (obj = patch->objs; obj->funcs; obj++) { |
| 966 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) | 953 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) |
