Live data from Hacker News

Return to abort() – Using code introspection to prevent stack-smashing

github.com

1–10 of 21 posts

Re: Return to abort() – Using code introspection to prevent stack-smashing

#3
post #2

Why isn't the return address stored in a register instead of on the stack to avoid this in the first place?

It has to get put on the stack at some point so you can call more than 1 function deep. So why not always put it on the stack so that you don't waste a valuable register?

Re: Return to abort() – Using code introspection to prevent stack-smashing

#4
So this limits the number of gadget options you have for ROP, but doesn't eliminate ROP entirely, right? It maybe increases the difficulty of ROP, if you can't find enough/sufficient gadgets that happen to start after function call sites. Not a silver bullet, anyway.

Re: Return to abort() – Using code introspection to prevent stack-smashing

#5
post #2

Why isn't the return address stored in a register instead of on the stack to avoid this in the first place?

It is stored in a register on some architectures like ARM. However, that register gets spilled to the stack to store another return address there when calling another level deeper. It doesn't change much. It does make it easier to implement return address control flow integrity that's not vulnerable to a race window between the CFI check and the return.

Re: Return to abort() – Using code introspection to prevent stack-smashing

#6
post #3
post #2

Why isn't the return address stored in a register instead of on the stack to avoid this in the first place?

It has to get put on the stack at some point so you can call more than 1 function deep. So why not always put it on the stack so that you don't waste a valuable register?

The answer to "why not always put it on the stack" is "because a lot of functions are leaf functions and so always writing it to the stack is making every function pay the memory access hit rather than just the ones that need it". RISC-ish architectures tend to have enough registers that dedicating one to a link pointer isn't a big deal (and once you do spill it to the stack you can use the link register as a temporary register anyway).

Some very early CPU architectures didn't actually support either putting the return address in a register or on the stack. For instance, on the PDP-8 (https://en.wikipedia.org/wiki/PDP-8#Subroutines) the JMS instruction writes the return address to the first word of the subroutine it's about to call (and the actual subroutine entry point is just after that), which meant it didn't conveniently support recursion. It wasn't alone in that either -- I think that it just wasn't quite appreciated how important recursion/reentrancy was back in the early 60s when these ISAs were designed.

Re: Return to abort() – Using code introspection to prevent stack-smashing

#7
post #4

So this limits the number of gadget options you have for ROP, but doesn't eliminate ROP entirely, right? It maybe increases the difficulty of ROP, if you can't find enough/sufficient gadgets that happen to start after function call sites. Not a silver bullet, anyway.

i think all the ROPs i used in the last exploit i wrote were all not real instructions. these seem to be the most interesting.

Re: Return to abort() – Using code introspection to prevent stack-smashing

#8
post #4

So this limits the number of gadget options you have for ROP, but doesn't eliminate ROP entirely, right? It maybe increases the difficulty of ROP, if you can't find enough/sufficient gadgets that happen to start after function call sites. Not a silver bullet, anyway.

I don't believe there are any silver bullets in security.

Re: Return to abort() – Using code introspection to prevent stack-smashing

#9
post #4

So this limits the number of gadget options you have for ROP, but doesn't eliminate ROP entirely, right? It maybe increases the difficulty of ROP, if you can't find enough/sufficient gadgets that happen to start after function call sites. Not a silver bullet, anyway.

Well, it means that modulo hash collisions, a function can only return to one of the places which calls that function, so in the really tragic case (for example) that someone called a vulnerable function and then immediately after called system() with a stack variable as the arg, the attacker can just return there and make the arg point to "bash". But in general the whole business of knitting together assembly instructions in executable memory would pretty much be gone. Edit: typo, clarity

Re: Return to abort() – Using code introspection to prevent stack-smashing

#10
post #9
post #4

So this limits the number of gadget options you have for ROP, but doesn't eliminate ROP entirely, right? It maybe increases the difficulty of ROP, if you can't find enough/sufficient gadgets that happen to start after function call sites. Not a silver bullet, anyway.

Well, it means that modulo hash collisions, a function can only return to one of the places which calls that function, so in the really tragic case (for example) that someone called a vulnerable function and then immediately after called system() with a stack variable as the arg, the attacker can just return there and make the arg point to "bash". But in general the whole business of knitting together assembly instru…

Is it really limited to only call sites of that function, or to all call sites? I can't tell if their return cookie is shared throughout the binary or unique to callees.
Post reply on HN