Bug 211271 - Application which needs execstack results in denied { execmem } in audit.log
Application which needs execstack results in denied { execmem } in audit.log
Status: CLOSED NOTABUG
Product: Fedora
Classification: Fedora
Component: kernel (Show other bugs)
rawhide
All Linux
medium Severity medium
: ---
: ---
Assigned To: Eric Paris
Brian Brock
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2006-10-18 07:21 EDT by Hans de Goede
Modified: 2007-11-30 17:11 EST (History)
4 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2007-10-01 15:15:55 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Hans de Goede 2006-10-18 07:21:42 EDT
Ok,

This is a long story and probably more then one bug is contained in here, so
I'll start by just telling to story (I'll try to be brief) and then you can
instruct me which bugs to file against what components.

I was working on packaging a program which contains lots of i386 asm code. And
it turns out that this programs contains self modifying asm code. That is it
contains code which does a mov instruction with a label in the same code (a
label which one would normally only use for a jmp) as dest. The programmers got
this to work by putting all of this code in a .data segment.

I've made the following observations from working with this program, some of
which I concider bugs:

1) Since the asm code doesn't contain a GNU-stack section the resulting 
   executable requires an executable stack. However when trying to execute it
   it does start, but hangs shortly into execution. I would expect it to not
   start as I have allow_execstack set to off and I'm running in enforcing mode,
   and if it starts I would expect it to just run, since it is making no 
   mprotect calls of itself (ld.so probably is).

2) When I try to run it I get an denied  { execmem } message in audit.log,
   I would expect to get an denied  { execstack } message (or both) here.
   Strange enough setting the allow_execstack bool to true still fixes
   the running of the app. And so does setting allow_execmem (with 
   allow_execstack off). They behave as if they are one and the same bool
   (in this case), with either of them being allowed being sufficient.

3) When I set enforcing to 0 or make it java_exec_t or allow_execstack then it
   runs, meaning appearantly, that execstack implies also having an executable
   data segment (the selfmodifying code is in the data segment). I think this
   is correct behaviour but I still was surprised.

4) Since I do not want it to have an executable stack I've added the nescesarry
   GNU-stack sections to the asm code, since however part of the asm code is 
   selfmodifying, I do need the data segment to be executable (or the code 
   segment to be writable). So I've added the following to the start of the
   selfmodifying asm files:
   .section .data, "awx", @progbits;
   Making the data section executable, resulting in:
   eu-readelf -l foo
   LOAD           0x000000 0x08048000 0x08048000 0x343f94 0x343f94 R E 0x1000
   LOAD           0x344000 0x0838c000 0x0838c000 0x103ef9 0x258ac0 RWE 0x1000
   So the data section got marked executable as expected and trying to start
   the binary resulted in an denied { execmem } message. Also when trying to
   run the binary now it exits with a message of "killed", which is better
   behaviour then the strange start a bit and then hang behaviour it had with
   execstack set. After setenforce 0 the applications runs properly.

   So I did a chcon -t java_exec_t foo and tried to run it with enforcing on,
   but it didn't. Instead I got an denied { execmem } message, and it exits with
   a message of "killed". It seems that ld.so (or the kernel?) is trying to 
   create an executable mapping for the datasegment here before changing the
   SELinux context / SID to the new one of the program.



So in short I believe we have the following 3 bugs here (but I don't know which
components to blame):
1) Application who required an executable stack start even though 
   allow_execstack = 0, then somewhat later in their exec they hang.
2) Requiring an executable stack results in execmem avc messages not execstack
   ones (but setting allow_execstack bool makes these go away).
3) An application which requires an executable data segment without requiring an
   executable stack will not run even it has a type which is allowed execmem.


This is all on an x86_64 system running an x86_64 version of the distro, with a
fully updated (as of today / FC-6 gold spin (the third one)) kernel, glibc and
selinux-policy(-targeted)
Comment 1 Daniel Walsh 2006-10-18 11:42:57 EDT
Uli, I am not sure this bug is an SELinux bug?
Comment 2 Hans de Goede 2006-11-13 07:31:25 EST
Uli, ping? (IOW, can you please take a look at this ?).
Comment 3 Eric Paris 2006-11-25 17:40:45 EST
2) Requiring an executable stack results in execmem avc messages not execstack
   ones (but setting allow_execstack bool makes these go away).

This is the only thing that I know to comment on to begin with.  First off the
allow_execstack boolean now grants the execmem permission.  As I recall this is
because in multithreaded applications the second (and subsequent) thread stack
actually comes from 'memory' and gets marked as executable.  Thus the check on
new thread stacks is an execmem check rather than execstack.  Is your
application multithreaded and does that answer some of the questions about
'hanging after starting' and why you can execmem checks although you were
expecting execstack?

I'll admit I don't know the answer to a lot of the other questions, but I will
find the people who do.
Comment 4 Hans de Goede 2006-11-26 02:02:49 EST
Yes this is a multithreaded application, and yes that propably explains the hang
(I actually already knew about this, see another selinux bug from mine).

But that still doesn't explain why even though the needs exec stack stuff is
present in the elf header the binary starts in the first place and I never get
an execstack denied message. IOW the main thread/process starts fine which IMHO
it shouldn't.
Comment 5 Ulrich Drepper 2007-02-13 15:42:58 EST
> 1) Application who required an executable stack start even though 
>    allow_execstack = 0, then somewhat later in their exec they hang.

I've never seen this.  Certainly looks like a bug.


> 2) Requiring an executable stack results in execmem avc messages not execstack
>    ones (but setting allow_execstack bool makes these go away).

Eric in comment #3 is right.  execstack implies execmem.  The opposite needs not
to be true.


> 3) An application which requires an executable data segment without requiring an
>    executable stack will not run even it has a type which is allowed execmem.

I haven't see this either.


You should be able to produce a small test case if these are real problems and
not something in this crooked application.
Comment 6 Hans de Goede 2007-02-14 05:14:57 EST
(In reply to comment #5)
> > 1) Application who required an executable stack start even though 
> >    allow_execstack = 0, then somewhat later in their exec they hang.
> 
> I've never seen this.  Certainly looks like a bug.
> 

To reproduce, write helloworld.c and then:
[hans@localhost ~]$ gcc -o hello helloworld.c 
[hans@localhost ~]$ execstack -s hello
[hans@localhost ~]$ ./hello
hello world
[hans@localhost ~]$ getenforce
Enforcing
[hans@localhost ~]$ getsebool -a | grep exec
allow_execheap --> off
allow_execmem --> off
allow_execmod --> off
allow_execstack --> off
allow_java_execstack --> off
allow_unconfined_execmem_dyntrans --> off
httpd_ssi_exec --> off
httpd_suexec_disable_trans --> off

This bug is particularry nasty, because when this happens (application requires
execstack, but execstack is not allowed) running the apps succeeds as
demonstrated above, but when the apps tries to create any threads with pthreads
this thread creation fails because pthread cannot make the stack for the new
thread executable. Surprisingly many applications react to this thread creation
failing by just hanging -> bad.


> > 3) An application which requires an executable data segment without requiring an
> >    executable stack will not run even it has a type which is allowed execmem.
> 
> I haven't see this either.
> 

To reproduce
1) write helloworld.c
2) gcc -s helloworld.c  -o hello.s
3) Edit hello.s and change '.section .rodata' to '.section mysect, "awx"'
4) And then:
[hans@localhost ~]$ gcc -o hello hello.s
[hans@localhost ~]$ chcon -t unconfined_execmem_exec_t hello
[hans@localhost ~]$ ./hello
Killed
[hans@localhost ~]$ sudo tail /var/log/audit/audit.log
<snip>
type=AVC msg=audit(1171447749.536:44): avc:  denied  { execmem } for  pid=6648
comm="hello" scontext=user_u:system_r:unconfined_t:s0
tcontext=user_u:system_r:unconfined_t:s0 tclass=process
type=SYSCALL msg=audit(1171447749.536:44): arch=40000003 syscall=11 success=yes
exit=0 a0=bfb749b4 a1=bfb75a68 a2=bfb75a70 a3=0 items=0 ppid=6647 pid=6648
auid=500 uid=500 gid=500 euid=500 suid=500 fsuid=500 egid=500 sgid=500 fsgid=500
tty=pts0 comm="hello" exe="/home/hans/hello"
subj=user_u:system_r:unconfined_t:s0 key=(null)
<snip>

Notice how when the execmem is denied, the context-type is still: unconfined_t,
so appearantly the exec call tries to map the executable data segment we made
with the mysect .section statement before changing the context.
Comment 7 Stephen Smalley 2007-02-16 14:04:25 EST
checkreqprot affects the handling of binaries with read-implies-exec.

Comment 8 Stephen Smalley 2007-02-16 15:33:22 EST
To clarify, checkreqprot is a selinux setting that can be controlled via
selinuxfs (e.g. echo 0 > /selinux/checkreqprot) or specified as a kernel boot
parameter (e.g. checkreqprot=0).

Also, execstack is only checked on mprotect, not mmap.  That was always a
limitation of that check, unlike execmem.

checkreqprot was introduced because legacy binaries and (later) binaries marked
with PT_GNU_STACK RWE automatically enabled the kernel's read-implies-exec
logic, which led to every attempt to map a file with PROT_READ being treated as
an attempt to also make it PROT_EXEC, thereby triggering pervasive SELinux
permission denials on legacy binaries (entire distros when dealing with legacy
distros) and marked binaries.
Comment 9 Eric Paris 2007-10-01 15:15:55 EDT
Do we still have questions problems here?  I'm going to close as NOTABUG (I did
fix the execstack implies execmem issue in policy a while back)

If something else is cause problems please re-open

Note You need to log in before you can comment on or make changes to this bug.