Live data from Hacker News

Mandatory enforcement of indirect branch targets

undeadly.org

81–90 of 134 posts

Re: Mandatory enforcement of indirect branch targets

#81
post #18

Earlier quoted context omitted.

C allows for any function to be called via a function pointer, and functions can be in different translation units, so the compiler can't simply assume that a function will never be called indirectly and has to pessimistically insert endbr64 in order to maintain a reasonable ABI. And no, as I understand it, this is only for branch/calls not returns.

Is this theoretically something lto could remove?

If you disable dlopen and ld_preload.

Re: Mandatory enforcement of indirect branch targets

#82

Earlier quoted context omitted.

You've got it backwards: this hardware solution makes the software solutions irrelevant.

Nope. Here's the actual problem, in these crappy languages it's really easy for mistakes to result in a stack smash, so, these types of hacks aim to make it harder for the bad guys to turn that into arbitrary remote code execution. Not impossible, just harder. Specifically in this case the idea is that they won't be able to abuse arbitrary bits of function without calling the whole function, at a cost of some hardwar…

I’m always amused by how many of OpenBSD’s mitigations are patching over something as basic as lack of bounds checking, yet they’ll never add bounds checking. And, as you said, those are all just speed bumps, not fixes.

Re: Mandatory enforcement of indirect branch targets

#83

Earlier quoted context omitted.

Nope. Here's the actual problem, in these crappy languages it's really easy for mistakes to result in a stack smash, so, these types of hacks aim to make it harder for the bad guys to turn that into arbitrary remote code execution. Not impossible, just harder. Specifically in this case the idea is that they won't be able to abuse arbitrary bits of function without calling the whole function, at a cost of some hardwar…

I think one could argue that all the software mitigations that aren't based on compile time proofs result in quite a bit more "emitting unnecessary code", if "unnecessary" is taken to mean "not strictly intrinsic to the task of the program". And undefined behavior is bad, but getting rid of it wouldn't be a silver bullet for this problem in C, I think. All undefined behavior could become "implementation defined" tomo…

> All undefined behavior could become "implementation defined" tomorrow, where the C compiler becomes more like a high-level assembler (again), and you could still jump the instruction pointer into arbitrary program text.

Try to work this through in your head. Imagine how you need to specify the working of the abstract machine in order to allow this. How do we talk about an "instruction pointer" on the abstract machine? What are the instructions it's pointing to? Am I defining an entire bytecode VM?

Nah, instead you're going to do one of two things. One: "Undefined Behaviour" which we explicitly took off the table, or Two: "If this happens the program aborts". And with that the big problem evaporates. Does it make those C programmers happy? I expect not.

Re: Mandatory enforcement of indirect branch targets

#84

Earlier quoted context omitted.

I think one could argue that all the software mitigations that aren't based on compile time proofs result in quite a bit more "emitting unnecessary code", if "unnecessary" is taken to mean "not strictly intrinsic to the task of the program". And undefined behavior is bad, but getting rid of it wouldn't be a silver bullet for this problem in C, I think. All undefined behavior could become "implementation defined" tomo…

> All undefined behavior could become "implementation defined" tomorrow, where the C compiler becomes more like a high-level assembler (again), and you could still jump the instruction pointer into arbitrary program text. Try to work this through in your head. Imagine how you need to specify the working of the abstract machine in order to allow this. How do we talk about an "instruction pointer" on the abstract machi…

Implementation defined means the compiler must specify the behavior, but it has near total freedom, and it can define it specific to the target system. There is no abstract machine. If I use GCC on Linux x86-64, then there very much is an instruction pointer.

Re: Mandatory enforcement of indirect branch targets

#85
post #63

Earlier quoted context omitted.

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?

I'd assume so since it wouldn't be a call/jmp coming from a computed address in a register. That said I haven't read the documentation for any of this. But interrupts should be having a stack pointer change and other things happening that would be different, which is why they use the IRET instruction and not the RET one.

Re: Mandatory enforcement of indirect branch targets

#86

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…

This is my main takeaway too. As a one time OpenBSD enthusiast (and still admirer), now I'm a bit older I find the continual smugness starts to grate.

Truth is, Linux has a lot more constraints on how it can implement something because it has users. Users that have all sorts of different ways they need it to work.

Re: Mandatory enforcement of indirect branch targets

#87
post #52

Earlier quoted context omitted.

Interesting. Seems like enforcement on Intel CPUs is supported since Tiger Lake (so ~2020). Windows has basically the same feature implemented in software since 2015, called Control Flow Guard [1]. I wonder what the story there is, and if Windows has any plans to (get everyone to) switch to the hardware version once those CPUs have sufficient market share. 1: https://learn.microsoft.com/en-us/windows/win32/secbp/cont…

Windows also recently implemented a far better version of this called Extended Flow Guard (XFG) that not only checks whether the location is a valid destination, but also whether it's a valid destination for that specific source. For example, for any virtual function call or function pointer call, the destination must have a correct tag with the hash of the arguments. It's much more secure, and also faster, since loa…

That does sound like it would be more robust, but definitely sounds like it'd require a lot more silicon than the IBT that they did implement. Something like it might be something that comes in some future revisions.

Re: Mandatory enforcement of indirect branch targets

#88
post #8

Earlier quoted context omitted.

Various architectures do other interesting things with NOPs, IIRC one convention on PowerPC had something vaguely related to debugging or tracing (I can't remember the details or find any references right now).

RISC-V has a whole HINT space that's basically just morphs of load immediate into zero register. AArch64 has a similar space: https://developer.arm.com/documentation/ddi0596/2020-12/Base... And yes, PowerPC has a similar space as well holding hints like 'give priority to the other hardware threads on this core' and the like. https://utcc.utoronto.ca/~cks/space/blog/tech/PowerPCInstruc...

I was wondering where did I read about PowerPC, and this is exactly the article! So, it was for thread priority. Strikes me as an odd design choice, this probably should've been something to be managed by the OS more explicitly.

Re: Mandatory enforcement of indirect branch targets

#89
post #2

For anybody unfamiliar with this, as I was, this appears to refer to Intel's Indirect Branch Tracking feature[1] (and the equivalent on ARM, BTI). The idea is that an indirect branch can only pass control to a location that starts with an "end branch" instruction. An indirect branch is one that jumps to a location whose value is loaded or computed from either a register or memory address: think calling a function poi…

It was an old joke that the opposite of "goto" is "come from", or that if goto is considered harmful, nobody said anything about a "come from". Marking something as a branch target reminds me of this.

https://en.m.wikipedia.org/wiki/COMEFROM

Re: Mandatory enforcement of indirect branch targets

#90

Earlier quoted context omitted.

> All undefined behavior could become "implementation defined" tomorrow, where the C compiler becomes more like a high-level assembler (again), and you could still jump the instruction pointer into arbitrary program text. Try to work this through in your head. Imagine how you need to specify the working of the abstract machine in order to allow this. How do we talk about an "instruction pointer" on the abstract machi…

Implementation defined means the compiler must specify the behavior, but it has near total freedom, and it can define it specific to the target system. There is no abstract machine. If I use GCC on Linux x86-64, then there very much is an instruction pointer.

In the real world, compilers just specify that the behaviour is undefined and tell you to suck it up. But we're talking about a hypothetical where we aren't allowing Undefined Behaviour. Saying "Oh, but we can if we say it's the implementation choosing" is a get out which is meaningless for the hypothetical. Just refuse to engage with the hypothetical instead if you don't like it.
Post reply on HN