-1

The title is misleading; let me clarify it. First let's consider a security context.

An attacking operation writes to some unmapped/inaccessible memory (e.g., due to heap buffer overflow). Assume I can capture the signal triggered by the memory access violation.

In the signal handler, can I strategically "mute" the write operation? An analogy is redirecting the stdout to /dev/null. In the meanwhile, I need to let the write operation finish, otherwise the control flow cannot move on (for example, the write pointer doesn't increase in the loop) and the program running is stuck.

I think the significance of the idea is that it mutes the attack without crashing the system, right?

Edit: I cannot change the user code. I think about manipulating the PC in my signal handler to skip the mov instruction. Will it work?

Infinite
  • 3,198
  • 4
  • 27
  • 36
  • Memory access violation would cause undefined behaviour or program crash. How do you capture and deal with the *signal* unless you are talking about how the compiler handles it? – ajay Feb 19 '14 at 16:46
  • 1
    Some valuable info is [here](http://stackoverflow.com/a/8456099/509868) – anatolyg Feb 19 '14 at 16:53
  • Thanks to ajay anatolyg. I understand that generally you cannot omit such a signal and the program status is probably corrupted, but my situation is special. I am 100% percent the attacker has no chance to corrupt any program data when I receive the signal. The signal in my case merely means the attacker has touched a page that I set up intentionally, like [electric fence](http://linux.die.net/man/3/efence) does. – Infinite Feb 19 '14 at 17:14
  • Afaik, a handler for a segfault must not return, because that will just cause the segfault to be rethrown. That means, you can only finish by either calling `abort()` or `exit()`, or trying to `longjmp()` out of the signal handler. If something like that is possible, it's excrutiatingly difficult to get right. But, most importantly, I think you are asking the wrong question. If you want to stop an attack, you must fix up the vulnerable code, not just try to arrest the attacker. And if the vulnerable code is too convoluted to fix, rewrite it. – cmaster - reinstate monica Feb 19 '14 at 18:36
  • In that case, you can simply change the protection on the page before returning from the handler and it will "work". But then, what have you gained? You are allowing the attacker to overwrite memory, not really a big step forward, is it? One needs to prevent attackers from doing buffer overruns in the first place by properly validating. Once they're able to write to some "illegal" place, you only have the option of crashing, or the option of allowing them to execute arbitrary code... neither of which is good. – Damon Feb 19 '14 at 18:36
  • Or put differently, there is a good reason why the SEGFAULT happened. You can of course "fix" it and continue, but the mere fact that it happened in the first place was already wrong. – Damon Feb 19 '14 at 18:38

1 Answers1

1

You can most definitely do it, but it's hard, and it can't be done without architecting your entire software stack to be resilient against such failures. You may end up implementing half of Erlang by the time you're done :)

You must essentially run a debugger in a separate thread, attached to your own application, and use platform-specific debug APIs to get a notification of a hardware (CPU) exception happening in the watched thread(s).

Upon such notification, the monitored thread is suspended, and you will have access to the state of registers at the moment the fault happened. At that point you can disassemble the instruction to determine its length, and rewrite it with NOPs. You'd also need to identify in what kind of a memory space is the instruction that has faulted - if it's in your own code, you should definitely not touch anything and simply resume the thread, letting the native signal/exception handlers (if any) take care of it. You should only catch such issues when they happen in the non-code area (say: data area).

Alas, on most sane platforms, the data pages won't be executable anyway, so the hardware exception that you catch will indicate that code execution is attempted in a non-executable page. There's no trivial way around that short of doing stack analysis and figuring out where the code should be executing instead. It would be a very bad idea indeed to defeat data execution prevention at run-time by making the page executable!

Ideally, when faults occur, you should have a mechanism of terminating and restarting the thread in question. That's the approach taken by Erlang: let it crash and re-start the crashed thread/process.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313