summaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
authorJessica Yu <jeyu@kernel.org>2018-01-09 18:51:24 -0500
committerIngo Molnar <mingo@kernel.org>2018-02-16 03:12:58 -0500
commit297f9233b53a08fd457815e19f1d6f2c3389857b (patch)
treea69f719f75c4e11a8fea600b1f92ea0ee25d6d0a /kernel/kprobes.c
parent12310e3437554328bcd75186cf331bc712cb30b2 (diff)
kprobes: Propagate error from disarm_kprobe_ftrace()
Improve error handling when disarming ftrace-based kprobes. Like with arm_kprobe_ftrace(), propagate any errors from disarm_kprobe_ftrace() so that we do not disable/unregister kprobes that are still armed. In other words, unregister_kprobe() and disable_kprobe() should not report success if the kprobe could not be disarmed. disarm_all_kprobes() keeps its current behavior and attempts to disarm all kprobes. It returns the last encountered error and gives a warning if not all probes could be disarmed. This patch is based on Petr Mladek's original patchset (patches 2 and 3) back in 2015, which improved kprobes error handling, found here: https://lkml.org/lkml/2015/2/26/452 However, further work on this had been paused since then and the patches were not upstreamed. Based-on-patches-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Jessica Yu <jeyu@kernel.org> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com> Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Cc: David S . Miller <davem@davemloft.net> Cc: Jiri Kosina <jikos@kernel.org> Cc: Joe Lawrence <joe.lawrence@redhat.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Miroslav Benes <mbenes@suse.cz> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Petr Mladek <pmladek@suse.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/20180109235124.30886-3-jeyu@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c78
1 files changed, 53 insertions, 25 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 2d988141ab85..102160ff5c66 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1011,23 +1011,27 @@ err_ftrace:
1011} 1011}
1012 1012
1013/* Caller must lock kprobe_mutex */ 1013/* Caller must lock kprobe_mutex */
1014static void disarm_kprobe_ftrace(struct kprobe *p) 1014static int disarm_kprobe_ftrace(struct kprobe *p)
1015{ 1015{
1016 int ret; 1016 int ret = 0;
1017 1017
1018 kprobe_ftrace_enabled--; 1018 if (kprobe_ftrace_enabled == 1) {
1019 if (kprobe_ftrace_enabled == 0) {
1020 ret = unregister_ftrace_function(&kprobe_ftrace_ops); 1019 ret = unregister_ftrace_function(&kprobe_ftrace_ops);
1021 WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret); 1020 if (WARN(ret < 0, "Failed to unregister kprobe-ftrace (%d)\n", ret))
1021 return ret;
1022 } 1022 }
1023
1024 kprobe_ftrace_enabled--;
1025
1023 ret = ftrace_set_filter_ip(&kprobe_ftrace_ops, 1026 ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
1024 (unsigned long)p->addr, 1, 0); 1027 (unsigned long)p->addr, 1, 0);
1025 WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret); 1028 WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret);
1029 return ret;
1026} 1030}
1027#else /* !CONFIG_KPROBES_ON_FTRACE */ 1031#else /* !CONFIG_KPROBES_ON_FTRACE */
1028#define prepare_kprobe(p) arch_prepare_kprobe(p) 1032#define prepare_kprobe(p) arch_prepare_kprobe(p)
1029#define arm_kprobe_ftrace(p) (-ENODEV) 1033#define arm_kprobe_ftrace(p) (-ENODEV)
1030#define disarm_kprobe_ftrace(p) do {} while (0) 1034#define disarm_kprobe_ftrace(p) (-ENODEV)
1031#endif 1035#endif
1032 1036
1033/* Arm a kprobe with text_mutex */ 1037/* Arm a kprobe with text_mutex */
@@ -1046,18 +1050,18 @@ static int arm_kprobe(struct kprobe *kp)
1046} 1050}
1047 1051
1048/* Disarm a kprobe with text_mutex */ 1052/* Disarm a kprobe with text_mutex */
1049static void disarm_kprobe(struct kprobe *kp, bool reopt) 1053static int disarm_kprobe(struct kprobe *kp, bool reopt)
1050{ 1054{
1051 if (unlikely(kprobe_ftrace(kp))) { 1055 if (unlikely(kprobe_ftrace(kp)))
1052 disarm_kprobe_ftrace(kp); 1056 return disarm_kprobe_ftrace(kp);
1053 return;
1054 }
1055 1057
1056 cpus_read_lock(); 1058 cpus_read_lock();
1057 mutex_lock(&text_mutex); 1059 mutex_lock(&text_mutex);
1058 __disarm_kprobe(kp, reopt); 1060 __disarm_kprobe(kp, reopt);
1059 mutex_unlock(&text_mutex); 1061 mutex_unlock(&text_mutex);
1060 cpus_read_unlock(); 1062 cpus_read_unlock();
1063
1064 return 0;
1061} 1065}
1062 1066
1063/* 1067/*
@@ -1639,11 +1643,12 @@ static int aggr_kprobe_disabled(struct kprobe *ap)
1639static struct kprobe *__disable_kprobe(struct kprobe *p) 1643static struct kprobe *__disable_kprobe(struct kprobe *p)
1640{ 1644{
1641 struct kprobe *orig_p; 1645 struct kprobe *orig_p;
1646 int ret;
1642 1647
1643 /* Get an original kprobe for return */ 1648 /* Get an original kprobe for return */
1644 orig_p = __get_valid_kprobe(p); 1649 orig_p = __get_valid_kprobe(p);
1645 if (unlikely(orig_p == NULL)) 1650 if (unlikely(orig_p == NULL))
1646 return NULL; 1651 return ERR_PTR(-EINVAL);
1647 1652
1648 if (!kprobe_disabled(p)) { 1653 if (!kprobe_disabled(p)) {
1649 /* Disable probe if it is a child probe */ 1654 /* Disable probe if it is a child probe */
@@ -1657,8 +1662,13 @@ static struct kprobe *__disable_kprobe(struct kprobe *p)
1657 * should have already been disarmed, so 1662 * should have already been disarmed, so
1658 * skip unneed disarming process. 1663 * skip unneed disarming process.
1659 */ 1664 */
1660 if (!kprobes_all_disarmed) 1665 if (!kprobes_all_disarmed) {
1661 disarm_kprobe(orig_p, true); 1666 ret = disarm_kprobe(orig_p, true);
1667 if (ret) {
1668 p->flags &= ~KPROBE_FLAG_DISABLED;
1669 return ERR_PTR(ret);
1670 }
1671 }
1662 orig_p->flags |= KPROBE_FLAG_DISABLED; 1672 orig_p->flags |= KPROBE_FLAG_DISABLED;
1663 } 1673 }
1664 } 1674 }
@@ -1675,8 +1685,8 @@ static int __unregister_kprobe_top(struct kprobe *p)
1675 1685
1676 /* Disable kprobe. This will disarm it if needed. */ 1686 /* Disable kprobe. This will disarm it if needed. */
1677 ap = __disable_kprobe(p); 1687 ap = __disable_kprobe(p);
1678 if (ap == NULL) 1688 if (IS_ERR(ap))
1679 return -EINVAL; 1689 return PTR_ERR(ap);
1680 1690
1681 if (ap == p) 1691 if (ap == p)
1682 /* 1692 /*
@@ -2109,12 +2119,14 @@ static void kill_kprobe(struct kprobe *p)
2109int disable_kprobe(struct kprobe *kp) 2119int disable_kprobe(struct kprobe *kp)
2110{ 2120{
2111 int ret = 0; 2121 int ret = 0;
2122 struct kprobe *p;
2112 2123
2113 mutex_lock(&kprobe_mutex); 2124 mutex_lock(&kprobe_mutex);
2114 2125
2115 /* Disable this kprobe */ 2126 /* Disable this kprobe */
2116 if (__disable_kprobe(kp) == NULL) 2127 p = __disable_kprobe(kp);
2117 ret = -EINVAL; 2128 if (IS_ERR(p))
2129 ret = PTR_ERR(p);
2118 2130
2119 mutex_unlock(&kprobe_mutex); 2131 mutex_unlock(&kprobe_mutex);
2120 return ret; 2132 return ret;
@@ -2486,34 +2498,50 @@ already_enabled:
2486 return ret; 2498 return ret;
2487} 2499}
2488 2500
2489static void disarm_all_kprobes(void) 2501static int disarm_all_kprobes(void)
2490{ 2502{
2491 struct hlist_head *head; 2503 struct hlist_head *head;
2492 struct kprobe *p; 2504 struct kprobe *p;
2493 unsigned int i; 2505 unsigned int i, total = 0, errors = 0;
2506 int err, ret = 0;
2494 2507
2495 mutex_lock(&kprobe_mutex); 2508 mutex_lock(&kprobe_mutex);
2496 2509
2497 /* If kprobes are already disarmed, just return */ 2510 /* If kprobes are already disarmed, just return */
2498 if (kprobes_all_disarmed) { 2511 if (kprobes_all_disarmed) {
2499 mutex_unlock(&kprobe_mutex); 2512 mutex_unlock(&kprobe_mutex);
2500 return; 2513 return 0;
2501 } 2514 }
2502 2515
2503 kprobes_all_disarmed = true; 2516 kprobes_all_disarmed = true;
2504 printk(KERN_INFO "Kprobes globally disabled\n");
2505 2517
2506 for (i = 0; i < KPROBE_TABLE_SIZE; i++) { 2518 for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
2507 head = &kprobe_table[i]; 2519 head = &kprobe_table[i];
2520 /* Disarm all kprobes on a best-effort basis */
2508 hlist_for_each_entry_rcu(p, head, hlist) { 2521 hlist_for_each_entry_rcu(p, head, hlist) {
2509 if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) 2522 if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) {
2510 disarm_kprobe(p, false); 2523 err = disarm_kprobe(p, false);
2524 if (err) {
2525 errors++;
2526 ret = err;
2527 }
2528 total++;
2529 }
2511 } 2530 }
2512 } 2531 }
2532
2533 if (errors)
2534 pr_warn("Kprobes globally disabled, but failed to disarm %d out of %d probes\n",
2535 errors, total);
2536 else
2537 pr_info("Kprobes globally disabled\n");
2538
2513 mutex_unlock(&kprobe_mutex); 2539 mutex_unlock(&kprobe_mutex);
2514 2540
2515 /* Wait for disarming all kprobes by optimizer */ 2541 /* Wait for disarming all kprobes by optimizer */
2516 wait_for_kprobe_optimizer(); 2542 wait_for_kprobe_optimizer();
2543
2544 return ret;
2517} 2545}
2518 2546
2519/* 2547/*
@@ -2556,7 +2584,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
2556 case 'n': 2584 case 'n':
2557 case 'N': 2585 case 'N':
2558 case '0': 2586 case '0':
2559 disarm_all_kprobes(); 2587 ret = disarm_all_kprobes();
2560 break; 2588 break;
2561 default: 2589 default:
2562 return -EINVAL; 2590 return -EINVAL;