diff options
author | Jiri Kosina <jkosina@suse.cz> | 2015-04-13 17:57:20 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2015-04-13 17:57:20 -0400 |
commit | bcf5d545890e9f7414341c572337ce58cba00a32 (patch) | |
tree | 962e6d5c744b0029534535efb6d3fcf6a8906a1f /kernel/livepatch | |
parent | 8cb2c2dc472775479a1a7e78180955f6f1cb0b0a (diff) | |
parent | 2e3ac940f2754d7dc616aba1643a668954fe892f (diff) |
Merge branch 'for-4.1/core-noarch' into for-linus
Diffstat (limited to 'kernel/livepatch')
-rw-r--r-- | kernel/livepatch/core.c | 69 |
1 files changed, 17 insertions, 52 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 3f9f1d6b4c2e..284e2691e380 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
@@ -335,32 +335,20 @@ unlock: | |||
335 | rcu_read_unlock(); | 335 | rcu_read_unlock(); |
336 | } | 336 | } |
337 | 337 | ||
338 | static int klp_disable_func(struct klp_func *func) | 338 | static void klp_disable_func(struct klp_func *func) |
339 | { | 339 | { |
340 | struct klp_ops *ops; | 340 | struct klp_ops *ops; |
341 | int ret; | ||
342 | |||
343 | if (WARN_ON(func->state != KLP_ENABLED)) | ||
344 | return -EINVAL; | ||
345 | 341 | ||
346 | if (WARN_ON(!func->old_addr)) | 342 | WARN_ON(func->state != KLP_ENABLED); |
347 | return -EINVAL; | 343 | WARN_ON(!func->old_addr); |
348 | 344 | ||
349 | ops = klp_find_ops(func->old_addr); | 345 | ops = klp_find_ops(func->old_addr); |
350 | if (WARN_ON(!ops)) | 346 | if (WARN_ON(!ops)) |
351 | return -EINVAL; | 347 | return; |
352 | 348 | ||
353 | if (list_is_singular(&ops->func_stack)) { | 349 | if (list_is_singular(&ops->func_stack)) { |
354 | ret = unregister_ftrace_function(&ops->fops); | 350 | WARN_ON(unregister_ftrace_function(&ops->fops)); |
355 | if (ret) { | 351 | WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0)); |
356 | pr_err("failed to unregister ftrace handler for function '%s' (%d)\n", | ||
357 | func->old_name, ret); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0); | ||
362 | if (ret) | ||
363 | pr_warn("function unregister succeeded but failed to clear the filter\n"); | ||
364 | 352 | ||
365 | list_del_rcu(&func->stack_node); | 353 | list_del_rcu(&func->stack_node); |
366 | list_del(&ops->node); | 354 | list_del(&ops->node); |
@@ -370,8 +358,6 @@ static int klp_disable_func(struct klp_func *func) | |||
370 | } | 358 | } |
371 | 359 | ||
372 | func->state = KLP_DISABLED; | 360 | func->state = KLP_DISABLED; |
373 | |||
374 | return 0; | ||
375 | } | 361 | } |
376 | 362 | ||
377 | static int klp_enable_func(struct klp_func *func) | 363 | static int klp_enable_func(struct klp_func *func) |
@@ -432,23 +418,15 @@ err: | |||
432 | return ret; | 418 | return ret; |
433 | } | 419 | } |
434 | 420 | ||
435 | static int klp_disable_object(struct klp_object *obj) | 421 | static void klp_disable_object(struct klp_object *obj) |
436 | { | 422 | { |
437 | struct klp_func *func; | 423 | struct klp_func *func; |
438 | int ret; | ||
439 | 424 | ||
440 | for (func = obj->funcs; func->old_name; func++) { | 425 | for (func = obj->funcs; func->old_name; func++) |
441 | if (func->state != KLP_ENABLED) | 426 | if (func->state == KLP_ENABLED) |
442 | continue; | 427 | klp_disable_func(func); |
443 | |||
444 | ret = klp_disable_func(func); | ||
445 | if (ret) | ||
446 | return ret; | ||
447 | } | ||
448 | 428 | ||
449 | obj->state = KLP_DISABLED; | 429 | obj->state = KLP_DISABLED; |
450 | |||
451 | return 0; | ||
452 | } | 430 | } |
453 | 431 | ||
454 | static int klp_enable_object(struct klp_object *obj) | 432 | static int klp_enable_object(struct klp_object *obj) |
@@ -464,22 +442,19 @@ static int klp_enable_object(struct klp_object *obj) | |||
464 | 442 | ||
465 | for (func = obj->funcs; func->old_name; func++) { | 443 | for (func = obj->funcs; func->old_name; func++) { |
466 | ret = klp_enable_func(func); | 444 | ret = klp_enable_func(func); |
467 | if (ret) | 445 | if (ret) { |
468 | goto unregister; | 446 | klp_disable_object(obj); |
447 | return ret; | ||
448 | } | ||
469 | } | 449 | } |
470 | obj->state = KLP_ENABLED; | 450 | obj->state = KLP_ENABLED; |
471 | 451 | ||
472 | return 0; | 452 | return 0; |
473 | |||
474 | unregister: | ||
475 | WARN_ON(klp_disable_object(obj)); | ||
476 | return ret; | ||
477 | } | 453 | } |
478 | 454 | ||
479 | static int __klp_disable_patch(struct klp_patch *patch) | 455 | static int __klp_disable_patch(struct klp_patch *patch) |
480 | { | 456 | { |
481 | struct klp_object *obj; | 457 | struct klp_object *obj; |
482 | int ret; | ||
483 | 458 | ||
484 | /* enforce stacking: only the last enabled patch can be disabled */ | 459 | /* enforce stacking: only the last enabled patch can be disabled */ |
485 | if (!list_is_last(&patch->list, &klp_patches) && | 460 | if (!list_is_last(&patch->list, &klp_patches) && |
@@ -489,12 +464,8 @@ static int __klp_disable_patch(struct klp_patch *patch) | |||
489 | pr_notice("disabling patch '%s'\n", patch->mod->name); | 464 | pr_notice("disabling patch '%s'\n", patch->mod->name); |
490 | 465 | ||
491 | for (obj = patch->objs; obj->funcs; obj++) { | 466 | for (obj = patch->objs; obj->funcs; obj++) { |
492 | if (obj->state != KLP_ENABLED) | 467 | if (obj->state == KLP_ENABLED) |
493 | continue; | 468 | klp_disable_object(obj); |
494 | |||
495 | ret = klp_disable_object(obj); | ||
496 | if (ret) | ||
497 | return ret; | ||
498 | } | 469 | } |
499 | 470 | ||
500 | patch->state = KLP_DISABLED; | 471 | patch->state = KLP_DISABLED; |
@@ -553,8 +524,6 @@ static int __klp_enable_patch(struct klp_patch *patch) | |||
553 | pr_notice("enabling patch '%s'\n", patch->mod->name); | 524 | pr_notice("enabling patch '%s'\n", patch->mod->name); |
554 | 525 | ||
555 | for (obj = patch->objs; obj->funcs; obj++) { | 526 | for (obj = patch->objs; obj->funcs; obj++) { |
556 | klp_find_object_module(obj); | ||
557 | |||
558 | if (!klp_is_object_loaded(obj)) | 527 | if (!klp_is_object_loaded(obj)) |
559 | continue; | 528 | continue; |
560 | 529 | ||
@@ -945,7 +914,6 @@ static void klp_module_notify_going(struct klp_patch *patch, | |||
945 | { | 914 | { |
946 | struct module *pmod = patch->mod; | 915 | struct module *pmod = patch->mod; |
947 | struct module *mod = obj->mod; | 916 | struct module *mod = obj->mod; |
948 | int ret; | ||
949 | 917 | ||
950 | if (patch->state == KLP_DISABLED) | 918 | if (patch->state == KLP_DISABLED) |
951 | goto disabled; | 919 | goto disabled; |
@@ -953,10 +921,7 @@ static void klp_module_notify_going(struct klp_patch *patch, | |||
953 | pr_notice("reverting patch '%s' on unloading module '%s'\n", | 921 | pr_notice("reverting patch '%s' on unloading module '%s'\n", |
954 | pmod->name, mod->name); | 922 | pmod->name, mod->name); |
955 | 923 | ||
956 | ret = klp_disable_object(obj); | 924 | klp_disable_object(obj); |
957 | if (ret) | ||
958 | pr_warn("failed to revert patch '%s' on module '%s' (%d)\n", | ||
959 | pmod->name, mod->name, ret); | ||
960 | 925 | ||
961 | disabled: | 926 | disabled: |
962 | klp_free_object_loaded(obj); | 927 | klp_free_object_loaded(obj); |