From patchwork Tue Mar 30 19:09:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Madhavan T. Venkataraman" X-Patchwork-Id: 12173593 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84DD8C433C1 for ; Tue, 30 Mar 2021 19:12:51 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EB39761998 for ; Tue, 30 Mar 2021 19:12:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EB39761998 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=9fDy6vgT4jUpCObhWyM3VQML6VUbIcyxfB9CZcpnqPo=; b=mXGYOvVivQWN58cx7hLrBdtTz W7ae5K2uYA7g4jB3TVXfHELOLnAKnOfWdlkGxMIH7VA1zo4y4ibglRM/wowZnmkEKVvirSe1pGCnF H9a0CYwmzy2l06l4XGbmmhHbooWhDu0O8VsjgGtKevKuTnOzcMQmu+gq8FiBbCgw/00+WjttctEWJ w+yIuoMINCJvF3KbHRNvwNMOo/4miga/Ri8W+GHT8d8qrNyAyXWpe2jwP0TFB3lmQzLB69UuVHZ2s AVbWve0JZsW1Su5ABoR2yOCnOUQCM/UTW4FqMxKw0SanDTIl041IRHfhyvaA93v7IpJPJJUT75icM hTlHobJLg==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJlX-004gdX-QW; Tue, 30 Mar 2021 19:11:03 +0000 Received: from linux.microsoft.com ([13.77.154.182]) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJkd-004gZv-Mk for linux-arm-kernel@lists.infradead.org; Tue, 30 Mar 2021 19:10:14 +0000 Received: from x64host.home (unknown [47.187.194.202]) by linux.microsoft.com (Postfix) with ESMTPSA id 532E020B5680; Tue, 30 Mar 2021 12:10:03 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 532E020B5680 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1617131404; bh=Q73XCtD3h8sCsPmxTLvtfVtrZv9vCQxH/D2OWaUjTkY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=TtjXtRuNrG2QkAf3llREdetY6o6aLGy9PBryQS/0Kwq1ufBPRBCdoYsJir8E7syx/ D/eob10Ojeq30xLsQx1UIKpmaQTusOLNnnvNBqWNJZsabPZyXpjFT8hjds3GymPbJu +6aWnXJ42W94iUAkPYMFtzrg/GirCsFjLxYuOdfE= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, jthierry@redhat.com, catalin.marinas@arm.com, will@kernel.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v1 1/4] arm64: Implement infrastructure for stack trace reliability checks Date: Tue, 30 Mar 2021 14:09:52 -0500 Message-Id: <20210330190955.13707-2-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210330190955.13707-1-madvenka@linux.microsoft.com> References: <77bd5edeea72d44533c769b1e8c0fea7a9d7eb3a> <20210330190955.13707-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_201008_276687_9C84BAB5 X-CRM114-Status: GOOD ( 19.24 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: "Madhavan T. Venkataraman" Implement a check_reliability() function that will contain checks for the presence of various features and conditions that can render the stack trace unreliable. Introduce the first reliability check - If a return PC encountered in a stack trace is not a valid kernel text address, the stack trace is considered unreliable. It could be some generated code. Other reliability checks will be added in the future. These checks will involve checking the return PC to see if it falls inside any special functions where the stack trace is considered unreliable. Implement the infrastructure needed for this. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/include/asm/stacktrace.h | 2 + arch/arm64/kernel/stacktrace.c | 80 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index eb29b1fe8255..684f65808394 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -59,6 +59,7 @@ struct stackframe { #ifdef CONFIG_FUNCTION_GRAPH_TRACER int graph; #endif + bool reliable; }; extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); @@ -169,6 +170,7 @@ static inline void start_backtrace(struct stackframe *frame, bitmap_zero(frame->stacks_done, __NR_STACK_TYPES); frame->prev_fp = 0; frame->prev_type = STACK_TYPE_UNKNOWN; + frame->reliable = true; } #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index ad20981dfda4..ff35b3953c39 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -18,6 +18,84 @@ #include #include +struct function_range { + unsigned long start; + unsigned long end; +}; + +/* + * Special functions where the stack trace is unreliable. + */ +static struct function_range special_functions[] = { + { 0, 0 } +}; + +static bool is_reliable_function(unsigned long pc) +{ + static bool inited = false; + struct function_range *func; + + if (!inited) { + static char sym[KSYM_NAME_LEN]; + unsigned long size, offset; + + for (func = special_functions; func->start; func++) { + if (kallsyms_lookup(func->start, &size, &offset, + NULL, sym)) { + func->start -= offset; + func->end = func->start + size; + } else { + /* + * This is just a label. So, we only need to + * consider that particular location. So, size + * is the size of one Aarch64 instruction. + */ + func->end = func->start + 4; + } + } + inited = true; + } + + for (func = special_functions; func->start; func++) { + if (pc >= func->start && pc < func->end) + return false; + } + return true; +} + +/* + * Check for the presence of features and conditions that render the stack + * trace unreliable. + * + * Once all such cases have been addressed, this function can aid live + * patching (and this comment can be removed). + */ +static void check_reliability(struct stackframe *frame) +{ + /* + * If the stack trace has already been marked unreliable, just return. + */ + if (!frame->reliable) + return; + + /* + * First, make sure that the return address is a proper kernel text + * address. A NULL or invalid return address probably means there's + * some generated code which __kernel_text_address() doesn't know + * about. Mark the stack trace as not reliable. + */ + if (!__kernel_text_address(frame->pc)) { + frame->reliable = false; + return; + } + + /* + * Check the reliability of the return PC's function. + */ + if (!is_reliable_function(frame->pc)) + frame->reliable = false; +} + /* * AArch64 PCS assigns the frame pointer to x29. * @@ -108,6 +186,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) frame->pc = ptrauth_strip_insn_pac(frame->pc); + check_reliability(frame); + return 0; } NOKPROBE_SYMBOL(unwind_frame); From patchwork Tue Mar 30 19:09:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Madhavan T. Venkataraman" X-Patchwork-Id: 12173589 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73AB8C433E0 for ; Tue, 30 Mar 2021 19:12:28 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D814B61998 for ; Tue, 30 Mar 2021 19:12:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D814B61998 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=0BO6iJFBMPBaOqVmKVrjLlTv8/s/R1zVsa7on+CbyC0=; b=Kw9gBI4tbCAJHKT46S9Og+1y2 y2oFs1eFC3Ea/wNBgRwtCE3dp/FnkJRZugPFu7YSgz2BYmoIv7kuEAgxtGejtMOhcO9MkLkxU7zLh ssrTIQQqZi12T/f2nDv1255Lldy4ztEgA2m1b4f1TZ2jy/b3q7400XQFkS+GMk8umvWbOOQCVxP/Y C4F5WudcGuyEsV/EwFpauoIT0AbGqowyD9YLqvJE/FwXujbllC0bLFGjFe7FLNXnHwL6tZi1ehaA8 XnfjY3ke6OhNaQkYqYx1vC64RVvRVeKu3GmeOMdA0o3Aoi16pwSrW36LQRCJkCaLUfKjRGmoAkbst Wbg20jm/A==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJkn-004gbT-Vt; Tue, 30 Mar 2021 19:10:26 +0000 Received: from linux.microsoft.com ([13.77.154.182]) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJke-004gZx-4S for linux-arm-kernel@lists.infradead.org; Tue, 30 Mar 2021 19:10:12 +0000 Received: from x64host.home (unknown [47.187.194.202]) by linux.microsoft.com (Postfix) with ESMTPSA id 3ABA320B5681; Tue, 30 Mar 2021 12:10:04 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 3ABA320B5681 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1617131404; bh=8WqRBqOL5eacZZZ/2y2AI7eJekzqSItDIQKWe5DSzMo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pR2pY9KKd8J3Bj0Xvj/kLNGgCmwf4ynx7Xk8uUqwRdn2ubbi8J9qCGcMq9VItPQcu PiooUS+0/EnjY76r5o1lNbfiTgIb90FsZYBBIQkHIGBa+NBSFcBTZ5NJ2/yHy/Hv6I BDmIqNEfwOAJKWk+JiAEjVmWvyo/ph5ZgdRyXmwg= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, jthierry@redhat.com, catalin.marinas@arm.com, will@kernel.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v1 2/4] arm64: Mark a stack trace unreliable if an EL1 exception frame is detected Date: Tue, 30 Mar 2021 14:09:53 -0500 Message-Id: <20210330190955.13707-3-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210330190955.13707-1-madvenka@linux.microsoft.com> References: <77bd5edeea72d44533c769b1e8c0fea7a9d7eb3a> <20210330190955.13707-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_201008_849431_9C82BE3E X-CRM114-Status: GOOD ( 17.48 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: "Madhavan T. Venkataraman" EL1 exceptions can happen on any instruction including instructions in the frame pointer prolog or epilog. Depending on where exactly they happen, they could render the stack trace unreliable. If an EL1 exception frame is found on the stack, mark the stack trace as unreliable. Now, the EL1 exception frame is not at any well-known offset on the stack. It can be anywhere on the stack. In order to properly detect an EL1 exception frame, the return address must be checked against all of the possible EL1 exception handlers. Preemption ========== Interrupts encountered in kernel code are also EL1 exceptions. At the end of an interrupt, the interrupt handler checks if the current task must be preempted for any reason. If so, it calls the preemption code which takes the task off the CPU. A stack trace taken on the task after the preemption will show the EL1 frame and will be considered unreliable. This is correct behavior as preemption can happen practically at any point in code. Probing ======= Breakpoints encountered in kernel code are also EL1 exceptions. The probing infrastructure uses breakpoints for executing probe code. While in the probe code, the stack trace will show an EL1 frame and will be considered unreliable. This is also correct behavior. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/include/asm/exception.h | 8 +++++++ arch/arm64/kernel/entry.S | 14 +++++------ arch/arm64/kernel/stacktrace.c | 37 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h index 6546158d2f2d..4ebd2390ef54 100644 --- a/arch/arm64/include/asm/exception.h +++ b/arch/arm64/include/asm/exception.h @@ -35,6 +35,14 @@ asmlinkage void el1_sync_handler(struct pt_regs *regs); asmlinkage void el0_sync_handler(struct pt_regs *regs); asmlinkage void el0_sync_compat_handler(struct pt_regs *regs); +asmlinkage void el1_sync(void); +asmlinkage void el1_irq(void); +asmlinkage void el1_error(void); +asmlinkage void el1_sync_invalid(void); +asmlinkage void el1_irq_invalid(void); +asmlinkage void el1_fiq_invalid(void); +asmlinkage void el1_error_invalid(void); + asmlinkage void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs); asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs); asmlinkage void enter_from_user_mode(void); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a31a0a713c85..9fe3aaeff019 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -630,19 +630,19 @@ SYM_CODE_START_LOCAL(el0_fiq_invalid_compat) SYM_CODE_END(el0_fiq_invalid_compat) #endif -SYM_CODE_START_LOCAL(el1_sync_invalid) +SYM_CODE_START(el1_sync_invalid) inv_entry 1, BAD_SYNC SYM_CODE_END(el1_sync_invalid) -SYM_CODE_START_LOCAL(el1_irq_invalid) +SYM_CODE_START(el1_irq_invalid) inv_entry 1, BAD_IRQ SYM_CODE_END(el1_irq_invalid) -SYM_CODE_START_LOCAL(el1_fiq_invalid) +SYM_CODE_START(el1_fiq_invalid) inv_entry 1, BAD_FIQ SYM_CODE_END(el1_fiq_invalid) -SYM_CODE_START_LOCAL(el1_error_invalid) +SYM_CODE_START(el1_error_invalid) inv_entry 1, BAD_ERROR SYM_CODE_END(el1_error_invalid) @@ -650,7 +650,7 @@ SYM_CODE_END(el1_error_invalid) * EL1 mode handlers. */ .align 6 -SYM_CODE_START_LOCAL_NOALIGN(el1_sync) +SYM_CODE_START_NOALIGN(el1_sync) kernel_entry 1 mov x0, sp bl el1_sync_handler @@ -658,7 +658,7 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_sync) SYM_CODE_END(el1_sync) .align 6 -SYM_CODE_START_LOCAL_NOALIGN(el1_irq) +SYM_CODE_START_NOALIGN(el1_irq) kernel_entry 1 gic_prio_irq_setup pmr=x20, tmp=x1 enable_da_f @@ -737,7 +737,7 @@ el0_irq_naked: b ret_to_user SYM_CODE_END(el0_irq) -SYM_CODE_START_LOCAL(el1_error) +SYM_CODE_START(el1_error) kernel_entry 1 mrs x1, esr_el1 gic_prio_kentry_setup tmp=x2 diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index ff35b3953c39..7662f57d3e88 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -25,8 +26,44 @@ struct function_range { /* * Special functions where the stack trace is unreliable. + * + * EL1 exceptions + * ============== + * + * EL1 exceptions can happen on any instruction including instructions in + * the frame pointer prolog or epilog. Depending on where exactly they happen, + * they could render the stack trace unreliable. + * + * If an EL1 exception frame is found on the stack, mark the stack trace as + * unreliable. Now, the EL1 exception frame is not at any well-known offset + * on the stack. It can be anywhere on the stack. In order to properly detect + * an EL1 exception frame, the return address must be checked against all of + * the possible EL1 exception handlers. + * + * Interrupts encountered in kernel code are also EL1 exceptions. At the end + * of an interrupt, the current task can get preempted. A stack trace taken + * on the task after the preemption will show the EL1 frame and will be + * considered unreliable. This is correct behavior as preemption can happen + * practically at any point in code. + * + * Breakpoints encountered in kernel code are also EL1 exceptions. Breakpoints + * can happen practically on any instruction. Mark the stack trace as + * unreliable. Breakpoints are used for executing probe code. Stack traces + * taken while in the probe code will show an EL1 frame and will be considered + * unreliable. This is correct behavior. */ static struct function_range special_functions[] = { + /* + * EL1 exception handlers. + */ + { (unsigned long) el1_sync, 0 }, + { (unsigned long) el1_irq, 0 }, + { (unsigned long) el1_error, 0 }, + { (unsigned long) el1_sync_invalid, 0 }, + { (unsigned long) el1_irq_invalid, 0 }, + { (unsigned long) el1_fiq_invalid, 0 }, + { (unsigned long) el1_error_invalid, 0 }, + { 0, 0 } }; From patchwork Tue Mar 30 19:09:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Madhavan T. Venkataraman" X-Patchwork-Id: 12173587 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8BF2DC433C1 for ; Tue, 30 Mar 2021 19:12:27 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0EC99619CD for ; Tue, 30 Mar 2021 19:12:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0EC99619CD Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=K+yKs3aCA9XAzZbJT+6FONH44iIS6G8jW2QwBS62JnM=; b=qNRqU7Q6nR+dF6qiV2PkydxhT kKQlAqyR0BEf4WJXTZQN9TiHZ/psKv8fIRsnOXngk2Yt9fT/0HWVGPPvA7r7YNjaG273zFy5Zm5tv xwuopHASWm4E2aUv7H4o4w/0pWqQ5nrJ7OgsOW2sY/3iqNYQI4RlToAxxbvtbQj6TcI2E769Jn2M1 DK8oQvGuw4DJ+fNxTvg4UjLBBYnI+RPYLUfTaGdF1iixiB8k9V6HK6NwFbXhB6Pq5aoO1mt5MAWRP q3lX5WxPw0dohzCWGsywBuuibprlYNGCGwh4hfJNkhl2Gg/JTflQkQYHqQMrmp/t0Ni1P9f2U82dL lXHmvPrlg==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJlE-004gce-6k; Tue, 30 Mar 2021 19:10:44 +0000 Received: from linux.microsoft.com ([13.77.154.182]) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJke-004gZy-8J for linux-arm-kernel@lists.infradead.org; Tue, 30 Mar 2021 19:10:12 +0000 Received: from x64host.home (unknown [47.187.194.202]) by linux.microsoft.com (Postfix) with ESMTPSA id 2059920B5682; Tue, 30 Mar 2021 12:10:05 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 2059920B5682 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1617131405; bh=hJ+tRyaOajTKVDku/PeJpOdfpmhUZp9TFHFGI2dnanc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=G8rLUhl3BJ4zjRJeNxjMkf0XMN2QZMfRlr51MvT+D4OKGuwB/pMgpdP2qHA7DvCYc 79p+hGKoAGYcE2NAuWr/qZNdOQn1iU/7CTXCrzxEv9SBghKlXLua08lLlYbpQ9m53o vqwLTDFFUvulLl1qSYxTRuSo0zVKRs754n1b+sx0= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, jthierry@redhat.com, catalin.marinas@arm.com, will@kernel.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v1 3/4] arm64: Detect FTRACE cases that make the stack trace unreliable Date: Tue, 30 Mar 2021 14:09:54 -0500 Message-Id: <20210330190955.13707-4-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210330190955.13707-1-madvenka@linux.microsoft.com> References: <77bd5edeea72d44533c769b1e8c0fea7a9d7eb3a> <20210330190955.13707-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_201008_857908_43896F24 X-CRM114-Status: GOOD ( 24.17 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: "Madhavan T. Venkataraman" When CONFIG_DYNAMIC_FTRACE_WITH_REGS is enabled and tracing is activated for a function, the ftrace infrastructure is called for the function at the very beginning. Ftrace creates two frames: - One for the traced function - One for the caller of the traced function That gives a reliable stack trace while executing in the ftrace code. When ftrace returns to the traced function, the frames are popped and everything is back to normal. However, in cases like live patch, a tracer function may redirect execution to a different function when it returns. A stack trace taken while still in the tracer function will not show the target function. The target function is the real function that we want to track. So, if an FTRACE frame is detected on the stack, just mark the stack trace as unreliable. The detection is done by checking the return PC against FTRACE trampolines. Also, the Function Graph Tracer modifies the return address of a traced function to a return trampoline to gather tracing data on function return. Stack traces taken from that trampoline and functions it calls are unreliable as the original return address may not be available in that context. Mark the stack trace unreliable accordingly. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/kernel/entry-ftrace.S | 10 ++++++ arch/arm64/kernel/stacktrace.c | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S index b3e4f9a088b1..5373f88b4c44 100644 --- a/arch/arm64/kernel/entry-ftrace.S +++ b/arch/arm64/kernel/entry-ftrace.S @@ -95,6 +95,16 @@ SYM_CODE_START(ftrace_common) SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) bl ftrace_stub + /* + * The only call in the FTRACE trampoline code is above. The above + * instruction is patched to call a tracer function. Its return + * address is below (ftrace_graph_call). In a stack trace taken from + * a tracer function, ftrace_graph_call() will show. The unwinder + * checks this for reliable stack trace. Please see the comments + * in stacktrace.c. If another call is added in the FTRACE + * trampoline code, the special_functions[] array in stacktrace.c + * must be updated. + */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller(); nop // If enabled, this will be replaced diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 7662f57d3e88..8b493a90c9f3 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -51,6 +51,52 @@ struct function_range { * unreliable. Breakpoints are used for executing probe code. Stack traces * taken while in the probe code will show an EL1 frame and will be considered * unreliable. This is correct behavior. + * + * FTRACE + * ====== + * + * When CONFIG_DYNAMIC_FTRACE_WITH_REGS is enabled, the FTRACE trampoline code + * is called from a traced function even before the frame pointer prolog. + * FTRACE sets up two stack frames (one for the traced function and one for + * its caller) so that the unwinder can provide a sensible stack trace for + * any tracer function called from the FTRACE trampoline code. + * + * There are two cases where the stack trace is not reliable. + * + * (1) The task gets preempted before the two frames are set up. Preemption + * involves an interrupt which is an EL1 exception. The unwinder already + * handles EL1 exceptions. + * + * (2) The tracer function that gets called by the FTRACE trampoline code + * changes the return PC (e.g., livepatch). + * + * Not all tracer functions do that. But to err on the side of safety, + * consider the stack trace as unreliable in all cases. + * + * When Function Graph Tracer is used, FTRACE modifies the return address of + * the traced function in its stack frame to an FTRACE return trampoline + * (return_to_handler). When the traced function returns, control goes to + * return_to_handler. return_to_handler calls FTRACE to gather tracing data + * and to obtain the original return address. Then, return_to_handler returns + * to the original return address. + * + * There are two cases to consider from a stack trace reliability point of + * view: + * + * (1) Stack traces taken within the traced function (and functions that get + * called from there) will show return_to_handler instead of the original + * return address. The original return address can be obtained from FTRACE. + * The unwinder already obtains it and modifies the return PC in its copy + * of the stack frame to the original return address. So, this is handled. + * + * (2) return_to_handler calls FTRACE as mentioned before. FTRACE discards + * the record of the original return address along the way as it does not + * need to maintain it anymore. This means that the unwinder cannot get + * the original return address beyond that point while the task is still + * executing in return_to_handler. So, consider the stack trace unreliable + * if return_to_handler is detected on the stack. + * + * NOTE: The unwinder must do (1) before (2). */ static struct function_range special_functions[] = { /* @@ -64,6 +110,17 @@ static struct function_range special_functions[] = { { (unsigned long) el1_fiq_invalid, 0 }, { (unsigned long) el1_error_invalid, 0 }, + /* + * FTRACE trampolines. + */ +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + { (unsigned long) &ftrace_graph_call, 0 }, +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + { (unsigned long) ftrace_graph_caller, 0 }, + { (unsigned long) return_to_handler, 0 }, +#endif +#endif + { 0, 0 } }; From patchwork Tue Mar 30 19:09:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Madhavan T. Venkataraman" X-Patchwork-Id: 12173595 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40345C433DB for ; Tue, 30 Mar 2021 19:12:57 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AD07E619CC for ; Tue, 30 Mar 2021 19:12:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AD07E619CC Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=eNe0ZDA8bDFaLWYNRN8sgS/vrIdFRYx3Bz/QF9n3L/o=; b=pnlfODViWw2Mhi8Sp/QivS3Jo kEl7dWZHws3iGaERynJnEyY2IFnWSWzuvho9nq6mX9h+0rJ+537bGkYBk1GtHmwfogc+f7cpceGqq NbUO+Xt0//ETwlS88xtg+3m46lE3kXM8we0QFINKihqo8o0drZwwPr3RGk2uH6CgRu5mr9Dn7NRUP jKpKxIZPSRNVPoHz2Hnrfy+7ud9q+RLeH3wmbD6aFhVy9ed+P9lyc4sgwifujBb8Kogy9p5iX6dtp R3qjs8ylGHplqOBKHTGfqdyUSXAGh3rtwYy4TlvNfvKmeWTcG7n33vjZiFt1RwudRyX1Sx0pbMbSn m+/dKw+mg==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJll-004gfO-2Y; Tue, 30 Mar 2021 19:11:17 +0000 Received: from linux.microsoft.com ([13.77.154.182]) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRJkk-004gZz-A7 for linux-arm-kernel@lists.infradead.org; Tue, 30 Mar 2021 19:10:16 +0000 Received: from x64host.home (unknown [47.187.194.202]) by linux.microsoft.com (Postfix) with ESMTPSA id 0607C20B5683; Tue, 30 Mar 2021 12:10:05 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0607C20B5683 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1617131406; bh=tG53wNZpf8HBZJKuIfmKDNwBoTuKOAvtDqAtxH3M2v0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Rb2oJC71omuekDN5ZjPznt6w7CJFxUAwPMV1nc5iwpLcnYy02Kn3eLR/PnzsROHS6 CHvro9WlnChrnD4/L3Jf8hzFGWVMQcQr5OcD0aDZjhfw4SBAbYChL3Ti0h/kE/wVNj QruGMqLmy7dE7nEtXQWwfCZJIc9sMUxX7ijnSInc= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, jthierry@redhat.com, catalin.marinas@arm.com, will@kernel.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v1 4/4] arm64: Mark stack trace as unreliable if kretprobed functions are present Date: Tue, 30 Mar 2021 14:09:55 -0500 Message-Id: <20210330190955.13707-5-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210330190955.13707-1-madvenka@linux.microsoft.com> References: <77bd5edeea72d44533c769b1e8c0fea7a9d7eb3a> <20210330190955.13707-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_201015_123819_F864A539 X-CRM114-Status: GOOD ( 20.46 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: "Madhavan T. Venkataraman" When a kretprobe is active for a function, the function's return address in its stack frame is modified to point to the kretprobe trampoline. When the function returns, the frame is popped and control is transferred to the trampoline. The trampoline eventually returns to the original return address. If a stack walk is done within the function (or any functions that get called from there), the stack trace will only show the trampoline and the not the original caller. Also, if the trampoline itself and the functions it calls do a stack trace, that stack trace will also have the same problem. Detect this as well. If the trampoline is detected in the stack trace, mark the stack trace as unreliable. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/kernel/stacktrace.c | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 8b493a90c9f3..bf5abb0dd876 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -97,6 +97,36 @@ struct function_range { * if return_to_handler is detected on the stack. * * NOTE: The unwinder must do (1) before (2). + * + * KPROBES + * ======= + * + * There are two types of kprobes: + * + * (1) Regular kprobes that are placed anywhere in a probed function. + * This is implemented by replacing the probed instruction with a + * breakpoint. When the breakpoint is hit, the kprobe code emulates + * the original instruction in-situ and returns to the next + * instruction. + * + * Breakpoints are EL1 exceptions. When the unwinder detects them, + * the stack trace is marked as unreliable as it does not know where + * exactly the exception happened. Detection of EL1 exceptions in + * a stack trace will be done separately. + * + * (2) Return kprobes that are placed on the return of a probed function. + * In this case, Kprobes sets up an initial breakpoint at the + * beginning of the probed function. When the breakpoint is hit, + * Kprobes replaces the return address in the stack frame with the + * kretprobe_trampoline and records the original return address. + * When the probed function returns, control goes to the trampoline + * which eventually returns to the original return address. + * + * Stack traces taken while in the probed function or while in the + * trampoline will show kretprobe_trampoline instead of the original + * return address. Detect this and mark the stack trace unreliable. + * The detection is done by checking if the return PC falls anywhere + * in kretprobe_trampoline. */ static struct function_range special_functions[] = { /* @@ -121,6 +151,13 @@ static struct function_range special_functions[] = { #endif #endif + /* + * Kprobe trampolines. + */ +#ifdef CONFIG_KRETPROBES + { (unsigned long) kretprobe_trampoline, 0 }, + #endif + { 0, 0 } };