[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Tinycc-devel] Use an anonymous file to back mmap
From: |
Michael Matz |
Subject: |
Re: [Tinycc-devel] Use an anonymous file to back mmap |
Date: |
Sat, 11 Jan 2014 19:41:51 +0100 (CET) |
User-agent: |
Alpine 2.00 (LNX 1167 2008-08-23) |
Hi,
On Thu, 9 Jan 2014, Keren Tan wrote:
I just submitted a tentative patch to the mob branch about mmap. When
selinux is enabled, tccrun.c uses mmap to hold the dynamically generated
code/data. It is backed by a randomly named file under /tmp directory.
My patch is to use an anonymous file in mmap instead, so that the
generated code/data only resides in memory, and tcc does not depend on a
writable /tmp anymore.
It's customary to actually test changes before committing. In your case:
% ./configure --with-selinux
% make && make test
...
------------ test3 ------------
../tcc -B.. -I.. -I.. -I../include -DCONFIG_LDDIR="\"lib64\""
-DTCC_TARGET_X86_64 -DONE_SOURCE -run ../tcc.c -B.. -I.. -I.. -I../include
-DCONFIG_LDDIR="\"lib64\"" -DTCC_TARGET_X86_64 -DONE_SOURCE -run ../tcc.c
-B.. -I.. -I.. -I../include -DCONFIG_LDDIR="\"lib64\"" -DTCC_TARGET_X86_64
-DONE_SOURCE -run ../tcc.c -B.. -I.. -I.. -I../include -run tcctest.c >
test.out3
/bin/sh: line 1: 15954 Segmentation fault ../tcc -B.. -I.. -I..
-I../include -DCONFIG_LDDIR="\"lib64\"" -DTCC_TARGET_X86_64 -DONE_SOURCE
-run ../tcc.c -B.. -I.. -I.. -I../include -DCONFIG_LDDIR="\"lib64\""
-DTCC_TARGET_X86_64 -DONE_SOURCE -run ../tcc.c -B.. -I.. -I.. -I../include
-DCONFIG_LDDIR="\"lib64\"" -DTCC_TARGET_X86_64 -DONE_SOURCE -run ../tcc.c
-B.. -I.. -I.. -I../include -run tcctest.c > test.out3
make[1]: *** [test3] Error 139
This is no wonder because the former mmap mechanism had some special
requirements mandated by SElinux that you ignored. Your patch basically
did this:
s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
- MAP_SHARED, fd, 0);
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
...
s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
- MAP_SHARED, fd, 0);
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
So it replaced two mmaps of the same region (the file), one mapping being
writable (pointer to it in ->write_mem), and another mapping being
executable (pointer in ->runtime_mem) by two completely unrelated anon
mappings, one writable, one executable.
The requirements of the whole things are such, that changes to the
writable mapping via ->write_mem need to be reflected in the mapping
reachable via ->runtime_mem. I.e. both mappings really need to be two
views on _exactly_ the same data.
Depending on the configuration of an SElinux system the following things
might be disallowed:
* creating mapping which is WRITE|EXEC
* changing flags of an existing writable mapping to include EXEC when it
didn't before (no matter if WRITE is now removed or not)
The first means you won't get away with just a single mmap of some
ANON|PRIVATE that is writable and executable. The second means you also
don't get away with first mapping something writable, let tcc generate its
code therein and then remap it executable (either via mprotect or mremap).
That is you indeed need two separate mappings. And because both mappings
need to be actually from the same underlying data they need to be related
somehow. And the only way to relate two separate mappings is via a file
descriptor and a MAP_SHARED mapping.
IOW: the former way of mapping a writable and executable piece of memory
via a shared mapping backed by a file is the only way that works in
SElinux. And yes, that means it needs to have a place for that file, and
it needs to be on a file system that isn't mounted noexec (i.e. /tmp might
actually not be the right place).
In still other words: please revert, sorry. :-/
tcc is fantastic! I am new to this community. Your comments are very
welcome!
Yeah, sorry to spoil the fun ;) Thanks for contributing, I hope the
above at least explains things. Testing is the key :)
Ciao,
Michael.