mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Josh Poimboeuf <jpoimboe@redhat.com>
To: Andy Lutomirski <luto@amacapital.net>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@kernel.org>, "H . Peter Anvin" <hpa@zytor.com>,
	X86 ML <x86@kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	Brian Gerst <brgerst@gmail.com>,
	Kees Cook <keescook@chromium.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Frederic Weisbecker <fweisbec@gmail.com>,
	Byungchul Park <byungchul.park@lge.com>,
	Nilay Vaish <nilayvaish@gmail.com>
Subject: Re: [PATCH v3 48/51] x86/unwind: warn if stack grows up
Date: Mon, 15 Aug 2016 11:25:24 -0500	[thread overview]
Message-ID: <20160815162524.ln4gz5nwt76no5pu@treble> (raw)
In-Reply-To: <CALCETrXZUS839iD-gOt6FoKLC5gRsACahtzh6aTzSO3ogaAF7g@mail.gmail.com>

On Sun, Aug 14, 2016 at 12:56:40AM -0700, Andy Lutomirski wrote:
> On Fri, Aug 12, 2016 at 7:29 AM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> > Add a sanity check to ensure the stack only grows down, and print a
> > warning if the check fails.
> >
> > Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
> > ---
> >  arch/x86/kernel/unwind_frame.c | 26 ++++++++++++++++++++++++--
> >  1 file changed, 24 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
> > index 5496462..f21b7ef 100644
> > --- a/arch/x86/kernel/unwind_frame.c
> > +++ b/arch/x86/kernel/unwind_frame.c
> > @@ -32,6 +32,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
> >  }
> >  EXPORT_SYMBOL_GPL(unwind_get_return_address);
> >
> > +static size_t regs_size(struct pt_regs *regs)
> > +{
> > +       /* x86_32 regs from kernel mode are two words shorter */
> > +       if (IS_ENABLED(CONFIG_X86_32) && !user_mode(regs))
> > +               return sizeof(*regs) - (2*sizeof(long));
> > +
> > +       return sizeof(*regs);
> > +}
> > +
> >  static bool is_last_task_frame(struct unwind_state *state)
> >  {
> >         unsigned long bp = (unsigned long)state->bp;
> > @@ -85,6 +94,7 @@ bool unwind_next_frame(struct unwind_state *state)
> >         struct pt_regs *regs;
> >         unsigned long *next_bp, *next_sp;
> >         size_t next_len;
> > +       enum stack_type prev_type = state->stack_info.type;
> >
> >         if (unwind_done(state))
> >                 return false;
> > @@ -140,6 +150,18 @@ bool unwind_next_frame(struct unwind_state *state)
> >         if (!update_stack_state(state, next_sp, next_len))
> >                 goto bad_address;
> >
> > +       /* make sure it only unwinds up and doesn't overlap the last frame */
> > +       if (state->stack_info.type == prev_type) {
> > +               if (state->regs &&
> > +                   (void *)next_sp < (void *)state->regs +
> > +                                     regs_size(state->regs))
> > +                       goto bad_address;
> > +
> > +               if (state->bp &&
> > +                   (void *)next_sp < (void *)state->bp + FRAME_HEADER_SIZE)
> > +                       goto bad_address;
> > +       }
> > +
> 
> Maybe this is obvious in context, but does something prevent this
> error from firing if the stack switched?  That is:
> 
> pushq $rbp
> movq $rsp, $rbp
> ...
> movq [irq stack], $rsp
> <- rsp and rbp have no particular relationship right now.

Short answer:

No, because the above warning only happens between two "frame" pointers
(where frame pointer might be a regs pointer) when the two frames are on
the same stack.  This warning has nothing to do with the stack pointer,
despite the "next_sp" name.  I should probably rename "next_sp" to
"next_frame" or something.

Long answer:

The unwinder is frame-pointer based, so in most cases it completely
ignores the value of the stack pointer.  The only exceptions are:

a) in __unwind_start() where it can use the value of regs->sp to determine how
   many frames to skip; and

b) when reading the next stack pointer to switch to the next stack.

If for example the regs where taken from an interrupt right after the
stack had been switched, then no frame would contain the stack pointer,
and __unwind_start() would skip all the frames, and the unwind would be
reported as empty.

Such edge cases are exceedingly rare, and are acceptable IMO, because
frame pointers and interrupts are inherently not 100% compatible.  And
these edge cases already exist in today's code.

(And I should reiterate that even when the unwinder breaks down like
that, the oops dump code should still keep going and show all the
addresses anyway.)

-- 
Josh

  reply	other threads:[~2016-08-15 16:25 UTC|newest]

Thread overview: 99+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-12 14:28 [PATCH v3 00/51] x86/dumpstack: rewrite x86 stack dump code Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 01/51] x86/dumpstack: remove show_trace() Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 02/51] x86/asm/head: remove unused init_rsp variable extern Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 03/51] x86/asm/head: rename 'stack_start' -> 'initial_stack' Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 04/51] x86/asm/head: use a common function for starting CPUs Josh Poimboeuf
2016-08-12 22:08   ` Nilay Vaish
2016-08-12 14:28 ` [PATCH v3 05/51] x86/dumpstack: make printk_stack_address() more generally useful Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 06/51] x86/dumpstack: add IRQ_USABLE_STACK_SIZE define Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 07/51] x86/dumpstack: remove extra brackets around "<EOE>" Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 08/51] x86/dumpstack: fix irq stack bounds calculation in show_stack_log_lvl() Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 09/51] x86/dumpstack: fix x86_32 kernel_stack_pointer() previous stack access Josh Poimboeuf
2016-08-14  7:26   ` Andy Lutomirski
2016-08-14 12:55     ` Brian Gerst
2016-08-14 13:42       ` Andy Lutomirski
2016-08-15 15:05     ` Josh Poimboeuf
2016-08-15 17:22       ` Josh Poimboeuf
2016-08-15 20:04         ` Andy Lutomirski
2016-08-12 14:28 ` [PATCH v3 10/51] x86/dumpstack: add get_stack_pointer() and get_frame_pointer() Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 11/51] x86/dumpstack: remove unnecessary stack pointer arguments Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 12/51] x86: move _stext marker to before head code Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 13/51] x86/asm/head: remove useless zeroed word Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 14/51] x86/asm/head: put real return address on idle task stack Josh Poimboeuf
2016-08-14  7:29   ` Andy Lutomirski
2016-08-17 20:30   ` Nilay Vaish
2016-08-17 21:10     ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 15/51] x86/asm/head: standardize the end of the stack for idle tasks Josh Poimboeuf
2016-08-14  7:30   ` Andy Lutomirski
2016-08-12 14:28 ` [PATCH v3 16/51] x86/32: put real return address on stack in entry code Josh Poimboeuf
2016-08-14  7:31   ` Andy Lutomirski
2016-08-15 15:09     ` Josh Poimboeuf
2016-08-15 18:04       ` H. Peter Anvin
2016-08-15 18:25         ` Josh Poimboeuf
2016-08-15 19:22           ` H. Peter Anvin
2016-08-15 20:06             ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 17/51] x86/smp: fix initial idle stack location on 32-bit Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 18/51] x86/entry/head/32: use local labels Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 19/51] x86/entry/32: rename 'error_code' to 'common_exception' Josh Poimboeuf
2016-08-14  7:40   ` Andy Lutomirski
2016-08-15 15:30     ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 20/51] perf/x86: check perf_callchain_store() error Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 21/51] oprofile/x86: add regs->ip to oprofile trace Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 22/51] proc: fix return address printk conversion specifer in /proc/<pid>/stack Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 23/51] ftrace: remove CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST from config Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 24/51] ftrace: only allocate the ret_stack 'fp' field when needed Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 25/51] ftrace: add return address pointer to ftrace_ret_stack Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 26/51] ftrace: add ftrace_graph_ret_addr() stack unwinding helpers Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 27/51] x86/dumpstack/ftrace: convert dump_trace() callbacks to use ftrace_graph_ret_addr() Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 28/51] ftrace/x86: implement HAVE_FUNCTION_GRAPH_RET_ADDR_PTR Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 29/51] x86/dumpstack/ftrace: mark function graph handler function as unreliable Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 30/51] x86/dumpstack/ftrace: don't print unreliable addresses in print_context_stack_bp() Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 31/51] x86/dumpstack: allow preemption in show_stack_log_lvl() and dump_trace() Josh Poimboeuf
2016-08-14  7:45   ` Andy Lutomirski
2016-08-15 15:32     ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 32/51] x86/dumpstack: simplify in_exception_stack() Josh Poimboeuf
2016-08-14  7:48   ` Andy Lutomirski
2016-08-15 15:34     ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 33/51] x86/dumpstack: add get_stack_info() interface Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 34/51] x86/dumpstack: add recursion checking for all stacks Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 35/51] x86/unwind: add new unwind interface and implementations Josh Poimboeuf
2016-08-15 21:43   ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 36/51] perf/x86: convert perf_callchain_kernel() to use the new unwinder Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 37/51] x86/stacktrace: convert save_stack_trace_*() " Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 38/51] oprofile/x86: convert x86_backtrace() " Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 39/51] x86/dumpstack: convert show_trace_log_lvl() " Josh Poimboeuf
2016-08-14  8:13   ` Andy Lutomirski
2016-08-15 16:44     ` Josh Poimboeuf
2016-08-12 14:28 ` [PATCH v3 40/51] x86/dumpstack: remove dump_trace() and related callbacks Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 41/51] x86/entry/unwind: create stack frames for saved interrupt registers Josh Poimboeuf
2016-08-14  8:10   ` Andy Lutomirski
2016-08-15 16:33     ` Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 42/51] x86/unwind: create stack frames for saved syscall registers Josh Poimboeuf
2016-08-14  8:23   ` Andy Lutomirski
2016-08-15 16:52     ` Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 43/51] x86/dumpstack: print stack identifier on its own line Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 44/51] x86/dumpstack: print any pt_regs found on the stack Josh Poimboeuf
2016-08-14  8:16   ` Andy Lutomirski
2016-08-12 14:29 ` [PATCH v3 45/51] x86: remove 64-byte gap at end of irq stack Josh Poimboeuf
2016-08-14  7:52   ` Andy Lutomirski
2016-08-14 12:50     ` Brian Gerst
2016-08-15 17:00       ` Josh Poimboeuf
2016-08-15 15:42     ` Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 46/51] x86/unwind: warn on kernel stack corruption Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 47/51] x86/unwind: warn on bad stack return address Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 48/51] x86/unwind: warn if stack grows up Josh Poimboeuf
2016-08-14  7:56   ` Andy Lutomirski
2016-08-15 16:25     ` Josh Poimboeuf [this message]
2016-08-12 14:29 ` [PATCH v3 49/51] x86/dumpstack: warn on stack recursion Josh Poimboeuf
2016-08-12 14:29 ` [PATCH v3 50/51] x86/mm: move arch_within_stack_frames() to usercopy.c Josh Poimboeuf
2016-08-12 17:36   ` Kees Cook
2016-08-12 19:12     ` Josh Poimboeuf
2016-08-12 20:06       ` Kees Cook
2016-08-12 20:36         ` Josh Poimboeuf
2016-08-12 20:44           ` Kees Cook
2016-08-12 14:29 ` [PATCH v3 51/51] x86/mm: convert arch_within_stack_frames() to use the new unwinder Josh Poimboeuf
2016-08-12 15:17   ` Josh Poimboeuf
2016-08-12 17:38     ` Kees Cook
2016-08-12 19:15       ` Josh Poimboeuf
2016-08-12 20:41   ` Josh Poimboeuf
2016-08-12 20:47     ` Kees Cook

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160815162524.ln4gz5nwt76no5pu@treble \
    --to=jpoimboe@redhat.com \
    --cc=brgerst@gmail.com \
    --cc=byungchul.park@lge.com \
    --cc=fweisbec@gmail.com \
    --cc=hpa@zytor.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=mingo@kernel.org \
    --cc=nilayvaish@gmail.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®