LWN.net Logo

Make the stack less fragile

Make the stack less fragile

Posted Feb 2, 2012 11:03 UTC (Thu) by epa (subscriber, #39769)
Parent article: Format string vulnerabilities

Why not a different calling convention? Push the arguments onto the stack followed by an integer saying how many arguments there are. Then it will be impossible to mistakenly pop off too many or too few.

This would slow down function calls a little bit, but it could be used as an alternative calling convention for varargs functions only. There would still be format string vulnerabilities, but this particular class of them would go away.


(Log in to post comments)

Make the stack less fragile

Posted Feb 2, 2012 12:53 UTC (Thu) by etienne (subscriber, #25256) [Link]

You can have a lot of different and incompatible calling conventions, like pushing the number of parameters (as a 32 or 64 bits number), pushing the size of the parameter area in bytes, telling which parameters are const pointers and which are pointers to variables, ...
That will often result in more security, but also slower software; and in C the simplest system has been chosen, which allows you to "bolt-on" more complex ones if you wish.

Make the stack less fragile

Posted Feb 2, 2012 16:50 UTC (Thu) by epa (subscriber, #39769) [Link]

I think that the C standard doesn't specify any particular calling convention? Implementers are free to implement stack frames and function calls however they like.

Make the stack less fragile

Posted Feb 3, 2012 20:15 UTC (Fri) by nix (subscriber, #2304) [Link]

Yes, but in practice for existing platforms such things are frozen by the needs of interoperability.

Make the stack less fragile

Posted Feb 3, 2012 20:15 UTC (Fri) by nix (subscriber, #2304) [Link]

Doesn't help. Now all you need to do is buffer-overrun that integer and you can pop as many args as you like, or as few. You've just given the attacker control over the stack frame in ways they can only dream of right now, so they can force functions to execute with other functions' local variables overlapping their own, or with garbage, or with their own local variables' values shifted into other variables partially or completely. A whole new class of security holes!

Make the stack less fragile

Posted Feb 5, 2012 10:38 UTC (Sun) by epa (subscriber, #39769) [Link]

Not so: clearly the generated code for a function such as foo(int a, int b) would first check that exactly two items are on the stack. If the integer at the top of the stack is not 2, then something has gone very wrong.

The only case where this integer number of arguments would change the program's behaviour (as opposed to redundantly stating what is already expected to be the case) is for varargs functions. And in those cases you validate the number of arguments on the stack against an expected number. If the format string is "%d%d" but there are 3 values on the stack, again something is wrong.

To cause an exploit the attacker must both manipulate the format string and somehow overwrite the number-of-arguments value at the top of the stack. It is no longer possible to take too many or too few values from the stack because of a format string vulnerability or other varargs bug.

Make the stack less fragile

Posted Feb 5, 2012 21:19 UTC (Sun) by nix (subscriber, #2304) [Link]

Well, yes, the attack vector is exactly that: overwrite the num-of-args value, and all bets are off.

Make the stack less fragile

Posted Feb 6, 2012 11:37 UTC (Mon) by epa (subscriber, #39769) [Link]

Perhaps I don't understand what you mean. To attack a varargs function such as printf() you would need to attack *both* the format string vulnerability and smash the stack somehow to overwrite the number-of-args value. This is harder than just exploiting the format string without stack protection.

So if printf() gets the format string "%d %d" but number-of-args != 2, it aborts. You would need to find a format string vulnerability *and* a stack-overwriting exploit to change the number-of-args value.

If you overwrite just the number-of-args value at the top of the stack, this is merely a denial of service attack for a call foo(a, b). It would not cause foo() to somehow take three arguments instead, because the number of args to pop off the stack is compiled in. Given all the other fun and games you can get by overwriting values on the stack (the return address in particular), I don't think that a number-of-args value presents a juicy target.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds