Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp2740678pxa; Tue, 25 Aug 2020 01:44:46 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyJm44qbnw9wPJoi02BgVTwMjc8ALe7FqtZjsBepw84gK5xlVV6H8LmphwafO9j7A+AnXVX X-Received: by 2002:a17:906:b34c:: with SMTP id cd12mr8926356ejb.504.1598345086425; Tue, 25 Aug 2020 01:44:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1598345086; cv=none; d=google.com; s=arc-20160816; b=x5zdPmS3RjLgkdI2PIU0yACYMS/WwK1x1Wi2EeNKee4yXqkfYcHPEjHowN6yp5w2ko pjYwukJADRhp3RuOOEX/BVcjWLERk6xrtKLyReurN8GVzqkO1cjSRKvJBrU73SH0wRCy nh46cLLZZ1usqiDjV8cFY382SYbfaGcTCmPB3NeRuTLl8CjXfCyEvHtLLe5voda0UC8h uDYF36Sho66p6WSiDVzc28YeqTEQb4lQxcNI6mODz+H9XtvM06pbkPF0RZ/jxEwd/5cI SDyVJfX1cyTAZJ4VE7y3ReAYx+YVdWGjKKJ6u7VTMGt1nM23Z5ah1tSirgmtZWANw9Os uvmQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:subject:cc:to:from:date :dkim-signature; bh=Whc70fVuICjOx64VNRB3qoVtuNeI/BWsiWaPXwOLYe4=; b=S8k3oWClf8Tr07nG5hvtrXTKZmpchrf5IUbfTkaHwee0Vo+0FW6zchuPv2ZizK5dKu AJaWRVAw1F4lTzM9e3aYvaIWlYjGShBC7T43CufP+d2DkJAERkYqyC/XT2lE4qHEWSXp rX7zNrBTYHY2F9wM7uujghZj9fVxaDYxy1bYuOrVy5cKLSe/2ry+D/+omJccO3xCUhT8 xWZsltZFVjtaBmM4G5VKfkhsQ/CKZPqI8Os/KL+T6WoK8d9vnNeFx1mLQeDk3/gJlaHZ EJMFZMKRt2HQzVHZMMyga9BucjIShuhO1XO7WaN5PXzBAIFnvNYVVgQN1MJdSJSTdOb3 Whrw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=HV6kvZ4D; 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=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f6si400995ejq.238.2020.08.25.01.44.20; Tue, 25 Aug 2020 01:44:46 -0700 (PDT) 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=@kernel.org header.s=default header.b=HV6kvZ4D; 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=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728366AbgHYGPn (ORCPT + 99 others); Tue, 25 Aug 2020 02:15:43 -0400 Received: from mail.kernel.org ([198.145.29.99]:53752 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726015AbgHYGPn (ORCPT ); Tue, 25 Aug 2020 02:15:43 -0400 Received: from devnote2 (NE2965lan1.rev.em-net.ne.jp [210.141.244.193]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 0688B204FD; Tue, 25 Aug 2020 06:15:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1598336142; bh=4Ys01Quvr/gd6AZTKP/iqgZLXjT13MOc/IDtxKyLkLQ=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=HV6kvZ4Dd37J+2DemTZVu2CCmBeufhRzjBxFcLYnpPHjjJ6hwNjM3vUBGCm8FtEtB v3v97KRZq1nvpMdEzpT9uLJHTAS6nsHnpXlFzvNuVaZdQrw5siL7dVKfWo1qgStts7 B2M951JEOA2XhurFHVsMYyUT1PPw582xRgboY7vY= Date: Tue, 25 Aug 2020 15:15:38 +0900 From: Masami Hiramatsu To: "Eddy_Wu@trendmicro.com" Cc: Peter Zijlstra , "linux-kernel@vger.kernel.org" , "x86@kernel.org" , "David S. Miller" Subject: Re: x86/kprobes: kretprobe fails to triggered if kprobe at function entry is not optimized (trigger by int3 breakpoint) Message-Id: <20200825151538.f856d701a34f4e0561a64932@kernel.org> In-Reply-To: <7396e7b2079644a6aafd9670a111232b@trendmicro.com> References: <8816bdbbc55c4d2397e0b02aad2825d3@trendmicro.com> <20200825005426.f592075d13be740cb3c9aa77@kernel.org> <7396e7b2079644a6aafd9670a111232b@trendmicro.com> X-Mailer: Sylpheed 3.7.0 (GTK+ 2.24.32; x86_64-pc-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Eddy, On Mon, 24 Aug 2020 16:41:58 +0000 "Eddy_Wu@trendmicro.com" wrote: > > -----Original Message----- > > From: Masami Hiramatsu > > Sent: Monday, August 24, 2020 11:54 PM > > To: Eddy Wu (RD-TW) > > Cc: Peter Zijlstra ; linux-kernel@vger.kernel.org; x86@kernel.org; David S. Miller > > Subject: Re: x86/kprobes: kretprobe fails to triggered if kprobe at function entry is not optimized (trigger by int3 breakpoint) > > > > > > This message was sent from outside of Trend Micro. Please do not click links or open attachments unless you recognise the source of this > > email and know the content is safe. > > > > > > On Mon, 24 Aug 2020 12:02:58 +0000 > > "Eddy_Wu@trendmicro.com" wrote: > > > > > Greetings! > > > > > > Starting from kernel 5.8 (x86_64), kretprobe handler will always missed if corresponding kprobe on function entry is not optimized > > (using break point instead). > > > > Oops, good catch. I always enabled ftrace hook for kretprobe, I didn't noticed that. > > > > > Step to reproduce this: > > > 1) Build the kretprobe example module (CONFIG_SAMPLE_KRETPROBES=m) > > > 2) Disable jump optimization (`sysctl debug.kprobes-optimization=0` or register any kprobe.post_handler at same location) > > > 3) Insert the kretprobe_example module > > > 4) Launch some process to trigger _do_fork > > > 5) Remove kretprobe_example module > > > 6) dmesg shows that all probing instances are missed > > > > > > Example output: > > > # sysctl debug.kprobes-optimization=0 > > > debug.kprobes-optimization = 0 > > > # insmod samples/kprobes/kretprobe_example.ko > > > # ls > /dev/null > > > # rmmod kretprobe_example > > > # dmesg > > > [48555.067295] Planted return probe at _do_fork: 0000000038ae0211 > > > [48560.229459] kretprobe at 0000000038ae0211 unregistered > > > [48560.229460] Missed probing 3 instances of _do_fork > > > > > > After bisecting, I found this behavior seems to introduce by this commit: (5.8-rc1) > > > 0d00449c7a28a1514595630735df383dec606812 x86: Replace ist_enter() with nmi_enter() > > > This make kprobe_int3_handler() effectively running as NMI context, which pre_handler_kretprobe() explicitly checked to prevent > > recursion. > > > > Thanks for the bisecting! > > > > > > > > (in_nmi() check appears from v3.17) > > > f96f56780ca584930bb3a2769d73fd9a101bcbbe kprobes: Skip kretprobe hit in NMI context to avoid deadlock > > > > > > To make kretprobe work again with int3 breakpoint, I think we can replace the in_nmi() check with in_nmi() == (1 << NMI_SHIFT) at > > kprobe_int3_handler() and skip kretprobe if nested NMI. > > > > Ah, I see. Now int3 is a kind of NMI, so in the handler in_nmi() always returns !0. > > > > > Did a quick test on 5.9-rc2 and it seems to be working. > > > I'm not sure if it is the best way to do since it may also require change to other architecture as well, any thought? > > > > Hmm, this behavior is arch-dependent. So I think we need an weak function like this. > > > > @kernel/kprobes.c > > > > bool __weak arch_kprobe_in_nmi(void) > > { > > return in_nmi() > > } > > > > @arch/x86/kernel/kprobes/core.c > > > > bool arch_kprobe_in_nmi(void) > > { > > /* > > * Since the int3 is one of NMI, we have to check in_nmi() is > > * bigger than 1 << NMI_SHIFT instead of !0. > > */ > > return in_nmi() > (1 << NMI_SHIFT); > > } > > > > And use arch_kprobe_in_nmi() instead of in_nmi() in kprobes.c. > > > > Thanks, > > > > -- > > Masami Hiramatsu > > Kretprobe might still trigger from NMI with nmi counter == 1 (if entry kprobe is jump-optimized). Ah, right. Hmm, in that case, we can store the int3 status in the kprobe_ctlblk and refer it in the handler. > The arch- dependent weak function looks cleaner than doing this in kprobe_int3_handler() under x86/, but I don't know if there is a way to check if called by specific int3 handler or not. > > My original patch below, need to change all architecture support kretprobe though OK, here is my fix. This will not change the other arches. please try it. From 24390dffe6eb9a3e95f7d46a528a1dcfd716dc81 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 25 Aug 2020 01:37:00 +0900 Subject: [PATCH] kprobes/x86: Fixes NMI context check on x86 Since commit 0d00449c7a28 ("x86: Replace ist_enter() with nmi_enter()") made int3 as one of NMI, in_nmi() in kprobe handlers always returns !0. Thus the kretprobe handlers always skipped the execution on x86 if it is using int3. (CONFIG_KPROBES_ON_FTRACE=n and echo 0 > /proc/sys/debug/kprobe_optimization) To avoid this issue, introduce arch_kprobe_in_nmi() and check the in_nmi() count is bigger than 1 << NMI_SHIFT on x86 if the handler has been invoked from kprobe_int3_handler. By default, the arch_kprobe_in_nmi() will be same as in_nmi(). Fixes: 0d00449c7a28 ("x86: Replace ist_enter() with nmi_enter()") Reported-by: Eddy Wu Signed-off-by: Masami Hiramatsu Cc: stable@vger.kernel.org --- arch/x86/include/asm/kprobes.h | 1 + arch/x86/kernel/kprobes/core.c | 18 ++++++++++++++++++ kernel/kprobes.c | 8 +++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h index 143bc9abe99c..ddb24feb95ad 100644 --- a/arch/x86/include/asm/kprobes.h +++ b/arch/x86/include/asm/kprobes.h @@ -98,6 +98,7 @@ struct kprobe_ctlblk { unsigned long kprobe_old_flags; unsigned long kprobe_saved_flags; struct prev_kprobe prev_kprobe; + bool in_int3; }; extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 2ca10b770cff..649d467c8231 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -583,6 +583,20 @@ static nokprobe_inline void restore_btf(void) } } +bool arch_kprobe_in_nmi(void) +{ + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (kcb->in_int3) { + /* + * Since the int3 is one of NMI, we have to check in_nmi() is + * bigger than 1 << NMI_SHIFT instead of !0. + */ + return in_nmi() > (1 << NMI_SHIFT); + } else + return in_nmi(); +} + void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { unsigned long *sara = stack_addr(regs); @@ -697,6 +711,7 @@ int kprobe_int3_handler(struct pt_regs *regs) return 1; } else { set_current_kprobe(p, regs, kcb); + kcb->in_int3 = true; kcb->kprobe_status = KPROBE_HIT_ACTIVE; /* @@ -710,6 +725,7 @@ int kprobe_int3_handler(struct pt_regs *regs) setup_singlestep(p, regs, kcb, 0); else reset_current_kprobe(); + kcb->in_int3 = false; return 1; } } else if (*addr != INT3_INSN_OPCODE) { @@ -994,7 +1010,9 @@ int kprobe_debug_handler(struct pt_regs *regs) if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { kcb->kprobe_status = KPROBE_HIT_SSDONE; + kcb->in_int3 = true; cur->post_handler(cur, regs, 0); + kcb->in_int3 = false; } /* Restore back the original saved kprobes variables and continue. */ diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 287b263c9cb9..9564928fb882 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1927,6 +1927,12 @@ unsigned long __weak arch_deref_entry_point(void *entry) } #ifdef CONFIG_KRETPROBES + +bool __weak arch_kprobe_in_nmi(void) +{ + return in_nmi(); +} + /* * This kprobe pre_handler is registered with every kretprobe. When probe * hits it will set up the return probe. @@ -1943,7 +1949,7 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) * statistical counter, so that the user is informed that * something happened: */ - if (unlikely(in_nmi())) { + if (unlikely(arch_kprobe_in_nmi())) { rp->nmissed++; return 0; } -- 2.25.1 -- Masami Hiramatsu