Re: [RFC] Circumventing FineIBT Via Entrypoints

From: David Laight
Date: Mon Feb 17 2025 - 08:11:59 EST


On Sat, 15 Feb 2025 22:07:29 +0100
Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:

> On Fri, Feb 14, 2025 at 10:57:51AM +0100, Peter Zijlstra wrote:
> > On Thu, Feb 13, 2025 at 12:53:28PM -0800, Kees Cook wrote:
> >
> > > Right, the "if they can control a function pointer" is the part I'm
> > > focusing on. This attack depends on making an indirect call with a
> > > controlled pointer. Non-FineIBT CFI will protect against that step,
> > > so I think this is only an issue for IBT-only and FineIBT, but not CFI
> > > nor CFI+IBT.
> >
> > Yes, the whole caller side validation should stop this.
>
> And I think we can retro-fit that in FineIBT. Notably the current call
> sites look like:
>
> 0000000000000060 <fineibt_caller>:
> 60: 41 ba 78 56 34 12 mov $0x12345678,%r10d
> 66: 49 83 eb 10 sub $0x10,%r11
> 6a: 0f 1f 40 00 nopl 0x0(%rax)
> 6e: 41 ff d3 call *%r11
> 71: 0f 1f 00 nopl (%rax)

I tried building a fineibt kernel (without LTO) and that isn't what I
see in the object files.
(I not trying to run it, just do some analysis.)
While the call targets have a 16 byte preamble it is all nops apart
from a final 'mov $hash,%rax'.
The call site loads $-hash and adds -4(target) and checks for zero.
It is too small to be patchable into the above.

There are far too many TLA (and ETLA) to follow all the options.

I did notice that although objtool seems to have code to remove 'spare'
endbra, the 'mov %rax,$hash' was present on all external functions.
Some 1600 are void fn(void) - there are high counts of others.


> Of which the last 6 bytes are the retpoline site (starting at 0x6e). It
> is trivially possible to re-arrange things to have both nops next to one
> another, giving us 7 bytes to muck about with.
>
> And I think we can just about manage to do a caller side hash validation
> in them bytes like:
>
> 0000000000000080 <fineibt_paranoid>:
> 80: 41 ba 78 56 34 12 mov $0x12345678,%r10d
> 86: 49 83 eb 10 sub $0x10,%r11
> 8a: 45 3b 53 07 cmp 0x7(%r11),%r10d
> 8e: 74 01 je 91 <fineibt_paranoid+0x11>
> 90: ea (bad)
> 91: 41 ff d3 call *%r11
>
> And while this is somewhat daft, it would close the hole vs this entry
> point swizzle afaict, no?

Doesn't it have the problem that it includes the value of the hash?
So you can arrange to jump directly into the sequence itself.

David