RE: How do I force an IBT trap in a demo kernel module?

From: Preble, Adam C
Date: Wed May 31 2023 - 19:02:29 EST


It looked to me like I was getting the indirect jump just fine with what I already was doing. Sure, I made the instruction pointer volatile and static, but nothing changed just from that.

The make command ultimately invoked is:
make -C /lib/modules/6.4.0.headers/build M=/root/module KCFLAGS="-mforce-indirect-call -O0" modules

(I'm now messing around with the 6.4.0 kernel; it was 6.3.0 before)

objtool will then puke:
/root/module/ibt_test.o: warning: objtool: init_ibt_test_module+0x11: relocation to !ENDBR: indirect_jump_to_me+0x0

I think that between those KCFLAGS and my function prototype that I was able to mark the function to not have an endbr64 landing pad:
__attribute__((nocf_check))
static void indirect_jump_to_me(void)

However, I am assuming that objtool is rejecting the alteration:
/root/ibt_experiments/module/ibt_test.o: warning: objtool: indirect_jmp_ptr.0+0x0: data relocation to !ENDBR: indirect_jump_to_me+0x0
MODPOST /root/ibt_experiments/module/Module.symvers
ERROR: modpost: "__x86_indirect_thunk_nt_rax" [/root/ibt_experiments/module/ibt_test.ko] undefined!

I wondered if I could circumvent this check too without, say, just resorting to coding it in assembler.

If there's one thing I'm learning so far, it's how hard it is to actually force IBT to trigger. This makes the trap I'm hitting in this legacy code with IBT on particularly galling.

-----Original Message-----
From: Pavel Machek <pavel@xxxxxx>
Sent: Saturday, May 27, 2023 5:41 PM
To: David Laight <David.Laight@xxxxxxxxxx>
Cc: Preble, Adam C <adam.c.preble@xxxxxxxxx>; linux-kernel@xxxxxxxxxxxxxxx
Subject: Re: How do I force an IBT trap in a demo kernel module?

On Wed 2023-05-24 08:00:36, David Laight wrote:
> From: Preble, Adam C
> > Sent: 23 May 2023 20:29
> >
> > I am debugging why a kernel module of ours triggers the IBT
> > (Indirect Branch Tracking) trap, and while doing that, I was trying
> > to write a standalone demo that would forcefully trigger it on
> > purpose. This has turned out to be much more difficult than I thought! What can I do to get a module to generate an indirect branch without an endbr64? Creating the indirect branch itself doesn't appear to be hard:
> >
> > 1. Set up a function call
> > 2. Assign it to a function pointer
> > 3. Call the function pointer
> > 4. ...maybe add a compiler flag so it doesn't optimize the call to a direct branch.
> >
> > I am primarily building in a Debian environment with gcc (Debian
> > 10.2.1-6) 10.2.1 20210110. By default, the branch does get optimized
> > away. I had to set the -mforce-indirect-call flag. The endbr64 instruction would still emit so I added a function attribute to suppress it:
> ...
> > So what do I have to do to tell objtool to allow to me deliberately shoot myself in the foot here?
>
> You could try adjusting the function pointer by the size of the endbr64 instrauction.
>
> Oh, put the function pointer variable into static data.
> That should stop it all being optimised away.

volatile will help, too.

Or simply write the code in assembly.
Pavel

--