Skip to content

Instantly share code, notes, and snippets.

@markmont
Created August 2, 2017 15:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markmont/dcd20d632fa753438f6fc1b3bb3711ec to your computer and use it in GitHub Desktop.
Save markmont/dcd20d632fa753438f6fc1b3bb3711ec to your computer and use it in GitHub Desktop.
W^X using mmap() and mprotect()
#
# 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]$
/* 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