class: center, middle # Memory Protection ## Alan Cox and Scott Rixner --- layout: true --- # Memory Protection - Set the permissions of a memory region - Read, write, execute - Can be used to prevent access to certain memory regions - Accessing a memory region with the wrong permissions - Results in a segmentation fault - Can be caught using a signal handler - Sometimes, the handler can update the permissions so the program can continue --- # `mprotect(2)` ``` int mprotect(void *addr, size_t len, int prot); ``` - `addr`: starting address of the memory region - `len`: length of the memory region - `prot`: permissions to set - `PROT_READ`: allow reading - `PROT_WRITE`: allow writing - `PROT_EXEC`: allow execution - `PROT_NONE`: disallow all access - Returns `0` on success, `-1` (and sets `errno`) on error --- # Using `mprotect(2)` - `mprotect(2)` can be used to change the permissions of a memory region at any time - Starting memory address (`addr`) must be page aligned - Length (`len`) should be a multiple of the page size - If memory region is accessed with the wrong permissions the process will receive a segmentation fault (protection fault) --- # Example ``` size_t page_size = sysconf(_SC_PAGESIZE); // Get the system's page size // Check for errors! void *mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); strcpy(mem, "Hello, world!"); printf("Before mprotect: %s\n", (char *)mem); if (mprotect(mem, page_size, PROT_READ) == -1) { perror("mprotect failed"); exit(1); } strcpy(mem, "New Data!"); // This will crash the program // Check for errors! munmap(mem, page_size); ``` --- # Handling `SIGSEGV` - A signal handler can be used to catch the segmentation fault - Signal handler receives a `signinfo_t` struct: ``` typedef struct { int si_signo; /* Signal number */ int si_code; /* Signal code */ pid_t si_pid; /* Sending process ID */ uid_t si_uid; /* Real user ID of sending process */ void *si_addr; /* Memory location which caused fault */ int si_status; /* Exit value or signal */ union sigval si_value; /* Signal value */ } siginfo_t; ``` --- # Exercise `handle_sigsegv` - Write a signal handler for `SIGSEGV` - Checkpointed memory will be read-only after the first checkpoint - The signal handler should: - Convert the faulting address into a page-sized range, `page`, whose start is page aligned - Check if `page` intersects one the memory ranges being checkpointed - If so, `sio_assert` that this is a protection fault, restore write access to `page`. and add `page` to the `update_ranges` list - If not, allow the program to crash with a segmentation violation --- # Exercise `range_list_insert_tail` - Your `handle_sigsegv` will need to insert a new range into the `update_ranges` list - Implement `range_list_insert_tail`, which is called by `range_list_insert` to insert the new range in the correct sorted location --- class: center, middle # Get Started!