Demo: Permissions Are Per Area¶
Read, write and execute, tried against the data area and the code area of a program. Four combinations work; three, commented out, each crash.
Goal¶
Show that every area of a process has its own permissions, that the permissions follow from the area's role, and that any access outside them is a segmentation fault.
Background¶
memory-access.c has a global array data[], which the compiler places in .data (rw-), and a function exec_do_nothing(), placed in .text (r-x).
Three helpers read from, write to and jump to an address.
main() runs the four allowed combinations, and has three more commented out:
//do_exec("executing .data section", &data[0]);
//do_write("writing to .text section", exec_do_nothing, 77);
//do_read("reading from NULL", NULL);
Build and run¶
Then uncomment one of the three lines at a time, rebuild and run again.
Results and explanations¶
As shipped:
$ ./memory-access
reading from .data section
writing to .data section
reading from .text section
executing .text section
Reading data, writing data, reading code and running code all work.
Reading code is allowed because .text is r-x: the program may look at its own instructions, which debuggers and some runtimes rely on.
Each of the commented lines faults, for a different reason:
| Line | Area | Permissions | Why it faults |
|---|---|---|---|
execute .data |
data | rw- |
no execute permission: SEGV_ACCERR |
write .text |
code | r-x |
no write permission: SEGV_ACCERR |
read NULL |
none | -- | address 0 is in no area at all: SEGV_MAPERR |
The first two are the same mechanism as the basic-memory-operations demo: the address exists, the access kind is wrong.
The third is the other kind of fault, and the common one: an address that belongs to no area.
The kernel leaves the lowest pages of every address space unmapped on purpose, so that a NULL pointer dereference -- the most frequent bug in C -- crashes at once rather than quietly reading whatever happened to be at address zero.
Permissions are what turns the areas of part 03 from bookkeeping into protection. The code of a program cannot be overwritten by a stray pointer, its data cannot be executed by a stray jump, and nothing can be done through a pointer that was never set.
Going further¶
- Run each crashing variant under
straceand compare thesi_codeof theSIGSEGV:SEGV_ACCERRfor the first two,SEGV_MAPERRfor the third. readelf -S memory-access | grep -E 'text|data'shows the section flags (AXfor allocate-execute,WAfor write-allocate) that the loader turns into area permissions.- Build with
-Wl,-N(or-Wl,--omagic) and the write to.textsucceeds: that linker flag makes the code segment writable, the way it was on systems before theNXbit.
References¶
man 2 sigaction(SEGV_MAPERR,SEGV_ACCERR),man 7 signalman 1 readelf,man 1 ld(-N)