I've been trying to use mprotect
against reading first, and then writing.
Is here my code
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int pagesize = sysconf(_SC_PAGE_SIZE);
int *a;
if (posix_memalign((void**)&a, pagesize, sizeof(int)) != 0)
perror("memalign");
*a = 42;
if (mprotect(a, pagesize, PROT_WRITE) == -1) /* Resp. PROT_READ */
perror("mprotect");
printf("a = %d\n", *a);
*a = 24;
printf("a = %d\n", *a);
free (a);
return 0;
}
Under Linux here are the results:
Here is the output for PROT_WRITE
:
$ ./main
a = 42
a = 24
and for PROT_READ
$ ./main
a = 42
Segmentation fault
Under Mac OS X 10.7:
Here is the output for PROT_WRITE
:
$ ./main
a = 42
a = 24
and for PROT_READ
$ ./main
[1] 2878 bus error ./main
So far, I understand that OSX / Linux behavior might be different, but I don't understand why PROT_WRITE
does not crash the program when reading the value with printf
.
Can someone explain this part?
There are two things that you are observing:
mprotect
was not designed to be used with heap pages. Linux and OS X have slightly different handling of the heap (remember that OS X uses the Mach VM). OS X does not like it's heap pages to be tampered with.
You can get identical behaviour on both OSes if you allocate your page via mmap
a = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (a == MAP_FAILED)
perror("mmap");
This is a restriction of your MMU (x86 in my case). The MMU in x86 does not support writable, but not readable pages. Thus setting
mprotect(a, pagesize, PROT_WRITE)
does nothing. while
mprotect(a, pagesize, PROT_READ)
removed write priveledges and you get a SIGSEGV as expected.
Also although it doesn't seem to be an issue here, you should either compile your code with -O0
or set a
to volatile int *
to avoid any compiler optimisations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With