Created
August 2, 2017 15:02
-
-
Save markmont/dcd20d632fa753438f6fc1b3bb3711ec to your computer and use it in GitHub Desktop.
W^X using mmap() and mprotect()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Run under Fedora 26 with SELinux enabled | |
# | |
[markmont@f26docker examples]$ sudo setsebool selinuxuser_execstack=off deny_execmem=on | |
[sudo] password for markmont: | |
[markmont@f26docker examples]$ gcc -o m1 m1.c | |
[markmont@f26docker examples]$ ./m1 | |
mprotect failed to mark exec-only: Permission denied | |
markmont@f26docker examples]$ sudo grep denied /var/log/audit/audit.log | tail -1 | |
type=AVC msg=audit(1501685251.234:287): avc: denied { execmem } for pid=14572 comm="m1" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=process permissive=0 | |
[markmont@f26docker examples]$ | |
# | |
# But it works when execmem is permitted: | |
# | |
[markmont@f26docker examples]$ sudo setsebool deny_execmem=off | |
[markmont@f26docker examples]$ ./m1 | |
(dynamic) code returned 42 | |
[markmont@f26docker examples]$ | |
# | |
# Note that the description for deny_execmem implies | |
# that the code SHOULD work, since the memory is never | |
# both executable and writable at the same time. I | |
# don't know why the AVC access gets denied. | |
# | |
[markmont@f26docker examples]$ sudo semanage boolean -l | grep deny_execmem | |
deny_execmem (off , off) Deny user domains applications to map a memory region as both executable and writable, this is dangerous and the executable should be reported in bugzilla | |
[markmont@f26docker examples]$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Slightly modified version of "The Final Solution" from | |
* https://stackoverflow.com/questions/28015876/what-do-i-have-to-do-to-execute-code-in-data-areas-segment-protection | |
*/ | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <sys/mman.h> | |
static uint8_t code[] = { | |
0xB8,0x2A,0x00,0x00,0x00, /* mov eax,0x2a */ | |
0xC3, /* ret */ | |
}; | |
int main(void) | |
{ | |
const size_t len = sizeof(code); | |
/* mmap a region for our code */ | |
void *p = mmap(NULL, len, PROT_READ|PROT_WRITE, /* No PROT_EXEC */ | |
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | |
if (p==MAP_FAILED) { | |
perror("mmap() failed"); | |
return 2; | |
} | |
/* Copy it in (still not executable) */ | |
memcpy(p, code, len); | |
/* Now make it execute-only */ | |
if (mprotect(p, len, PROT_EXEC) < 0) { | |
perror("mprotect failed to mark exec-only"); | |
return 2; | |
} | |
/* Go! */ | |
int (*func)(void) = p; | |
printf("(dynamic) code returned %d\n", func()); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment