Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20170802144612.GI1627@brightrain.aerifal.cx>
Date: Wed, 2 Aug 2017 10:46:12 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: possible bug in setjmp implementation for ppc64

On Wed, Aug 02, 2017 at 08:38:25AM -0500, Bobby Bingham wrote:
> On Wed, Aug 02, 2017 at 12:58:16AM -0400, Rich Felker wrote:
> > > sigsetjmp calls setjmp, but I believe this will always use the intra-dso
> > > entry point.  Same for the call siglongjmp makes to longjmp.  So calls
> > > via sigsetjmp/siglongjmp will always be detected as local calls, even
> > > when the originally caller of jig*jmp is in a different dso.
> > >
> > > My plan right now is create a __setjmp_toc function which is identical
> > > to the normal setjmp except that the TOC pointer to save is passed in as
> > > another parameter.  setjmp will detect which entry point is used, pull
> > > the TOC pointer from the right place, and call __setjmp_toc.  sigsetjmp
> > > will be updated similarly to detect which entry point is used and to
> > > call __setjmp_toc directly instead of going through setjmp.
> >
> > I've been thinking about it and at first thought it sounded overly
> > fragile and hard to understand, but now I think it makes sense and
> > should work. It would just involve copying r2 to a call-clobbered
> > argument register before loading the new value, right?
> 
> I'm not sure what "new value" you're referring to here.
> 
> The idea is basically:
> 
> 	setjmp: # non-local entry point
> 		r5 = r1[24]
> 		goto __setjmp_toc
> 
> 		.localentry # local entry point
> 		r5 = r2
> 
> 	__setjmp_toc:
> 		# all the existing code from setjmp, but save r5 instead of r2

For sigsetjmp, I think in this case you also need to duplicate the
assembler-generated code that would load a new r2; otherwise you can't
subsequently call __sigsetjmp_tail. For setjmp itself the above should
suffice since setjmp does not need a TOC itself.

Otherwise the pseudo-code above looks like what I expected after
thinking about it for a bit.

> > I was considering whether you could just avoid loading the TOC pointer
> > at all (leaving the correct value in r2 for setjmp to save), and this
> > might work, but I think it would make calling __sigsetjmp_tail
> > difficult and error-prone.
> >
> > > siglongjmp is current written in C by just calling longjmp.  I'm tempted
> > > to just add a "siglongjmp:" label in the asm for longjmp and add an
> > > empty powerpc64/siglongjmp.c file to suppress the default
> > > implementation.  I want to ask if there's any reason it wouldn't be
> > > valid for these two functions to have the same address.
> >
> > I don't see any reason to make this change (it won't make any
> > functional difference -- call frames and such don't matter at this
> > point), and at least the siglongjmp symbol would have to be weak to
> > respect namespace if you did it that way.
> 
> I'm not sure why a change like this wouldn't be required.
> 
> The requirements on longjmp here are:
> * when called through the local entry point, restore the TOC pointer
>   into r2
> * when called via the PLT stub, restore the TOC pointer to the stack
> 
> And siglongjmp needs to have the same behavior.  If the main program
> makes a cross-dso call to siglongjmp, it needs to restore the TOC
> pointer to the stack.  But siglongjmp works by making a local call to
> longjmp, meaning without this change, it will only ever restore the TOC
> pointer to r2.

Whether the call to longjmp/siglongjmp was local or not is irrelevant.
It's only whether the original call to setjmp/sigsetjmp was local or
not that's relevant. And in either case I'm pretty sure it suffices to
restore the saved value to both *(r1+24) and r2. Per the ABI, *(r1+24)
can't be used for any purpose except saving the TOC, so upon return
from setjmp, the caller's only options are to treat the value at
*(r1+24) as indeterminate or assume it contains the TOC pointer.
Likewise for r2, if the call was non-local, r2 is call-clobbered so it
doesn't matter what it contains after return, and if the call was
local, r2 is expected to contain the caller's TOC pointer.

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.