Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp2269466pxb; Thu, 11 Feb 2021 08:19:41 -0800 (PST) X-Google-Smtp-Source: ABdhPJxmJciOU7DOA4dUDXPVQsPf3WLroRIZOOCZexXdlkWNsdsQ5z2I0Ggz7dvSqFm5X93UMkok X-Received: by 2002:aa7:c901:: with SMTP id b1mr8985589edt.329.1613060381739; Thu, 11 Feb 2021 08:19:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1613060381; cv=none; d=google.com; s=arc-20160816; b=evkGQdD+vqYlbx0brm8ESgwpkKfloAL5HZFjELSImPYXWHst77pYBwp22msv5pkIXB OIgl7Z4oDKTaUvvykoXrPBHHucIjawUtmRhF7+CjKBpWorb72BFKAL4it/nCHu2UQGMC FUo1fTSjgYd4OdcMUgrjzfU4TDHXj/jdMBx9lV/Nhr3qj4rzKHAMMcstno66hEN0CKmo KDUsnu8mZkbWMVQ+Hjy3qqSSLRYBp96ZWS33hZJInhajXOfh1P+ijPfm/H+ypPsOP0gM PwajmAMk8AkHMH+TcfTYvBdpQYDW5y1jJRdjatJg+m3nbfxE0ahIMRbSS/RMVp8yyRta RBZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=BUjBwBFP4mN2805wexScHcmnhnvkZNDCczsRDlWK7Ro=; b=pr1K6h2Wl86Qj4Jz7uCUQC6fC35x/VweHhq1XAqFmj+7Rqg3tIhfliyNS+DCbccDtn RN2+tUo5lGtBb4ECRpvCWdkWp8LFskOmL/HOtbdlYmwgSLxj5I/9OBD5OylTQhdV/t5w ttLeBy/SQfzRC/1jyNNKf+85/3ymLSHCSh6aIIhAxGEfS7QSUpcwKnH4UwAH5nkVMaab 5h7HzidbwOO6IZnlv+GBG/PzWW+I1MB2G7XUkKznogykEDd7iHMtNef7EaUVvjt5wAUs vdfFqKgBdKhfQKd13QBgI7G0qT5MZoeGgbf2ercc5z7+p8U9pprCBepK8bCpt2/Ssey6 aemg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=vmkb9d2z; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id r13si4026105ejz.437.2021.02.11.08.19.18; Thu, 11 Feb 2021 08:19:41 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=vmkb9d2z; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231779AbhBKQSE (ORCPT + 99 others); Thu, 11 Feb 2021 11:18:04 -0500 Received: from mail.kernel.org ([198.145.29.99]:52630 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230484AbhBKPWw (ORCPT ); Thu, 11 Feb 2021 10:22:52 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 808EB64F33; Thu, 11 Feb 2021 15:07:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1613056057; bh=nbq3R7u7lI402KPHaihlSCT8lHxHJ8UorM+o0WDzCac=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vmkb9d2zzjgba/iBDh2pkTDXHTAXsXrngXo/dQEjOef0I4CuUgX9eAGGt42DjhAud yo5z9bFR0tW39oLcfIBHZWeSrA3AVl2XDMEanceax3oFV+bPKKiBO/ZWNK6rja4mSr /NbmlprxIQi3nN/dG/a3kjzd0u4h9qXicnmRytHk= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jianlin Lv , Masami Hiramatsu , "Steven Rostedt (VMware)" Subject: [PATCH 4.19 01/24] tracing/kprobe: Fix to support kretprobe events on unloaded modules Date: Thu, 11 Feb 2021 16:02:35 +0100 Message-Id: <20210211150147.819199739@linuxfoundation.org> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210211150147.743660073@linuxfoundation.org> References: <20210211150147.743660073@linuxfoundation.org> User-Agent: quilt/0.66 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Masami Hiramatsu commit 97c753e62e6c31a404183898d950d8c08d752dbd upstream. Fix kprobe_on_func_entry() returns error code instead of false so that register_kretprobe() can return an appropriate error code. append_trace_kprobe() expects the kprobe registration returns -ENOENT when the target symbol is not found, and it checks whether the target module is unloaded or not. If the target module doesn't exist, it defers to probe the target symbol until the module is loaded. However, since register_kretprobe() returns -EINVAL instead of -ENOENT in that case, it always fail on putting the kretprobe event on unloaded modules. e.g. Kprobe event: /sys/kernel/debug/tracing # echo p xfs:xfs_end_io >> kprobe_events [ 16.515574] trace_kprobe: This probe might be able to register after target module is loaded. Continue. Kretprobe event: (p -> r) /sys/kernel/debug/tracing # echo r xfs:xfs_end_io >> kprobe_events sh: write error: Invalid argument /sys/kernel/debug/tracing # cat error_log [ 41.122514] trace_kprobe: error: Failed to register probe event Command: r xfs:xfs_end_io ^ To fix this bug, change kprobe_on_func_entry() to detect symbol lookup failure and return -ENOENT in that case. Otherwise it returns -EINVAL or 0 (succeeded, given address is on the entry). Link: https://lkml.kernel.org/r/161176187132.1067016.8118042342894378981.stgit@devnote2 Cc: stable@vger.kernel.org Fixes: 59158ec4aef7 ("tracing/kprobes: Check the probe on unloaded module correctly") Reported-by: Jianlin Lv Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- include/linux/kprobes.h | 2 +- kernel/kprobes.c | 34 +++++++++++++++++++++++++--------- kernel/trace/trace_kprobe.c | 4 ++-- 3 files changed, 28 insertions(+), 12 deletions(-) --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -245,7 +245,7 @@ extern void kprobes_inc_nmissed_count(st extern bool arch_within_kprobe_blacklist(unsigned long addr); extern int arch_populate_kprobe_blacklist(void); extern bool arch_kprobe_on_func_entry(unsigned long offset); -extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset); +extern int kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset); extern bool within_kprobe_blacklist(unsigned long addr); extern int kprobe_add_ksym_blacklist(unsigned long entry); --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1921,29 +1921,45 @@ bool __weak arch_kprobe_on_func_entry(un return !offset; } -bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset) +/** + * kprobe_on_func_entry() -- check whether given address is function entry + * @addr: Target address + * @sym: Target symbol name + * @offset: The offset from the symbol or the address + * + * This checks whether the given @addr+@offset or @sym+@offset is on the + * function entry address or not. + * This returns 0 if it is the function entry, or -EINVAL if it is not. + * And also it returns -ENOENT if it fails the symbol or address lookup. + * Caller must pass @addr or @sym (either one must be NULL), or this + * returns -EINVAL. + */ +int kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset) { kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset); if (IS_ERR(kp_addr)) - return false; + return PTR_ERR(kp_addr); - if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset) || - !arch_kprobe_on_func_entry(offset)) - return false; + if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset)) + return -ENOENT; - return true; + if (!arch_kprobe_on_func_entry(offset)) + return -EINVAL; + + return 0; } int register_kretprobe(struct kretprobe *rp) { - int ret = 0; + int ret; struct kretprobe_instance *inst; int i; void *addr; - if (!kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset)) - return -EINVAL; + ret = kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset); + if (ret) + return ret; /* If only rp->kp.addr is specified, check reregistering kprobes */ if (rp->kp.addr && check_kprobe_rereg(&rp->kp)) --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -112,9 +112,9 @@ bool trace_kprobe_on_func_entry(struct t { struct trace_kprobe *tk = (struct trace_kprobe *)call->data; - return kprobe_on_func_entry(tk->rp.kp.addr, + return (kprobe_on_func_entry(tk->rp.kp.addr, tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name, - tk->rp.kp.addr ? 0 : tk->rp.kp.offset); + tk->rp.kp.addr ? 0 : tk->rp.kp.offset) == 0); } bool trace_kprobe_error_injectable(struct trace_event_call *call)