From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/10521 Path: news.gmane.org!.POSTED!not-for-mail From: Rich Felker Newsgroups: gmane.linux.lib.musl.general Subject: Re: [RFC] Support for segmentation-hardened SafeStack Date: Tue, 27 Sep 2016 10:43:03 -0400 Message-ID: <20160927144303.GG19318@brightrain.aerifal.cx> References: <390CE752059EB848A71F4F676EBAB76D3AC0B184@ORSMSX114.amr.corp.intel.com> <20160922234219.GA19318@brightrain.aerifal.cx> <20160926180822.GD19318@brightrain.aerifal.cx> <64befac3-af89-611a-70d1-9838c91097b3@intel.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: blaine.gmane.org 1474987411 29897 195.159.176.226 (27 Sep 2016 14:43:31 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 27 Sep 2016 14:43:31 +0000 (UTC) User-Agent: Mutt/1.5.21 (2010-09-15) Cc: "musl@lists.openwall.com" To: "LeMay, Michael" Original-X-From: musl-return-10534-gllmg-musl=m.gmane.org@lists.openwall.com Tue Sep 27 16:43:23 2016 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by blaine.gmane.org with smtp (Exim 4.84_2) (envelope-from ) id 1botbM-0006VK-6G for gllmg-musl@m.gmane.org; Tue, 27 Sep 2016 16:43:20 +0200 Original-Received: (qmail 19881 invoked by uid 550); 27 Sep 2016 14:43:19 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Original-Received: (qmail 19863 invoked from network); 27 Sep 2016 14:43:18 -0000 Content-Disposition: inline In-Reply-To: <64befac3-af89-611a-70d1-9838c91097b3@intel.com> Original-Sender: Rich Felker Xref: news.gmane.org gmane.linux.lib.musl.general:10521 Archived-At: 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