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)
Uli, I am not sure this bug is an SELinux bug?
Uli, ping? (IOW, can you please take a look at this ?).
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.
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.
> 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.
(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.
checkreqprot affects the handling of binaries with read-implies-exec.
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.
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