@@ -282,11 +282,52 @@ get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count)
282282 return data ;
283283}
284284
285+ static bool is_x86_ibt_enabled (void )
286+ {
287+ #if defined(__x86_64__ )
288+ struct kernel_config_option options [] = {
289+ { "CONFIG_X86_KERNEL_IBT" , },
290+ };
291+ char * values [ARRAY_SIZE (options )] = { };
292+ bool ret ;
293+
294+ if (read_kernel_config (options , ARRAY_SIZE (options ), values , NULL ))
295+ return false;
296+
297+ ret = !!values [0 ];
298+ free (values [0 ]);
299+ return ret ;
300+ #else
301+ return false;
302+ #endif
303+ }
304+
305+ static bool
306+ symbol_matches_target (__u64 sym_addr , __u64 target_addr , bool is_ibt_enabled )
307+ {
308+ if (sym_addr == target_addr )
309+ return true;
310+
311+ /*
312+ * On x86_64 architectures with CET (Control-flow Enforcement Technology),
313+ * function entry points have a 4-byte 'endbr' instruction prefix.
314+ * This causes kprobe hooks to target the address *after* 'endbr'
315+ * (symbol address + 4), preserving the CET instruction.
316+ * Here we check if the symbol address matches the hook target address
317+ * minus 4, indicating a CET-enabled function entry point.
318+ */
319+ if (is_ibt_enabled && sym_addr == target_addr - 4 )
320+ return true;
321+
322+ return false;
323+ }
324+
285325static void
286326show_kprobe_multi_json (struct bpf_link_info * info , json_writer_t * wtr )
287327{
288328 struct addr_cookie * data ;
289329 __u32 i , j = 0 ;
330+ bool is_ibt_enabled ;
290331
291332 jsonw_bool_field (json_wtr , "retprobe" ,
292333 info -> kprobe_multi .flags & BPF_F_KPROBE_MULTI_RETURN );
@@ -306,11 +347,13 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
306347 if (!dd .sym_count )
307348 goto error ;
308349
350+ is_ibt_enabled = is_x86_ibt_enabled ();
309351 for (i = 0 ; i < dd .sym_count ; i ++ ) {
310- if (dd .sym_mapping [i ].address != data [j ].addr )
352+ if (!symbol_matches_target (dd .sym_mapping [i ].address ,
353+ data [j ].addr , is_ibt_enabled ))
311354 continue ;
312355 jsonw_start_object (json_wtr );
313- jsonw_uint_field (json_wtr , "addr" , dd . sym_mapping [ i ]. address );
356+ jsonw_uint_field (json_wtr , "addr" , ( unsigned long ) data [ j ]. addr );
314357 jsonw_string_field (json_wtr , "func" , dd .sym_mapping [i ].name );
315358 /* Print null if it is vmlinux */
316359 if (dd .sym_mapping [i ].module [0 ] == '\0' ) {
@@ -719,6 +762,7 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
719762{
720763 struct addr_cookie * data ;
721764 __u32 i , j = 0 ;
765+ bool is_ibt_enabled ;
722766
723767 if (!info -> kprobe_multi .count )
724768 return ;
@@ -742,12 +786,14 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
742786 if (!dd .sym_count )
743787 goto error ;
744788
789+ is_ibt_enabled = is_x86_ibt_enabled ();
745790 printf ("\n\t%-16s %-16s %s" , "addr" , "cookie" , "func [module]" );
746791 for (i = 0 ; i < dd .sym_count ; i ++ ) {
747- if (dd .sym_mapping [i ].address != data [j ].addr )
792+ if (!symbol_matches_target (dd .sym_mapping [i ].address ,
793+ data [j ].addr , is_ibt_enabled ))
748794 continue ;
749795 printf ("\n\t%016lx %-16llx %s" ,
750- dd . sym_mapping [ i ]. address , data [j ].cookie , dd .sym_mapping [i ].name );
796+ ( unsigned long ) data [ j ]. addr , data [j ].cookie , dd .sym_mapping [i ].name );
751797 if (dd .sym_mapping [i ].module [0 ] != '\0' )
752798 printf (" [%s] " , dd .sym_mapping [i ].module );
753799 else
0 commit comments