Live data from Hacker News

Mandatory enforcement of indirect branch targets

undeadly.org

61–70 of 134 posts

Re: Mandatory enforcement of indirect branch targets

#61
post #43

Earlier quoted context omitted.

> Why should every function start with endbr64 command? Aren't functions usually called directly? They're usually called directly, but unless the compiler can prove that they always are (e.g., if they're static and nothing in the same file takes the address), endbr64 is required. > Also, is it required to insert endbr64 command after function calls (for return address)? No, IBT is only for jmp and call. SS is the equ…

> but unless the compiler can prove that they always are (e.g., if they're static and nothing in the same file takes the address), endbr64 is required Then why not just have the compiler break down every non-static function into two blocks: a static function that contains all the logic, and a non-static function that just contains an IBT and a direct jump to the static function? (Or, better yet, place the non-static…

The IBT NOP is "free" in that it will evaporate in the pipeline; it still has to be fetched and decoded to some extent, but it does not consume execution resources.

From a tooling perspective, what you're describing (two entrypoints for a function, the jump you mention is pointless) would require changes up and down the toolchain; it would affect the compiler, all linkers, all debuggers, etc. By contrast, just adding an additional instruction to the function prolog is relatively low-impact.

It's also worth noting that at the time code for a function is emitted, the compiler is not aware of whether the symbol will be exported and thus discoverable in some other module, or by symbol table lookup, so emitting the target instruction is essentially mandatory.

Re: Mandatory enforcement of indirect branch targets

#62

Earlier quoted context omitted.

I don't really buy their approach to security honestly. Trying to fix all bugs is great, but they provide little to prevent unknown bugs bing exploited (pledge is nice for software that opts in to use it, but otherwise not so much). I'd love to see them implement something like AppArmor with their approach, it would probably be amazing. I actually think NetBSD is a pretty interesting alternative, it has some nice sec…

> they provide little to prevent unknown bugs bing exploited They provide plenty of mitigations ( https://www.openbsd.org/innovations.html ). In fact OP's article is for preventing unknown bugs from being exploited.

They don't provide any mitigations of the sort I was clearly referencing. Specifically, for restricting malicious code or users that already has access to the system, exploiting insecure software that was not compiled with pledge support.

Re: Mandatory enforcement of indirect branch targets

#63
post #4

Earlier quoted context omitted.

The fun fact being that older CPUs decode ENDBR64 as a slightly weird NOP (with no architectural effects), but it'll fault on original Pentiums: https://stackoverflow.com/questions/56120231/how-do-old-cpus...

There's a good question in the comments there that I still don't see the answer to. How does this work if there's an interrupt between the branch and the endbranch? Does the OS need to save/restore the "branchness" bit?

there is no branchness bit, if there's an endbranch you can jump to it

Re: Mandatory enforcement of indirect branch targets

#64
post #43

Earlier quoted context omitted.

> but unless the compiler can prove that they always are (e.g., if they're static and nothing in the same file takes the address), endbr64 is required Then why not just have the compiler break down every non-static function into two blocks: a static function that contains all the logic, and a non-static function that just contains an IBT and a direct jump to the static function? (Or, better yet, place the non-static…

What is the overhead of executing the IBT NOP?

It's not "executed" per se. It consumes space in the cache hierarchy, and a slot in the front-end decoder. It won't ever be issued, but depending on the microarchitecture in question it might result in an issue cycle having less occupancy than it might have had in the case where the subsequent instruction was available.

With that said, the first few instructions of a called function often stall due to stack pointer dependencies, etc. so the true execution cost is likely to be even smaller than the above might suggest.

Re: Mandatory enforcement of indirect branch targets

#65
post #4

Earlier quoted context omitted.

The fun fact being that older CPUs decode ENDBR64 as a slightly weird NOP (with no architectural effects), but it'll fault on original Pentiums: https://stackoverflow.com/questions/56120231/how-do-old-cpus...

There's a good question in the comments there that I still don't see the answer to. How does this work if there's an interrupt between the branch and the endbranch? Does the OS need to save/restore the "branchness" bit?

Yes, on arm the branch type is saved in SPSR_EL1 in the BTYPE field. That stands for Saved Program State Register for Kernel Mode (Exception Level 1) and Branch Type. https://developer.arm.com/documentation/ddi0595/2021-12/AArc...

Re: Mandatory enforcement of indirect branch targets

#66
post #21

Earlier quoted context omitted.

It's an important comparison of the mechanisms, even in 2023, you can still find binaries on modern Linux distributions with executable stacks due to the fail-open design, 20 years later. The fact that Linux hasn't learned the right lessons in 20 years, and has chosen to "double down" in respect to IBT/BTI, does not inspire confidence that they will ever fix it. I'd say his 20 year estimate was in fact being pretty g…

> It's an important comparison of the mechanisms, even in 2023, you can still find binaries on modern Linux distributions with executable stacks due to the fail-open design, 20 years later. Unfortunately, for C code using GCC’s nested functions extension (or for languages that want to be ABI-compatible with C and support nested functions, like that paragon of advanced features called Pascal /s ), there’s no other com…

That strategy won't fly with IBT.

Now all software must pay the price and miss out on important mitigations, for all eternity, just because of some largely unused feature in one compiler?

Re: Mandatory enforcement of indirect branch targets

#67
post #63

Earlier quoted context omitted.

There's a good question in the comments there that I still don't see the answer to. How does this work if there's an interrupt between the branch and the endbranch? Does the OS need to save/restore the "branchness" bit?

there is no branchness bit, if there's an endbranch you can jump to it

Ah so when you return from an interrupt, the check is no longer done?

Re: Mandatory enforcement of indirect branch targets

#69
post #21

Theo had to get his digs in against Linux in that announcement. Why not just focus on what OpenBSD is doing, and maybe contrast it to what Linux does without the speculation that they will still be doing the same thing in 20 years. He's unquestionably brilliant, but I've had a few encounters with him on the mailing lists and he is so quick to take offense where none was meant and drop into name-calling and insults. I…

It's an important comparison of the mechanisms, even in 2023, you can still find binaries on modern Linux distributions with executable stacks due to the fail-open design, 20 years later. The fact that Linux hasn't learned the right lessons in 20 years, and has chosen to "double down" in respect to IBT/BTI, does not inspire confidence that they will ever fix it. I'd say his 20 year estimate was in fact being pretty g…

The funny thing is that this attitude towards breaking changes is one of the reasons why Theo is able to make this comment at all. If he would allow breaking changes then OpenBSD adoption likely would be higher and that in turn would cause him to resist the kind of things that Linux would not be able to get away with.

It's clearly different philosophies leading to different outcomes with neither of them clearly better than the other, it just depends on what you need. It would be possible to make that statement in a more graceful way.

Re: Mandatory enforcement of indirect branch targets

#70
post #66

Earlier quoted context omitted.

> It's an important comparison of the mechanisms, even in 2023, you can still find binaries on modern Linux distributions with executable stacks due to the fail-open design, 20 years later. Unfortunately, for C code using GCC’s nested functions extension (or for languages that want to be ABI-compatible with C and support nested functions, like that paragon of advanced features called Pascal /s ), there’s no other com…

That strategy won't fly with IBT. Now all software must pay the price and miss out on important mitigations, for all eternity, just because of some largely unused feature in one compiler?

IBT is already further along here. The hypothetical solution for executable stacks is to recompile all of your nested-function-using or -calling code with -ftrampolines (except that won’t work without the patch above—silently, really GCC?..). The already real and working solution for IBT is to recompile all of your indirect-branch-using code with -fcf-protection=branch. So, ignoring the fact that nested functions are in practice much rarer, if you accept the former as valid you’ll need to accept the latter as well, as far as logic as concerned.

I wouldn’t characterize this as a “largely unused feature in one compiler” screwing things up, but rather as the ABI on most Linux and -adjacent platforms (except SysV Itanium and FDPIC IIRC) being incapable of supporting closures (without executable stacks). That these are missing from standard C, and only present in languages that are either niche (Pascal, Ada) or don’t care about following the platform ABI (Rust, Go, C++’s lambdas), is a defect of C (and that’s at least a somewhat popular opinion among ISO C committee members[1]).

Of course, OpenBSD essentially does not have a stable ABI, so it’s much freer to experiment here.

[1] https://thephd.dev/lambdas-nested-functions-block-expression...

Post reply on HN