Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue, 27 Sep 2016 10:43:03 -0400
From: Rich Felker <dalias@...c.org>
To: "LeMay, Michael" <michael.lemay@...el.com>
Cc: "musl@...ts.openwall.com" <musl@...ts.openwall.com>
Subject: Re: [RFC] Support for segmentation-hardened SafeStack

On Mon, Sep 26, 2016 at 11:05:06PM -0700, LeMay, Michael wrote:
> 
> 
> On 9/26/2016 11:08, Rich Felker wrote:
> >On Mon, Sep 26, 2016 at 10:28:40AM -0700, LeMay, Michael wrote:
> ....
> >>A salient requirement is that all code that runs while restricted
> >>segment limits are in effect for DS and ES must use appropriate
> >>segment override prefixes.  This is to direct safe stack accesses to
> >>SS and thus avoid violating the segment limits on DS and ES.  It is
> >>still possible to call code that does not satisfy that requirement
> >>(I will refer to such functions as "standard functions", in contrast
> >>to "segmentation-aware functions") in the same program, but the
> >>segment registers would need to be reverted to contain flat segment
> >>descriptors before calling such code.  Otherwise, a segment limit
> >>violation would occur if a standard function attempted to access
> >>data on the stack using DS or ES.  Of course, reverting to flat
> >>segment descriptors would leave the safe stacks unprotected.
> >In short, non-safestack code called from safestack code would try to
> >store data on the safe stack, which doesn't/can't work.
> >
> >This could probably be avoided by a different approach that avoids
> >call/ret and instead uses manual pushes/pops to the safe stack and
> >jumps in place of call/ret. Then %ss could point to the non-safe stack
> >so that calling non-safestack code would work fine (but would be
> >unprotected as usual).
> >
> >I suspect this is sufficiently costly to implement (either in
> >performance or implementation complexity or both) that you're not
> >interested in doing it that way, but I mention it for completeness.
> 
> That's an interesting idea that could offer some benefits as you
> described, but it would indeed also have drawbacks.  One example
> that comes to mind is that to protect the safe stacks, only
> instructions that require access to the safe stacks should be able
> to use the segment that grants such access.  Thus, many instructions
> that access data sections and the heap would need to have segment
> override prefixes to direct their memory accesses to SS.  Using EBP
> as the base address for some of those accesses could reduce the need
> for segment override prefixes, but I don't know to what extent that

If you actually load %ss with the safestack segment, you would not be
able to call non-safestack code since it might use addressing forms
that immplicitly use %ss. Instead, %fs would have to be loaded with
the safestack segment and all jumps for calls and returns would have
to use a %fs prefix to load the address. Of course that makes it all
the more work to implement (and more costly at runtime).

> ....
> >>However, there are instances where such writes are
> >>necessary.  For example, the va_list object used to support variadic
> >>arguments stores a pointer to the safe stack.
> >Are your "safe stack pointers" just implementation-details like
> >va_list state? In that case I think they're valid since they can only
> >be accessed via va_arg. But I'm wondering why the argument list is on
> >the unsafe stack at all. This mandates that you copy incoming
> >(non-variadic) arguments rather than using them in-place, which is
> >very expensive for (moderately-)large aggregate-type arguments.
> 
> Arguments, whether variadic or not, are still passed on the main
> (safe) stack like usual, and they can be used in-place.

Here I think we're just differing on what "used in-place" means. For
me that would include the ability to take their addresses. I assume
you're just talking about using the values.

> >>I implemented other
> >>compiler patches to emit the SS segment override prefix when
> >>accessing variadic arguments, so storing the safe stack pointer into
> >>the va_list object should be allowed.  The intraprocedural analysis
> >>attempts to detect this type of write, but it currently has
> >>limitations on the complexity of pointer computations that it can
> >>handle.  Thus, I added compiler command line options to selectively
> >>override this analysis for certain files and allow safe stack
> >>pointers to be written to memory even when the compiler cannot
> >>verify that they are being written to va_list objects.
> >I don't think they should even be able to _arise_ except as
> >variadic-argument pointers. If they can't arise you don't need to
> >analyze where they're written.
> 
> I refreshed my memory on what allocations the SafeStack pass moves
> to the unsafe stack, and I think you're right.  If a pointer to the
> safe stack would be written to memory (e.g. into a structure passed
> to another function or into a global variable), then the SafeStack
> pass moves the allocation to the unsafe stack.  Sorry to have
> forgotten that when I wrote my previous message.  I found just a
> couple of exceptions to that rule.  Variadic argument handling is
> one and register spills are another.

This is another place where I think we're just using terms
differently. From my perspective (the formal C language) variadic
argument handling does not involve taking or dereferencing addresses
on the stack; those are just va_list/va_arg implementation details. At
the level of the formal language I think there are no exceptions; in
all cases where the address on "the stack" leaks outside the scope of
what the compiler can see/control, "the stack" it's on has to be the
unsafe stack.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.