7

Does there exist a way to allocate some memory and have some sort of callback (be it pointer to a function or signal) when the memory is being accessed (either read or written to)?

For example, if I said allocate 1mb of memory, I would like to have a way to call a function when any of that 1mb is being accessed.

The platform I'm working on is x86 Linux and writing in C/C++.

Sergey K.
  • 24,894
  • 13
  • 106
  • 174
John
  • 73
  • 1
  • 3
  • possible duplicate of [Possible to trap write to address (x86 - linux)](http://stackoverflow.com/questions/608584/possible-to-trap-write-to-address-x86-linux) – caf Jun 02 '11 at 07:52

4 Answers4

8

Yes, there is.

Use the mprotect(2) system call (see: http://linux.die.net/man/2/mprotect) to set read only or no access memory protection on the page and set a SIGEGVsignal handler that will be called when the memory has been accessed.

Note that you will need to use mprotect in your signal handler to actually allow the memory access once your signal handler is called and when you do you open a window to anything else to access the memory without you knowing it, for example from a different thread. This may or may not be an issue depending on your specific usage.

gby
  • 14,900
  • 40
  • 57
  • Yes, but doesn't that actually prevent the access? I think the question was how to know about the access, not how to prevent it. – littleadv Jun 02 '11 at 07:07
  • What will happen is that your program gets a SIGSEGV signal. You can catch the signal and use mprotect to change the memory protection to enable the action and when you return from the signal handler the operation will succeed automagically since the program pointer still points to the same location. There is a race condition hidden here, which may or may not be an issue. I have edited the answer to expand on this. Thanks – gby Jun 02 '11 at 07:11
  • @gby - But once you changed the permissions - you no longer can track it, because subsequent accesses with the same privileges will not trigger a signal. So it's kindof a one-time thingy, isn't it? – littleadv Jun 02 '11 at 07:12
  • To be honest, mprotect() is not listed as async-signal safe, so using it in this manner may cause dead locks *in theory* (if mprotects tries to take a lock in the C library that is already taken when the signal hit). In practice, I suspect that mprotect under glibc/linux doesn't take any such lock but I have no validated this. – gby Jun 02 '11 at 07:17
  • @littleadv well you can change the permission back after you're done with it or even set a timer in the signal handler and set it back there, but you are very right - there is an open window after each access where you don't track all accesses. Depending on what you want to do this may or not be a problem. For a lot of use cases (e.g. finding out who the heck writes junk on your data structure) it can be a life saver – gby Jun 02 '11 at 07:19
  • @gby - yeah, makes sense. To be bullet proof I'd combine it with the smart pointer though - this way you can also count access while permission doesn't change and trace loops and such. – littleadv Jun 02 '11 at 07:22
  • 1
    Instead of using timer you can try to patch code after the instruction that reads/writes the data to the page, place breakpoint (INT3) there and restore protection after the access. It's not bullet-proof (remember the threads), but much better than timer. – darkk Jun 09 '11 at 09:30
  • @darkk It works, but only as long as a debugger is not attached. Any idea how to patch the code after the instruction that reads/writes the data, *without* triggering the debugger? – Amir Gonnen May 28 '13 at 09:24
  • @AmirGonnen you can patch code with `jmp` to your code, but it needs more bytes than INT3, so it's a bit harder to restore original code in this case. Think about crossing page boundary and different permissions for pages. Another option is to push jmp point to stack and use RET instead of INT3 as one-byte-jmp-instruction. You should also remember that another thread may jump right into opcode you're patching, so you should be accurate if you want stable solution. :) – darkk May 28 '13 at 13:53
  • @darkk I need to put the `jmp`/`ret` right after the instruction that reads/writes the data. How do I find this point? I need to find out the length of the instruction that reads/writes the data. Can I know this without parsing the opcode/prefix etc'? – Amir Gonnen May 28 '13 at 15:23
  • @AmirGonnen I know no good heuristic to determine opcode length, but there are libraries that can do it for you. Also, you can copy memory-modifying instruction to a memory buffer and overwrite the instruction with jmp to the buffer appending jmp-back to the buffer :) It may be a bit easier in some cases. – darkk May 28 '13 at 18:46
3

You can use your own version of a "safe-pointer"-like class which will wrap the allocated pointer, and by the way will have an implementation of the dereference operator. It will require using it of cause for allocations, though.

Something in these lines:

// based on pretty standard auto_ptr
template <class T> class auto_ptr
{
    T* ptr;
public:
    explicit auto_ptr(T* p = 0) : ptr(p) {}
    ~auto_ptr()                 {delete ptr;}
    T& operator*()              {return *ptr;}   // <<--- add your stuff here
    T* operator->()             {return ptr;} // <<--- and here
    // .
};
littleadv
  • 20,100
  • 2
  • 36
  • 50
1

I don't think there is such an API to do so, until you create a wrapper object around the allocated memory and then access to the memory is done through this wrapper object. Then this wrapper object will be able to see all access to the underlying memory.

Ankur
  • 33,367
  • 2
  • 46
  • 72
0

Well....you could set up a buffer. You could even just set up an array with the allocation. Then set up an if statement that if anything tampers with that array section, for instance if the array was defaulted to have a value of 0 at an index, and now its not, call whatever you want to do.

If you want a lot to happen, and then the program break and respond to that allocation being tampered with, set a boolean and when the value is changed, the boolean goes to true, and have a function posted to check that boolean.

TheChes44
  • 648
  • 1
  • 10
  • 21