All of lore.kernel.org
 help / color / mirror / Atom feed
From: Josh Poimboeuf <jpoimboe@redhat.com>
To: Andy Lutomirski <luto@kernel.org>
Cc: "H. J. Lu" <hjl.tools@gmail.com>,
	"H. Peter Anvin" <hpa@zytor.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Jiri Slaby <jslaby@suse.cz>,
	Andrew Morton <akpm@linux-foundation.org>,
	live-patching@vger.kernel.org,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>,
	the arch/x86 maintainers <x86@kernel.org>,
	Jiri Kosina <jikos@kernel.org>,
	Linus Torvalds <torvalds@linux-foundation.org>
Subject: Re: [PATCH 7/7] DWARF: add the config option
Date: Sat, 20 May 2017 11:20:34 -0500	[thread overview]
Message-ID: <20170520162034.fcciinh3nw5mvad5@treble> (raw)
In-Reply-To: <CALCETrWxwhKvm2jYG+d2xupd6uuEDAeBkafPonYNhxF6O=+qVA@mail.gmail.com>

On Fri, May 19, 2017 at 10:23:53PM -0700, Andy Lutomirski wrote:
> On Fri, May 19, 2017 at 2:35 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> > On Fri, May 19, 2017 at 04:29:13PM -0500, Josh Poimboeuf wrote:
> >> > How are you handling control flow?
> >>
> >> Control flow of what?
> >>
> >> > > Here's the struct in its current state:
> >> > >
> >> > >   #define UNDWARF_REG_UNDEFINED           0
> >> > >   #define UNDWARF_REG_CFA                 1
> >> > >   #define UNDWARF_REG_SP                  2
> >> > >   #define UNDWARF_REG_FP                  3
> >> > >   #define UNDWARF_REG_SP_INDIRECT         4
> >> > >   #define UNDWARF_REG_FP_INDIRECT         5
> >> > >   #define UNDWARF_REG_R10                 6
> >> > >   #define UNDWARF_REG_DI                  7
> >> > >   #define UNDWARF_REG_DX                  8
> >> > >
> >> >
> >> > Why only those registers?  Also, if you have the option I would really
> >> > suggest using the actual x86 register numbers (ax, ex, dx, bx, sp, bp,
> >> > si, di, r8-r15 in that order.)
> >>
> >> Those are the only registers which are ever needed as the base for
> >> finding the previous stack frame.  99% of the time it's sp or bp, the
> >> other registers are needed for aligned stacks and entry code.
> >>
> >> Using the actual register numbers isn't an option because I don't need
> >> them all and they need to fit in a small number of bits.
> >>
> >> This construct might be useful for other arches, which is why I called
> >> it "FP" instead of "BP".  But then I ruined that with the last 3 :-)
> >
> > BTW, here's the link to the unwinder code if you're interested:
> >
> >   https://github.com/jpoimboe/linux/blob/undwarf/arch/x86/kernel/unwind_undwarf.c
> 
> At the risk of potentially overcomplicating matters, here's a
> suggestion.  As far as I know, all (or most all?) unwinders
> effectively do the following in a loop:
> 
> 1. Look up the IP to figure out how to unwind from that IP.
> 2. Use the results of that lookup to compute the previous frame state.
> 
> The results of step 1 could perhaps be expressed like this:
> 
> struct reg_formula {
>   unsigned int source_reg :4;
>   long offset;
>   bool dereference;  /* true: *(reg + offset); false: (reg + offset) */
>   /* For DWARF, I think this can be considerably more complicated, but
> I doubt it's useful. */
> };
> 
> struct unwind_step {
>   u16 available_regs;  /* mask of the caller frame regs that we are
> able to recover */
>   struct reg_formula[16];
> };

Ok, so I assume you mean we would need to have an in-kernel DWARF reader
which reads .eh_frame and converts it to the above, which is called for
every step of the unwind phase.

> The CFA computation is just reg_formula[UNWIND_REG_SP] (or that plus
> or minus sizeof(unsigned long) or whatever -- I can never remember
> exactly what CFA refers to.)  For a frame pointer-based unwinder, the
> entire unwind_step is a foregone conclusion independent of IP: SP = BP
> + 8 (or whatever), BP = *(BP + whatever), all other regs unknown.
> 
> Could it make sense to actually structure the code this way?  I can
> see a few advantages.  It would make the actual meat of the unwind
> loop totally independent of the unwinding algorithm in use,

Yes, this part of it is an interesting idea, separating the debuginfo
reading step from the unwinding step.  And for people who don't want to
carry around megs of DWARF data, get_dwarf_step() could just be a fake
lookup which always returns the frame pointer version.  

> it would
> make the meat be dead simple (and thus easy to verify for
> non-crashiness), and I think it just might open the door for a real
> in-kernel DWARF unwinder that Linus would be okay with.  Specifically,
> write a function like:
> 
> bool get_dwarf_step(struct unwind_step *step, unsigned long ip);

If we keep the frame pointer encoding thing for non-DWARF kernels then
we may also need to pass in bp as well.

Or maybe we could force frame pointer users to at least have DWARF data
for the entry code.  Then even frame pointer kernels could detect entry
regs and we could get rid of that nasty frame pointer encoding thing.

> Put this function in its own file and make it buildable as kernel code
> or as user code.  Write a test case that runs it on every single
> address on the kernel image (in user mode!) with address-sanitizer
> enabled (or in Valgrind or both) and make sure that (a) it doesn't
> blow up and (b) that the results are credible (e.g. by comparing to
> objtool output).  Heck, you could even fuzz-test it where the fuzzer
> is allowed to corrupt the actual DWARF data.  You could do the same
> thing with whatever crazy super-compacted undwarf scheme someone comes
> up with down the road, too.

I think your proposal can be separated into two ideas, which can each be
considered on their own merit:

1) Put .eh_frame in the kernel, along with an in-kernel DWARF unwinder.
   Manage the complexity of the unwinder by validating the output of the
   complex part of the algorithm in user space.

   That's a lot of hoops to jump through.  The only real advantage I can
   see is that it would allow us to use the toolchain's DWARF data.  But
   that data is going to have issues anyway because of inline asm,
   special sections (e.g., exception tables), generated code (e.g.,
   bpf), hand-coded asm with missing/incorrect annotations, etc.

   Now, we could use objtool to find such issues and warn about them.
   Then those issues could be corrected, either by hand or
   programmatically.

   But then, if we're going that far, why not just have objtool reformat
   the data into something much simpler?  It already has the knowledge
   to do so.  Then we don't have to jump through all those hoops to
   justify jumping through more hoops in the kernel (i.e., having a
   complex DWARF state machine).  With a simple debuginfo format, the
   kernel unwinder is simple enough that we don't need to validate its
   functionality in a simulator.

2) Make a unified unwinder which uses get_dwarf_step() to abstract out
   the differences between frame pointers and DWARF (or undwarf or
   whatever else).  This could an interesting.  Though I'm not sure how
   it would integrate with our "guess" unwinder for kernels which don't
   have frame pointers or DWARF/undwarf.  I guess we could still keep
   that one separate.

> I personally like the idea of using real DWARF annotations in the
> entry code because it makes gdb work better (not kgdb -- real gdb
> attached to KVM).
>
> I bet that we could get entry asm annotations into
> good shape if we really wanted to.  OTOH, getting DWARF to work well
> for inline asm is really nasty IIRC.
> 
> (H.J., could we get a binutils feature that allows is to do:
> 
> pushq %whatever
> .cfi_adjust_sp -8
> ...
> popq %whatever
> .cfi_adjust_sp 8
> 
> that will emit the right DWARF instructions regardless of whether
> there's a frame pointer or not?  .cfi_adjust_cfa_offset is not
> particularly helpful here because it's totally wrong if the CFA is
> currently being computed based on BP.)

I agree that entry_64.o should have DWARF data, regardless of what the
in-kernel representation of the data looks like.  And the same for all
the other asm .o files.

But how we achieve that is debatable.  In the past, having all the
manual .cfi annotations everywhere for every push/pop was an
unmaintainable disaster.

If we could have binutils do automatic adjustments for pushes and pops
and sp adds/subtracts without the .cfi annotations, that would be great.

Otherwise, objtool can do it.  And it can write both undwarf and DWARF,
if needed.

> Also, you read the stack like this:
> 
> *val = *(unsigned long *)addr;
> 
> how about probe_kernel_read() instead?

It depends on how paranoid you want to be.  The undwarf code has the
level of paranoia the frame pointer code has always had.

In other words, it ensures each dereference is within the bounds of the
current stack.  It relies on task->stack and the percpu exception/irq
stack pointers, as well as the previous stack pointers at the edge of
each stack.

I don't think we've ever had a problem with that level of paranoia, so I
think staying with the status quo might be fine.

If we did use probe_kernel_read() we'd have to use some other form of it
because it does some kasan and hardened usercopy checks which wouldn't
always be appropriate.

-- 
Josh

  reply	other threads:[~2017-05-20 16:20 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-05 12:21 [PATCH 1/7] DWARF: add option to preserve unwind info Jiri Slaby
2017-05-05 12:21 ` [PATCH 2/7] DWARF: EH-frame based stack unwinding Jiri Slaby
2017-05-05 12:21 ` [PATCH 3/7] vmlinux.lds: preserve eh_frame for DWARF unwinder Jiri Slaby
2017-05-05 12:21 ` [PATCH 4/7] DWARF: initialize structures for kernel and modules Jiri Slaby
2017-05-05 12:21 ` [PATCH 5/7] unwinder: show_stack, check also ret_addr_p's contents Jiri Slaby
2017-05-05 12:21 ` [PATCH 6/7] unwinder: plug in the DWARF unwinder Jiri Slaby
2017-05-05 12:22 ` [PATCH 7/7] DWARF: add the config option Jiri Slaby
2017-05-05 19:57   ` Linus Torvalds
2017-05-06  7:19     ` Ingo Molnar
2017-05-10  7:46       ` Jiri Slaby
2017-05-06 14:24     ` Jiri Kosina
2017-05-07 16:55     ` Josh Poimboeuf
2017-05-07 17:59       ` Ingo Molnar
2017-05-07 18:08         ` hpa
2017-05-07 21:48           ` Josh Poimboeuf
2017-05-08  7:50             ` Vojtech Pavlik
2017-05-08 13:14               ` Josh Poimboeuf
2017-05-08  5:35       ` Andy Lutomirski
2017-05-08  6:15         ` Ingo Molnar
2017-05-08 14:40         ` Josh Poimboeuf
2017-05-08 18:57           ` hpa
2017-05-09  0:21       ` Andy Lutomirski
2017-05-09  1:38         ` Josh Poimboeuf
2017-05-09  2:31           ` Andy Lutomirski
2017-05-09  3:38             ` Josh Poimboeuf
2017-05-09 10:00               ` hpa
2017-05-09 14:58                 ` Josh Poimboeuf
2017-05-09 16:46                   ` H.J. Lu
2017-05-10  8:15                 ` Jiri Slaby
2017-05-10 13:09                   ` Josh Poimboeuf
2017-05-10 16:23                     ` H.J. Lu
2017-05-09 18:47       ` Jiri Kosina
2017-05-09 19:22         ` Josh Poimboeuf
2017-05-10  8:32           ` Jiri Slaby
2017-05-10 13:13             ` Josh Poimboeuf
2017-05-23  7:07             ` Peter Zijlstra
2017-05-23  7:27               ` Ingo Molnar
2017-05-19 20:53       ` Josh Poimboeuf
2017-05-19 20:57         ` H. Peter Anvin
2017-05-19 20:59         ` H. Peter Anvin
2017-05-19 21:29           ` Josh Poimboeuf
2017-05-19 21:35             ` Josh Poimboeuf
2017-05-20  5:23               ` Andy Lutomirski
2017-05-20 16:20                 ` Josh Poimboeuf [this message]
2017-05-20 17:19                   ` Josh Poimboeuf
2017-05-20 20:01                   ` H.J. Lu
2017-05-20 21:58                     ` Andy Lutomirski
2017-05-20 22:20                       ` H.J. Lu
2017-05-22 11:34                         ` Jiri Kosina
2017-05-22 14:39                           ` H.J. Lu
2017-05-22 21:07                     ` H. Peter Anvin
2017-05-22 21:37                       ` H. Peter Anvin
2017-05-22 22:11                         ` Josh Poimboeuf
2017-05-20 20:16                 ` Linus Torvalds
2017-05-20 21:56                   ` Andy Lutomirski
2017-05-20 23:00                     ` Linus Torvalds
2017-05-20 23:29                       ` Linus Torvalds
2017-05-26  6:54               ` Jiri Slaby
2017-05-26 11:29                 ` Jiri Slaby
2017-05-26 12:14                   ` Josh Poimboeuf
2017-05-22 11:12             ` Ingo Molnar
2017-05-22 21:16               ` H. Peter Anvin
2017-05-22 23:23                 ` Jiri Kosina
2017-05-23  5:49                 ` Ingo Molnar
2017-05-26 19:16                   ` hpa
2017-05-28  9:12                     ` Ingo Molnar
2017-05-10  7:39     ` Jiri Slaby
2017-05-10 12:42       ` Josh Poimboeuf
2017-05-10 12:47         ` Jiri Slaby
2017-05-10 18:11       ` Linus Torvalds

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=20170520162034.fcciinh3nw5mvad5@treble \
    --to=jpoimboe@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=hjl.tools@gmail.com \
    --cc=hpa@zytor.com \
    --cc=jikos@kernel.org \
    --cc=jslaby@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mingo@redhat.com \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.