On Fri, Aug 15, 2025 at 03:52:27AM +0100, chenyuan_fl@xxxxxxx wrote: > From: Yuan Chen <chenyuan@xxxxxxxxxx> > > Adjust symbol matching logic to account for Control-flow Enforcement > Technology (CET) on x86_64 systems. CET prefixes functions with > a 4-byte 'endbr' instruction, shifting the actual hook entry point to > symbol + 4. > > Signed-off-by: Yuan Chen <chenyuan@xxxxxxxxxx> > --- > tools/bpf/bpftool/link.c | 50 ++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 48 insertions(+), 2 deletions(-) > > diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c > index a773e05d5ade..6787971d3167 100644 > --- a/tools/bpf/bpftool/link.c > +++ b/tools/bpf/bpftool/link.c > @@ -282,11 +282,52 @@ get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count) > return data; > } > > +static bool is_x86_ibt_enabled(void) > +{ > +#if defined(__x86_64__) > + struct kernel_config_option options[] = { > + { "CONFIG_X86_KERNEL_IBT", }, > + }; > + char *values[ARRAY_SIZE(options)] = { }; > + bool ret; > + > + if (read_kernel_config(options, ARRAY_SIZE(options), values, NULL)) > + return false; > + > + ret = !!values[0]; > + free(values[0]); > + return ret; > +#else > + return false; > +#endif nit, we could store the result to 'static bool enabled' in this function, so we would not need to pass is_ibt_enabled arg below, and just call is_x86_ibt_enabled directly, but up to you > +} > + > +static bool > +symbol_matches_target(__u64 sym_addr, __u64 target_addr, bool is_ibt_enabled) > +{ > + if (sym_addr == target_addr) > + return true; > + > + /* > + * On x86_64 architectures with CET (Control-flow Enforcement Technology), > + * function entry points have a 4-byte 'endbr' instruction prefix. > + * This causes kprobe hooks to target the address *after* 'endbr' > + * (symbol address + 4), preserving the CET instruction. > + * Here we check if the symbol address matches the hook target address > + * minus 4, indicating a CET-enabled function entry point. > + */ > + if (is_ibt_enabled && sym_addr == target_addr - 4) > + return true; > + > + return false; > +} > + > static void > show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) > { > struct addr_cookie *data; > __u32 i, j = 0; > + bool is_ibt_enabled; > > jsonw_bool_field(json_wtr, "retprobe", > info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN); > @@ -306,8 +347,10 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) > if (!dd.sym_count) > goto error; > > + is_ibt_enabled = is_x86_ibt_enabled(); > for (i = 0; i < dd.sym_count; i++) { > - if (dd.sym_mapping[i].address != data[j].addr) > + if (!symbol_matches_target(dd.sym_mapping[i].address, > + data[j].addr, is_ibt_enabled)) > continue; > jsonw_start_object(json_wtr); > jsonw_uint_field(json_wtr, "addr", dd.sym_mapping[i].address); > @@ -719,6 +762,7 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) > { > struct addr_cookie *data; > __u32 i, j = 0; > + bool is_ibt_enabled; > > if (!info->kprobe_multi.count) > return; > @@ -742,9 +786,11 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) > if (!dd.sym_count) > goto error; > > + is_ibt_enabled = is_x86_ibt_enabled(); > printf("\n\t%-16s %-16s %s", "addr", "cookie", "func [module]"); > for (i = 0; i < dd.sym_count; i++) { > - if (dd.sym_mapping[i].address != data[j].addr) > + if (!symbol_matches_target(dd.sym_mapping[i].address, > + data[j].addr, is_ibt_enabled)) > continue; > printf("\n\t%016lx %-16llx %s", > dd.sym_mapping[i].address, data[j].cookie, dd.sym_mapping[i].name); I wonder should we display the kprobe attached address instead of symbol address in here otherwise the patchset lgtm thanks, jirka