2

I need to do a small sw that needs to protect a page for read/write and then when the memory is accessed, It need to increment a counter and allow the read/write, after that it needs to then protect the memory back

I have this code but it is causing an infinite loop

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static int alloc_size;
static char* memory;

void segv_handler (int signal_number) 
{
 printf ("memory accessed!\n");
 /* allow read and write */
 mprotect (memory, alloc_size, PROT_READ | PROT_WRITE);

 /* Protect memory back*/
 mprotect (memory, alloc_size, PROT_NONE);
} 

int main ()
{
 struct sigaction sa;

 /* Install segv_handler as the handler for SIGSEGV. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &segv_handler;
 sigaction (SIGSEGV, &sa, NULL);

 alloc_size = 4096;
 memory = mmap (0, alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);   /* anonymous mapping doesn't need a file desc */

 /* Write to the page to obtain a private copy. */
 memory[0] = 0;
 memory[1] = 0;

 /* Make the memory unwritable. */
 mprotect (memory, alloc_size, PROT_NONE);
 /* Write to the allocated memory region. */
 memory[0] = 1; //--> this should trigger the SIGSEGV
 memory[1] = 1;

 /* All done; unmap the memory. */
 printf ("all done\n");
 munmap (memory, alloc_size);
 return 0;
}
George Koehler
  • 1,560
  • 17
  • 23
emalware
  • 73
  • 1
  • 9
  • possible duplicate of [Write a signal handler to catch SIGSEGV](http://stackoverflow.com/questions/2663456/write-a-signal-handler-to-catch-sigsegv) – Chris Dodd Aug 12 '12 at 02:19
  • I read this, but if possible a code example will be great because this other guys got many other issues, and futhermore I only have 2 weeks coding with C – emalware Aug 12 '12 at 17:12

2 Answers2

0

You said you want to basically (1) catch the invalid memory access, (2) temporarily unprotect the page, (3) allow the memory access, (4) reprotect the page, (5) resume normal execution. But that's not what your code does. Your segv_handler unprotects the page (step 2) and then immediately reprotects it again (step 4), so by the time your segv_handler returns it's too late for step 3. The insruction faults again and you get an infinite loop.

Installing a signal handler does not support what you need to do. What you need to do is make some changes, execute a single instruction, then make some more changes. Only single-steping the program under a debugger will allow you to do this.

ptrace is the system call you will need to do this. There are many questions on SO that talk about ptrace and single stepping, but I warn you: ptrace is not for the faint of heart, it's a lot more complicated than a signal handler.

Community
  • 1
  • 1
Celada
  • 21,627
  • 4
  • 64
  • 78
  • isn't this line allowing the read and write mprotect (memory, alloc_size, PROT_READ | PROT_WRITE);. this is part of a homework a i need to use signals – emalware Aug 13 '12 at 00:16
  • yes it would allow the access, but the very next line `mprotect (memory, alloc_size, PROT_NONE);` undoes the effect. – Celada Aug 13 '12 at 00:46
  • then, do you know any option using signals? – emalware Aug 13 '12 at 01:00
  • Please read what I wrote in my answer: "Installing a signal handler does not support what you need to do.". – Celada Aug 13 '12 at 01:03
  • thanks Celada, I saw your answer, but according to my operating system professor this is possible done using mmap, mprotect and signals – emalware Aug 13 '12 at 03:27
0

I think you can use some disassemble library such as Libasm to achieve this, but it will not looks so good.

In your segv_handler,

  1. Allow the read/write to the page
  2. Load the last instruction that cause the SIGSEGV, put it to a executable memory and run it.
  3. Apply the protection back
  4. Do something you want (increment a counter)
  5. Before segv_handler returns, modify the return address on the stack to the next instruction so you wont run that instruction twice and catch the signal again.
ItsEddy
  • 1
  • 1