2

In x86, GCC generates the following instructions when it wants to call __stack_chk_fail:

; start of the basic block
00000757         call       sub_590 ; __stack_chk_fail@plt
0000075c         add        byte [ds:eax], al
0000075e         add        byte [ds:eax], al
; start point of another function

Similar behavior happens in ARM:

; start of the basic block
00001000         bl         __stack_chk_fail@PLT
00001004         dd         0x0000309c ; data entry, NOT executable indeed!

In static analysis tools, when one wants to build a CFG, the CFG algorithm can't determine last instruction of the basic block which the __stack_chk_fails is called in.

It's reasonable to have some sort of return instruction after calling __stack_chk_fail to prevent CPU to execute instructions (or potentially data entries) which it shouldn't.

In these cases, CFG generator algorithm assumes it's a regular function call and continues traversing to another function's code (in the former example) or to data entries (in the later one) which is totally unwanted.

So, my question is why doesn't GCC insert a return (or branch) instruction at the end point of the basic block?

frogatto
  • 28,539
  • 11
  • 83
  • 129
  • 1
    Isn't the `__stack_chk_fail` function guaranteed to be `noreturn`? Are you just asking why the compiler doesn't generate double-defensive code? – Cody Gray - on strike Jul 08 '16 at 12:51
  • @CodyGray I agree with you. `__stack_chk_fail` never returns. But how would a static analysis tool which wants to build a CFG, know whether it's dealing with a `noreturn` function or not? Such functions make them to build completely wrong CFGs. – frogatto Jul 08 '16 at 12:56
  • @HiI'mFrogatto I'd expect there to be a way of annotating functions as `noreturn` for the analysis tool, otherwise `exit()` would be problematic too. – EOF Jul 08 '16 at 12:58
  • @EOF No annotations AFAIK. There's only a jump to a function at `.plt` wherein there's another jump to a `got` entry. – frogatto Jul 08 '16 at 13:00
  • 1
    I'm expecting that *you* can *manually* tell the tool that any jump/call to that address will not return. I'd have a look at the tool's documentation, see how they treat `exit()`. – EOF Jul 08 '16 at 13:02
  • @EOF Seems the only way is to hard-coding such functions. Thanks anyway. – frogatto Jul 08 '16 at 13:04
  • Arguably, it would make more sense for the compiler to generate an unconditional jump to a `noreturn` function, like `__stack_chk_fail`. I'm not sure why it uses `call` instead. But as others have said, surely your static analysis tool provides some facility to consider function annotations. – Cody Gray - on strike Jul 08 '16 at 13:04
  • 1
    @CodyGray: I think it uses `call` to pass a return address so `__stack_chk_fail` can tell where the check failure happened. This is the same as when throwing an exception. It puzzled me, too, until I realized that the return address was important, even though it isn't fed to a `ret` instruction. – Peter Cordes Jul 08 '16 at 15:28

0 Answers0