Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
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
#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 */
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
You can’t perform that action at this time.