Received: by 10.223.185.116 with SMTP id b49csp2798246wrg; Mon, 5 Mar 2018 08:51:14 -0800 (PST) X-Google-Smtp-Source: AG47ELtYkt/+m1xdjsnY0NvP23TZI/yhlMqzgXjn3BRtoM46zUTcKRrLSxkdTFAU5UzPOxiNRO8a X-Received: by 2002:a17:902:20e6:: with SMTP id v35-v6mr13658146plg.226.1520268674658; Mon, 05 Mar 2018 08:51:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520268674; cv=none; d=google.com; s=arc-20160816; b=Z+GgGvfsIl8ZxkMNUDyZGeaPOMknIaaG36NAp6UUzvgK78g7/wSjA4uyKMlKjlr/R5 mFT4+e2HOysy+QXSEM1uyLfB9m09uHPvktjIqHKwE+UJvyWmFspRWHgrzhe1LkpcwGGG z3WPiw291R9dPa9/oNGfLnV9tfw2r1aVE1HNyufwnREC87ayMNQ6sYYzqAr2f+FQZ8+9 qOzAp7d8o1+Wo5wgntsf0Odew/a0hmKKFszavs/5OlT3hCwuIUOIjqTwaZPolxbUYvtg QLpQ+AeuGIJ2e/bw7bSkfJMppAs7x2JPhY0sJbFT73xHdMht7avkbL8aG/wtowR2HeWO 8QWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:content-transfer-encoding :content-disposition:mime-version:message-id:subject:cc:to:from:date :arc-authentication-results; bh=I8G71w8+LdlTEZx1b/QVIwlq4Om+R+meFQAVlyk/JrQ=; b=zlFGgwmFawsSrp2MolVNblwSStqo8E+IUO/3HJoQ8BICoFOLoM0PciH7aMAeNFWuPQ 5NHOwEz+4anvBp952ZLGQlggsFaMiju5j2K/t81MgXFoHWNMrCZRPprc5qpsgFElbMw8 Bu+02dtoRaLfc5li4nKgGOMYxW+KzNpevIxVf+mHekqUmLXS03bU7C0tMMHqvm7q74J6 e4VBb6KvITKoRbts4ANZ5KbEBRthXzSbP1d0i4sCargU7Lv/NZVAKFjRyiJMDY1cfQDh BudJVoETaI2hzjkz1YX4xMmYW0tRVZ4KcQBwPqL7wLfTyyB+OQPCaO+/SSuEGGWwLOo+ YLCg== 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 y128si8600137pgb.126.2018.03.05.08.50.59; Mon, 05 Mar 2018 08:51:14 -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 S1752561AbeCEQte (ORCPT + 99 others); Mon, 5 Mar 2018 11:49:34 -0500 Received: from verein.lst.de ([213.95.11.211]:48414 "EHLO newverein.lst.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751462AbeCEQta (ORCPT ); Mon, 5 Mar 2018 11:49:30 -0500 Received: by newverein.lst.de (Postfix, from userid 2005) id 8619A68DD6; Mon, 5 Mar 2018 17:49:28 +0100 (CET) Date: Mon, 5 Mar 2018 17:49:28 +0100 From: Torsten Duwe To: Michael Ellerman Cc: Jiri Kosina , Josh Poimboeuf , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, Nicholas Piggin , live-patching@vger.kernel.org Subject: [PATCH v2] On ppc64le we HAVE_RELIABLE_STACKTRACE Message-ID: <20180305164928.GA17953@lst.de> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.5.17 (2007-11-01) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The "Power Architecture 64-Bit ELF V2 ABI" says in section 2.3.2.3: [...] There are several rules that must be adhered to in order to ensure reliable and consistent call chain backtracing: * Before a function calls any other function, it shall establish its own stack frame, whose size shall be a multiple of 16 bytes. – In instances where a function’s prologue creates a stack frame, the back-chain word of the stack frame shall be updated atomically with the value of the stack pointer (r1) when a back chain is implemented. (This must be supported as default by all ELF V2 ABI-compliant environments.) [...] – The function shall save the link register that contains its return address in the LR save doubleword of its caller’s stack frame before calling another function. To me this sounds like the equivalent of HAVE_RELIABLE_STACKTRACE. This patch may be unneccessarily limited to ppc64le, but OTOH the only user of this flag so far is livepatching, which is only implemented on PPCs with 64-LE, a.k.a. ELF ABI v2. This change also implements save_stack_trace_tsk_reliable() for ppc64 that checks for the above conditions, where possible. Signed-off-by: Torsten Duwe --- v2: * implemented save_stack_trace_tsk_reliable(), with a bunch of sanity checks. The test for a kernel code pointer is much nicer now, and the exit condition is exact (when compared to last week's follow-up) --- diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 73ce5dd07642..9f49913e19e3 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -220,6 +220,7 @@ config PPC select HAVE_PERF_USER_STACK_DUMP select HAVE_RCU_TABLE_FREE if SMP select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RELIABLE_STACKTRACE if PPC64 && CPU_LITTLE_ENDIAN select HAVE_SYSCALL_TRACEPOINTS select HAVE_VIRT_CPU_ACCOUNTING select HAVE_IRQ_TIME_ACCOUNTING diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index d534ed901538..e14c2dfd5311 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c @@ -11,8 +11,11 @@ */ #include +#include +#include #include #include +#include #include #include #include @@ -76,3 +79,77 @@ save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) save_context_stack(trace, regs->gpr[1], current, 0); } EXPORT_SYMBOL_GPL(save_stack_trace_regs); + +#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE +int +save_stack_trace_tsk_reliable(struct task_struct *tsk, + struct stack_trace *trace) +{ + unsigned long sp; + unsigned long stack_page = (unsigned long)task_stack_page(tsk); + + /* The last frame (unwinding first) may not yet have saved + * its LR onto the stack. + */ + int firstframe = 1; + + if (tsk == current) + sp = current_stack_pointer(); + else + sp = tsk->thread.ksp; + + if (sp < stack_page + sizeof(struct thread_struct) + || sp > stack_page + THREAD_SIZE - STACK_FRAME_OVERHEAD) + return 1; + + for (;;) { + unsigned long *stack = (unsigned long *) sp; + unsigned long newsp, ip; + + /* sanity check: ABI requires SP to be aligned 16 bytes. */ + if (sp & 0xF) + return 1; + + newsp = stack[0]; + /* Stack grows downwards; unwinder may only go up. */ + if (newsp <= sp) + return 1; + + if (newsp >= stack_page + THREAD_SIZE) + return 1; /* invalid backlink, too far up. */ + + /* Examine the saved LR: it must point into kernel code. */ + ip = stack[STACK_FRAME_LR_SAVE]; + if (!firstframe) { + if (!func_ptr_is_kernel_text((void *)ip)) { +#ifdef CONFIG_MODULES + struct module *mod = __module_text_address(ip); + + if (!mod) +#endif + return 1; + } + } + firstframe = 0; + + if (!trace->skip) + trace->entries[trace->nr_entries++] = ip; + else + trace->skip--; + + /* SP value loaded on kernel entry, see "PACAKSAVE(r13)" in + * _switch() and system_call_common() + */ + if (newsp == stack_page + THREAD_SIZE - /* SWITCH_FRAME_SIZE */ + (STACK_FRAME_OVERHEAD + sizeof(struct pt_regs))) + break; + + if (trace->nr_entries >= trace->max_entries) + return -E2BIG; + + sp = newsp; + } + return 0; +} +EXPORT_SYMBOL_GPL(save_stack_trace_tsk_reliable); +#endif /* CONFIG_HAVE_RELIABLE_STACKTRACE */