PROT_READ and PROT_WRITE Behavior Using mprotect

I am trying to use mprotect for the first reading and then writing.

Here is 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; } 

On Linux, the results are shown here:

Here is the result for PROT_WRITE :

 $ ./main a = 42 a = 24 

and for PROT_READ

 $ ./main a = 42 Segmentation fault 

On Mac OS X 10.7:

Here is the result for PROT_WRITE :

 $ ./main a = 42 a = 24 

and for PROT_READ

 $ ./main [1] 2878 bus error ./main 

Until now, I understand that the behavior of OSX / Linux may be different, but I do not understand why PROT_WRITE does not crash the program when reading a value using printf .

Can someone explain this part?

+5
c
source share
2 answers

There are two things you observe:

  • mprotect not intended to be used with heap pages. Linux and OS X have slightly different heap handling (remember that OS X uses Mach Mach). OS X doesn't like pages with heaps to be tampered with.

    You can get the same behavior for both OSs if you place your page using mmap

     a = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (a == MAP_FAILED) perror("mmap"); 
  • This is a limitation of your MMU (x86 in my case). The x86 MMU does not support writing but not readable pages. Thus setting

     mprotect(a, pagesize, PROT_WRITE) 

    doing nothing. while

     mprotect(a, pagesize, PROT_READ) 

    deleted email records and you will get SIGSEGV as expected.

In addition, although this is not a problem, you must either compile your code with -O0 or set a to volatile int * to avoid compiler optimizations.

+7
source share

Most operating systems and / or cpu processors automatically make something readable when it is written, so PROT_WRITE more often means PROT_READ . It is simply impossible to do something writable without making it readable. Reasons can be suggested, or you shouldn’t attach extra readability bits to MMUs and caches, or, as it was on some earlier architectures, you really need to read the MMUs in the cache before you can write, so doing something unreadable automatically does its unacceptable.

In addition, it is likely that printf trying to allocate from memory corrupted with mprotect . You want to extract the full page from libc when changing its protection, otherwise you will change the protection of the page that you do not own completely, and libc does not expect that it will be protected. In your MacOS test with PROT_READ this is what happens. printf allocates some internal structures, tries to access them and crashes when reading only.

+1
source share

All Articles