On Wed, Nov 22, 2023 at 3:15 AM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote: > > > To be very explicit, let me list all the various forms of function > calls: > > Traditional: > > foo: > ... code here ... > ret > > direct caller: > > call foo > > indirect caller: > > lea foo(%rip), %r11 > call *%r11 > > IBT: > > foo: > endbr64 > ... code here ... > ret > > direct caller: > > call foo / call foo+4 > > indirect caller: > > lea foo(%rip), %r11 > ... > call *%r11 > > > kCFI: > > __cfi_foo: > movl $0x12345678, %rax > (11 nops when CALL_PADDING) > foo: > endbr64 (when also IBT) > ... code here ... > ret > > direct caller: > > call foo / call foo+4 > > indirect caller: > > lea foo(%rip), %r11 > ... > movl $(-0x12345678), %r10d > addl -15(%r11), %r10d (or -4 without CALL_PADDING) > je 1f > ud2 > 1:call *%r11 > > > FineIBT (builds as kCFI + CALL_PADDING + IBT + RETPOLINE and runtime > patches things to look like): > > __cfi_foo: > endbr64 > subl $0x12345678, %r10d > jz foo > ud2 > nop > foo: > osp nop3 (was endbr64) > ... code here ... > ret > > direct caller: > > call foo / call foo+4 > > indirect caller: > > lea foo(%rip), %r11 > ... > movl $0x12345678, %r10d > subl $16, %r11 > nop4 > call *%r11 Got it. That helps a lot! You kind of have this comment scattered through arch/x86/kernel/alternative.c but having it in one place like above would go a long way. Could you please add it to arch/x86/net/bpf_jit_comp.c or arch/x86/include/asm/cfi.h next to enum cfi_mode ? > > I'm not sure doing cfi_bpf_hash check in JITed code is completely solving the problem. > > From bpf_dispatcher_*_func() calling into JITed will work, > > but this emit_prologue() is doing the same job for all bpf progs. > > Some bpf progs call each other directly and indirectly. > > bpf_dispatcher_*_func() -> JITed_BPF_A -> JITed_BPF_B. > > A into B can be a direct call (which cfi doesn't care about) and > > indirect via emit_bpf_tail_call_indirect()->emit_indirect_jump(). > > Should we care about fineibt/kcfi there too? > > The way I understood the tail-call thing to work is that it jumps to > bpf_prog + X86_TAIL_CALL_OFFSET, we already emit an extra ENDBR there to > make this work. > > So the A -> B indirect call is otherwise unadornen and only needs ENDBR. > > Ideally that would use kCFI/FineIBT but since it also skips some of the > setup, this gets to be non-trivial, so I've let this be as is. I see. yeah. The setup is not trivial indeed. Keep as-is is fine. > So the kCFI thing is 'new' but readily inspected by objdump or godbolt: > > https://godbolt.org/z/sGe18z3ca > > (@Sami, that .Ltmp15 thing, I don't see that in the kernel, what > compiler flag makes that go away?) I also noticed this discrepancy. It doesn't seem to be used. Looks weird to spend 8 bytes to store -sizeof(ud2) > As to FineIBT, that has a big comment in arch/x86/kernel/alternative.c > where I rewrite the kCFI thing into FineIBT. I can refer there to avoid > duplicating comments, would that work? Just the above comment somewhere would work. I wouldn't worry about duplication. This is tricky stuff. When gcc folks get around implementing kcfi they will find it useful too.