Received: by 10.223.185.116 with SMTP id b49csp3984366wrg; Tue, 13 Feb 2018 10:47:51 -0800 (PST) X-Google-Smtp-Source: AH8x226qr/z4tApTZjyj2UDKMzePwtuVVRYssovHbV2/f0BIDSwnirqd/TRmlmXYVFZT5R1/1hhz X-Received: by 10.99.155.1 with SMTP id r1mr1780883pgd.422.1518547671216; Tue, 13 Feb 2018 10:47:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518547671; cv=none; d=google.com; s=arc-20160816; b=aZwbV5xZfP+wUKkqWkdiiOjluSnXvDnrZXU2BJTREg+DsLNYT/3r0+gZYE5s/X129g Q+xlrhU6SVO4BfUAyu68Wxyypj2GWxo4ecuA6HE9Er48FWaw8vrnB+N8enAuFwewMRJU z6aIvka16xW2NsmBEOLBZt6tqcx+0cNEE1j6fQ6K9GQtIRDVfcJpsXTOqhea/g7Hi7QW DNK/TwIUA/yyIrCJRJ9LHAzI28ZHoi7/kAtVBkiVKcZA7Dg6t1ffRmnrTzCBDtoZm+k0 PawIiL7bMh0GvJuXOn7nVgN9+GasOhG9ZfeeEa3zUJeCckl4dUcvg4azZedB0wnDGji9 tvXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-disposition :content-transfer-encoding:mime-version:robot-unsubscribe:robot-id :git-commit-id:subject:to:references:in-reply-to:reply-to:cc :message-id:from:date:arc-authentication-results; bh=6GWUaoxsEIAf41k5s9Ah2F2APRuMXGxGjgtaKYeLy0U=; b=NNNQqtb4LRZRLlgWv+pzeZbbOBF1MYQhaKW6rkj0uTNHCqjoz1Kx5xV4qiyn6BJ5Vx npBHECGr/d68vwbMYCyupwTzrPa7eC6cLCx+rpl22G/cnKor5+qfRzdp4xkwerYXhBKu 4GL5pm+qww9Gt3TIf9UYEkAqPV23alvlFBYGJyAxJKZaugJd7WZ4lRwpN4zOPVRPxJG5 Bg4pb2ri7oANY/7P89hDk4y/lP6UJ1OaMFR+AuaSftMePbnD8M5aG44R2GE0Jis5HzGs Fp+Hu8+ySrirJ4cC9bLXamAbPVZHlMWe/JDO+Pc/5p0QmQ2PhNZU3XEb0PSP1CIBlLj4 eK3A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j8-v6si7615014plk.87.2018.02.13.10.47.36; Tue, 13 Feb 2018 10:47:51 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965525AbeBMSqr (ORCPT + 99 others); Tue, 13 Feb 2018 13:46:47 -0500 Received: from terminus.zytor.com ([198.137.202.136]:36173 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965415AbeBMSqq (ORCPT ); Tue, 13 Feb 2018 13:46:46 -0500 Received: from terminus.zytor.com (localhost [127.0.0.1]) by terminus.zytor.com (8.15.2/8.15.2) with ESMTP id w1DIk2Tx012701; Tue, 13 Feb 2018 10:46:02 -0800 Received: (from tipbot@localhost) by terminus.zytor.com (8.15.2/8.15.2/Submit) id w1DIk224012697; Tue, 13 Feb 2018 10:46:02 -0800 Date: Tue, 13 Feb 2018 10:46:02 -0800 X-Authentication-Warning: terminus.zytor.com: tipbot set sender to tipbot@zytor.com using -f From: tip-bot for Jessica Yu Message-ID: Cc: ananth@linux.vnet.ibm.com, tglx@linutronix.de, torvalds@linux-foundation.org, joe.lawrence@redhat.com, mhiramat@kernel.org, linux-kernel@vger.kernel.org, jpoimboe@redhat.com, rostedt@goodmis.org, pmladek@suse.com, davem@davemloft.net, jeyu@kernel.org, peterz@infradead.org, jikos@kernel.org, mbenes@suse.cz, hpa@zytor.com, anil.s.keshavamurthy@intel.com, mingo@kernel.org Reply-To: pmladek@suse.com, rostedt@goodmis.org, davem@davemloft.net, jpoimboe@redhat.com, mingo@kernel.org, jeyu@kernel.org, peterz@infradead.org, jikos@kernel.org, mbenes@suse.cz, hpa@zytor.com, anil.s.keshavamurthy@intel.com, ananth@linux.vnet.ibm.com, torvalds@linux-foundation.org, tglx@linutronix.de, mhiramat@kernel.org, linux-kernel@vger.kernel.org, joe.lawrence@redhat.com In-Reply-To: <20180109235124.30886-2-jeyu@kernel.org> References: <20180109235124.30886-2-jeyu@kernel.org> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/urgent] kprobes: Propagate error from arm_kprobe_ftrace() Git-Commit-ID: 384f1d86a8890fcf8118add0b6a0785ee35f5a65 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00 autolearn=ham autolearn_force=no version=3.4.1 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on terminus.zytor.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 384f1d86a8890fcf8118add0b6a0785ee35f5a65 Gitweb: https://git.kernel.org/tip/384f1d86a8890fcf8118add0b6a0785ee35f5a65 Author: Jessica Yu AuthorDate: Wed, 10 Jan 2018 00:51:23 +0100 Committer: Ingo Molnar CommitDate: Tue, 13 Feb 2018 18:20:00 +0100 kprobes: Propagate error from arm_kprobe_ftrace() Improve error handling when arming ftrace-based kprobes. Specifically, if we fail to arm a ftrace-based kprobe, register_kprobe()/enable_kprobe() should report an error instead of success. Previously, this has lead to confusing situations where register_kprobe() would return 0 indicating success, but the kprobe would not be functional if ftrace registration during the kprobe arming process had failed. We should therefore take any errors returned by ftrace into account and propagate this error so that we do not register/enable kprobes that cannot be armed. This can happen if, for example, register_ftrace_function() finds an IPMODIFY conflict (since kprobe_ftrace_ops has this flag set) and returns an error. Such a conflict is possible since livepatches also set the IPMODIFY flag for their ftrace_ops. arm_all_kprobes() keeps its current behavior and attempts to arm all kprobes. It returns the last encountered error and gives a warning if not all probes could be armed. 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 Signed-off-by: Jessica Yu Acked-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: David S . Miller Cc: Jiri Kosina Cc: Joe Lawrence Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Miroslav Benes Cc: Peter Zijlstra Cc: Petr Mladek Cc: Steven Rostedt Cc: Thomas Gleixner Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/20180109235124.30886-2-jeyu@kernel.org Signed-off-by: Ingo Molnar --- kernel/kprobes.c | 100 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index da2ccf1..2d98814 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -978,18 +978,36 @@ static int prepare_kprobe(struct kprobe *p) } /* Caller must lock kprobe_mutex */ -static void arm_kprobe_ftrace(struct kprobe *p) +static int arm_kprobe_ftrace(struct kprobe *p) { - int ret; + int ret = 0; ret = ftrace_set_filter_ip(&kprobe_ftrace_ops, (unsigned long)p->addr, 0, 0); - WARN(ret < 0, "Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret); - kprobe_ftrace_enabled++; - if (kprobe_ftrace_enabled == 1) { + if (ret) { + pr_debug("Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret); + return ret; + } + + if (kprobe_ftrace_enabled == 0) { ret = register_ftrace_function(&kprobe_ftrace_ops); - WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret); + if (ret) { + pr_debug("Failed to init kprobe-ftrace (%d)\n", ret); + goto err_ftrace; + } } + + kprobe_ftrace_enabled++; + return ret; + +err_ftrace: + /* + * Note: Since kprobe_ftrace_ops has IPMODIFY set, and ftrace requires a + * non-empty filter_hash for IPMODIFY ops, we're safe from an accidental + * empty filter_hash which would undesirably trace all functions. + */ + ftrace_set_filter_ip(&kprobe_ftrace_ops, (unsigned long)p->addr, 1, 0); + return ret; } /* Caller must lock kprobe_mutex */ @@ -1008,22 +1026,23 @@ static void disarm_kprobe_ftrace(struct kprobe *p) } #else /* !CONFIG_KPROBES_ON_FTRACE */ #define prepare_kprobe(p) arch_prepare_kprobe(p) -#define arm_kprobe_ftrace(p) do {} while (0) +#define arm_kprobe_ftrace(p) (-ENODEV) #define disarm_kprobe_ftrace(p) do {} while (0) #endif /* Arm a kprobe with text_mutex */ -static void arm_kprobe(struct kprobe *kp) +static int arm_kprobe(struct kprobe *kp) { - if (unlikely(kprobe_ftrace(kp))) { - arm_kprobe_ftrace(kp); - return; - } + if (unlikely(kprobe_ftrace(kp))) + return arm_kprobe_ftrace(kp); + cpus_read_lock(); mutex_lock(&text_mutex); __arm_kprobe(kp); mutex_unlock(&text_mutex); cpus_read_unlock(); + + return 0; } /* Disarm a kprobe with text_mutex */ @@ -1362,9 +1381,15 @@ out: if (ret == 0 && kprobe_disabled(ap) && !kprobe_disabled(p)) { ap->flags &= ~KPROBE_FLAG_DISABLED; - if (!kprobes_all_disarmed) + if (!kprobes_all_disarmed) { /* Arm the breakpoint again. */ - arm_kprobe(ap); + ret = arm_kprobe(ap); + if (ret) { + ap->flags |= KPROBE_FLAG_DISABLED; + list_del_rcu(&p->list); + synchronize_sched(); + } + } } return ret; } @@ -1573,8 +1598,14 @@ int register_kprobe(struct kprobe *p) hlist_add_head_rcu(&p->hlist, &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); - if (!kprobes_all_disarmed && !kprobe_disabled(p)) - arm_kprobe(p); + if (!kprobes_all_disarmed && !kprobe_disabled(p)) { + ret = arm_kprobe(p); + if (ret) { + hlist_del_rcu(&p->hlist); + synchronize_sched(); + goto out; + } + } /* Try to optimize kprobe */ try_to_optimize_kprobe(p); @@ -2116,7 +2147,9 @@ int enable_kprobe(struct kprobe *kp) if (!kprobes_all_disarmed && kprobe_disabled(p)) { p->flags &= ~KPROBE_FLAG_DISABLED; - arm_kprobe(p); + ret = arm_kprobe(p); + if (ret) + p->flags |= KPROBE_FLAG_DISABLED; } out: mutex_unlock(&kprobe_mutex); @@ -2407,11 +2440,12 @@ static const struct file_operations debugfs_kprobe_blacklist_ops = { .release = seq_release, }; -static void arm_all_kprobes(void) +static int arm_all_kprobes(void) { struct hlist_head *head; struct kprobe *p; - unsigned int i; + unsigned int i, total = 0, errors = 0; + int err, ret = 0; mutex_lock(&kprobe_mutex); @@ -2428,16 +2462,28 @@ static void arm_all_kprobes(void) /* Arming kprobes doesn't optimize kprobe itself */ for (i = 0; i < KPROBE_TABLE_SIZE; i++) { head = &kprobe_table[i]; - hlist_for_each_entry_rcu(p, head, hlist) - if (!kprobe_disabled(p)) - arm_kprobe(p); + /* Arm all kprobes on a best-effort basis */ + hlist_for_each_entry_rcu(p, head, hlist) { + if (!kprobe_disabled(p)) { + err = arm_kprobe(p); + if (err) { + errors++; + ret = err; + } + total++; + } + } } - printk(KERN_INFO "Kprobes globally enabled\n"); + if (errors) + pr_warn("Kprobes globally enabled, but failed to arm %d out of %d probes\n", + errors, total); + else + pr_info("Kprobes globally enabled\n"); already_enabled: mutex_unlock(&kprobe_mutex); - return; + return ret; } static void disarm_all_kprobes(void) @@ -2494,6 +2540,7 @@ static ssize_t write_enabled_file_bool(struct file *file, { char buf[32]; size_t buf_size; + int ret = 0; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -2504,7 +2551,7 @@ static ssize_t write_enabled_file_bool(struct file *file, case 'y': case 'Y': case '1': - arm_all_kprobes(); + ret = arm_all_kprobes(); break; case 'n': case 'N': @@ -2515,6 +2562,9 @@ static ssize_t write_enabled_file_bool(struct file *file, return -EINVAL; } + if (ret) + return ret; + return count; }