Re: [RFC PATCH 2/4] trace: Allow kprobes to override livepatched functions

Yafang Shao
2026-04-02T13:21:33Z

On Thu, Apr 2, 2026 at 8:48 PM Menglong Dong <menglong.dong@linux.dev> wrote:
>
> On 2026/4/2 17:26, Yafang Shao wrote:
> > Introduce the ability for kprobes to override the return values of
> > functions that have been livepatched. This functionality is guarded by the
> > CONFIG_KPROBE_OVERRIDE_KLP_FUNC configuration option.
>
> Hi, Yafang. This is a interesting idea.
>
> For now, the bpf_override_return() can only be used on the kernel
> functions that allow error injection to prevent the BPF program from
> crash the kernel. If we use it on the kernel functions that patched
> by the KLP, we can crash the kernel easily by return a invalid value
> with bpf_override_return(), right? (Of course, we can crash the kernel
> easily with KLP too ;)

Right.
Livepatch already grants the power to modify the kernel at will;
allowing BPF to override a patched function simply adds a layer of
runtime programmability to an existing modification.

>
> I haven't figure out the use case yet. Can KLP be used together with
> the BPF program that use bpf_override_return()?

The two mechanisms do not target the same entry point: whileKLP
modifies the original kernel function, bpf_override_return() is
applied to the newly patched function provided by the KLP module.

> The KLP will modify
> the RIP on the stack, and the bpf_override_return() will modify it too.
> AFAIK, there can't be two ftrace_ops that both have the
> FTRACE_OPS_FL_IPMODIFY flag. Did I miss something?

Correct, but as noted, they target different functions

>
> It will be helpful for me to understand the use case if a selftests is
> offered :)

Here is a recent use case from our production environment.

- The livepatch

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e378bbe5705f..047e937bfa6d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -5175,12 +5175,22 @@ int bond_update_slave_arr(struct bonding
*bond, struct slave *skipslave)
return ret;
}

+/* noclone to avoid bond_get_slave_hook.constprop.0 */
+__attribute__((__noclone__, __noinline__))
+int bond_get_slave_hook(struct sk_buff *skb, u32 hash, unsigned int count)
+{
+ return -1;
+}

static struct slave *bond_xmit_3ad_xor_slave_get(struct bonding *bond,
struct sk_buff *skb,
struct bond_up_slave *slaves)
{
struct slave *slave;
unsigned int count;
+ int slave_idx;
u32 hash;

hash = bond_xmit_hash(bond, skb);
@@ -5188,6 +5198,13 @@ static struct slave
*bond_xmit_3ad_xor_slave_get(struct bonding *bond,
if (unlikely(!count))
return NULL;

+ /* Try BPF hook first - returns slave index directly */
+ slave_idx = bond_get_slave_hook(skb, hash, count);
+ /* If BPF hook returned valid slave index, use it */
+ if (slave_idx >= 0 && slave_idx < count) {
+ slave = slaves->arr[slave_idx];
+ return slave;
+ }
slave = slaves->arr[hash % count];
return slave;
}

- The BPF program

SEC("kprobe/bond_get_slave_hook")
int BPF_KPROBE(slave_selector, struct sk_buff *skb, u32 hash, u32 count)
{
unsigned short net_hdr_off;
unsigned char *head;
struct iphdr iph;
int *slave_idx;
__u32 daddr;

__u16 proto = BPF_CORE_READ(skb, protocol);
if (proto != bpf_htons(0x0800))
return 0;

head = BPF_CORE_READ(skb, head);
net_hdr_off = BPF_CORE_READ(skb, network_header);

if (bpf_probe_read_kernel(&iph, sizeof(iph), head + net_hdr_off) != 0)
return 0;

daddr = iph.daddr;
slave_idx = bpf_map_lookup_elem(&ip_slave_map, &daddr);
if (slave_idx) {
int idx = *slave_idx;

if (idx >= 0 && idx < (int)count)
bpf_override_return(ctx, idx);
}
return 0;
}

>
> BTW, if we allow the usage of bpf_override_return() on the KLP patched
> function, we should allow the usage of BPF_MODIFY_RETURN on this
> case too, right?

It's a possibility, but I haven't tested that specifically yet.

--
Regards
Yafang