Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp4174181pxb; Mon, 8 Feb 2021 09:36:36 -0800 (PST) X-Google-Smtp-Source: ABdhPJzU9kep0AUwz+8ce+CZTWcMbYlTSrLZAGeQ8GvWgs+DoqNRWR/4T7TXcyUHmFOwjg7eh3uj X-Received: by 2002:a05:6402:3589:: with SMTP id y9mr18475769edc.344.1612805796584; Mon, 08 Feb 2021 09:36:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1612805796; cv=none; d=google.com; s=arc-20160816; b=m/6mbE4VT5ED4DvGUCXcRFCcNiDS+1+sNn2r7OiLfHQBLS9EScnEqcDHgfeV7rvPuU dotAzHsBGNt4661e34oghPxZG+C8f9Ehnhjlh24lKcMgCkVfu0BuWnt04++yfqy0vL4i y6oPkX3dwRABI+noUWxgRWqFPLlvXhT7EAxRwnjPzTy6K1yE5fQhUWYnw4eJpRyjsuPK Diqglw2SiLvrVSikZS4eaSpfpez7yYwU8dph95EvCFu/IwnAPgW0xZzZEoZiKUXHEXbO SaVCI47iCHmRAe20QN6CaDkk21fPdhsRehG/tSFrwJX2sF7wNjGHxY+7f6JuMcNPkl7p ajFw== 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=LxM+Z75HDCDPLJhKcgTD4CavgUAGRyWRrtYxYyDVG0Y=; b=rIBWEmvG9LzMzZFq37+oNbXwfFFNPeWYMa9NUsyN1XNwhF/cSYcfoFhXnQG88tI7lZ CRNdbX5YLcti4fshVRY2M4aOXIOrW1IruaUPbpESYO8JiLkgho799lpC4mpOnL/0YBon iIJJ2JsbT1DzvU631YSWUelkPdrc2X9eNGN85IzG5C2qYxpI/wyFUmxALtZhM44tUvth Oen9nnbQFQhvR3CEsDD3VaMpFryFyfg2/zlorpv5qpDNtDIdtR5w72U5OAdyaS64jEcW ihj7XrlA68tV2xRuOIGMSKGOk2iOkDgQ7pSOsO948NTr9TkExZpysoCe/geV4rR9soHh SENQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=UB1jcwXj; 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 de24si9132382ejc.234.2021.02.08.09.36.10; Mon, 08 Feb 2021 09:36:36 -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=UB1jcwXj; 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 S233470AbhBHRfR (ORCPT + 99 others); Mon, 8 Feb 2021 12:35:17 -0500 Received: from mail.kernel.org ([198.145.29.99]:37070 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233742AbhBHPaA (ORCPT ); Mon, 8 Feb 2021 10:30:00 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 15D8664E15; Mon, 8 Feb 2021 15:16:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1612797416; bh=pPjA3yeHHGBbfWZGwHX2qcSChmrCCpjamJpy06+U42E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UB1jcwXjFhZwaT33XxtHvQsSTfxEc1JWEoJ7+8uX03ihLeiOcKoYG96YPsv+ANcJw yKoje0TnhtZqh/OVALrrhysPIYc1BAFbsT/eGXXwbtrNZ9ap8Y96nKoHQFl1w5UI1i +tLHSmWVpBOOcESG/Cw70mCvoisj9jaA7wNRvB/I= 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 5.10 060/120] tracing/kprobe: Fix to support kretprobe events on unloaded modules Date: Mon, 8 Feb 2021 16:00:47 +0100 Message-Id: <20210208145820.818277358@linuxfoundation.org> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210208145818.395353822@linuxfoundation.org> References: <20210208145818.395353822@linuxfoundation.org> User-Agent: quilt/0.66 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 | 10 ++++++---- 3 files changed, 32 insertions(+), 14 deletions(-) --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -251,7 +251,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 @@ -2082,29 +2082,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 (kretprobe_blacklist_size) { addr = kprobe_addr(&rp->kp); --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -221,9 +221,9 @@ bool trace_kprobe_on_func_entry(struct t { struct trace_kprobe *tk = trace_kprobe_primary_from_call(call); - return tk ? kprobe_on_func_entry(tk->rp.kp.addr, + return tk ? (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) : false; + tk->rp.kp.addr ? 0 : tk->rp.kp.offset) == 0) : false; } bool trace_kprobe_error_injectable(struct trace_event_call *call) @@ -828,9 +828,11 @@ static int trace_kprobe_create(int argc, } if (is_return) flags |= TPARG_FL_RETURN; - if (kprobe_on_func_entry(NULL, symbol, offset)) + ret = kprobe_on_func_entry(NULL, symbol, offset); + if (ret == 0) flags |= TPARG_FL_FENTRY; - if (offset && is_return && !(flags & TPARG_FL_FENTRY)) { + /* Defer the ENOENT case until register kprobe */ + if (ret == -EINVAL && is_return) { trace_probe_log_err(0, BAD_RETPROBE); goto parse_error; }