tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: PAX mprotect and JIT



> Date: Sun, 26 Feb 2017 16:38:04 +0100
> From: Joerg Sonnenberger <joerg%bec.de@localhost>
> 
> On Sun, Feb 26, 2017 at 03:20:17PM +0000, Taylor R Campbell wrote:
> > Can we make this opt-in at mmap time -- that is, require you to have
> > specified MAP_REMAPDUP to mmap on a region in order to use it for
> > mremap on that region?  That way this introduces no new attack surface
> > for mappings that were not intended to be used with it in the first
> > place.
> 
> I don't think duplicating the mapping by itself creates any new attack
> surface.

I'm not so confident after a short time of thinking about it.  That's
why I suggest we avoid changing semantics for any existing users of
mmap -- so we don't have to be confident about that.

>          The better question is what the permissions should be. I'd far
> prefer that mmap has to request support for executable ahead of time.
> That doesn't work too well with the current pax logic though and there
> are some general questions of whether the interface is correct. E.g. if
> I request RWX for mmap, should we really silently drop the X from the
> effective permissions? I think a separate flag to make it RWx is better.
> That should address your concern as well.

It seems prudent to take the protection specified in the original mmap
call as the maximum for any duplicate mappings of the same backing
pages, and then apply the W^X rule individually.

Except for a perhaps slightly quirky interpretation of the parameters,
I don't foresee a problem with preferring PROT_WRITE over PROT_EXEC if
both are specified, as long as MAP_REMAPDUP is also specified -- in
particular, for the first mmap call, there is no sense in mapping the
memory PROT_EXEC before you have initialized it.

The idiom I imagine is something like:

	void *buf = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC,
	    MAP_ANON|MAP_REMAPDUP, -1, 0);
	/* initialize buf with machine instructions */
	void *ip = mremap(buf, len, NULL, len, MAP_REMAPDUP);
	mprotect(ip, len, PROT_EXEC);
	munmap(buf, len);
	/* jump to *ip */
	void *buf = mremap(ip, len, NULL, len, MAP_REMAPDUP);
	mprotect(buf, len, PROT_READ|PROT_WRITE);
	/* update buf with modified instructions */
	munmap(buf, len);

If you fail to use MAP_REMAPDUP with mmap(PROT_WRITE|PROT_EXEC), then
it will still fail as it does today -- i.e., this entails no changes
to the semantics of mmap without the MAP_REMAPDUP flag.

Aside: Do we need any additional memory barriers to synchronize
writing to code with executing the code in memory?  I don't have a
good sense of what the landscape of requirements on different CPU
architectures is.


Home | Main Index | Thread Index | Old Index