Bug 185214

Summary: allegro programs using streched blits crash because selinux denies mprotect (PROT_EXEC)
Product: [Fedora] Fedora Reporter: Hans de Goede <hdegoede>
Component: selinux-policy-targetedAssignee: Daniel Walsh <dwalsh>
Status: CLOSED NOTABUG QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: rawhideCC: drepper, jnovy
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2006-03-13 22:52:30 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Hans de Goede 2006-03-11 22:42:41 UTC
Description of problem:

I've been debugging crashes of the allegro library using programs on i386 arch
with NX. The problem is that allegro generates code on the fly to create optimal
stretched blitters fo a requested stretch factor. This code gets generated in
memory returned from realloc (realloc is used because the size of the code is
not known in advance so the buffer gets grown if needed).

At first my mprotect didn't help at all because I didn't page align the retval
from realloc. Now I have this code and the mprotect seems to work ok:
      char *p = (char *)((unsigned long)_scratch_mem & ~(PAGE_SIZE-1ul));
      if (mprotect(p, _scratch_mem_size + ((char *)_scratch_mem - p),
            PROT_EXEC|PROT_READ|PROT_WRITE))
         perror("allegro-error: mprotect failed during stretched blit!");

selinux however causes trouble. The strange thing is that for 1 run of my
testing prog it first says 3 times: granted {execmem} and then the 4th time it
says denied {execheap}

To reproduce:

Install the yet to be build and pushed allegro-4.2.0-10 from FE which will have
the correct mprotect code and worminator on a i386 with NX or the i386 versions
on x86_64. Run worminator, click exit -> boom.

Comment 1 Hans de Goede 2006-03-12 13:12:23 UTC
Update: the relevant allegro release has finaly been build (buildsys trouble) so
it should be in tomorrows rawhide push.


Comment 2 Daniel Walsh 2006-03-13 14:54:18 UTC
Uli any comments?

Comment 3 Hans de Goede 2006-03-13 15:35:07 UTC
allegro-4.2.0-10 has just been pushed to the FE repo so you should be able to
test / reproduce this now.


Comment 4 Ulrich Drepper 2006-03-13 16:09:33 UTC
First of all, it has *ALWAYS* been wrong to assume memory returned from the
malloc functions is executable.  This never ever has been guaranteed and must be
changed.  The argument " because the size of the code is not known in advance"
is bogus.  Just use mremap() or mmap() and copy the data.  Note that realloc()
doesn't guarantee the extension happens in-place so either the generated code is
position-independent or you have to regenerate it anyway.

But even with mmap() you cannot use the simple-minded approach (it would create
execmem errors, instead of execheap).  The way around is also described in

http://people.redhat.com/drepper/selinux-mem.html

You create a temporary file (actually an anonymous file is sufficient, just
unlink the file right away).  Use ftruncate to size the file to the current
requirements and mmap it _twice_ with MAP_SHARED: one time with read+write
permissions and the second time with read+exec permissions.  Then change the
code to write into the first mapping and execute in the second mapping.

This is a bit more complicated but really not much.

Comment 5 Ulrich Drepper 2006-03-13 17:42:02 UTC
I added some example code to the document mentionedin comment #4.  It's really
pretty simple to write this code safely.

Comment 6 Hans de Goede 2006-03-13 22:49:01 UTC
Hmm, this new behaviour will probably break other (broken) programs too. Anyways
I won't argue with you. I've fixed allegro with the two mmap's approach. Thanks!

Jindrich, I'm adding you to the CC because this bug explains the changes I'm
about to commit to FE-devel CVS for allegro.