[PATCH v4] bpftool: Add CET-aware symbol matching for x86/x86_64 architectures

chenyuan_fl@163.com posted 1 patch 2 months, 2 weeks ago
tools/bpf/bpftool/link.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
[PATCH v4] bpftool: Add CET-aware symbol matching for x86/x86_64 architectures
Posted by chenyuan_fl@163.com 2 months, 2 weeks ago
From: Yuan Chen <chenyuan@kylinos.cn>

Adjust symbol matching logic to account for Control-flow Enforcement
Technology (CET) on x86/x86_64 systems. CET prefixes functions with
a 4-byte 'endbr' instruction, shifting the actual hook entry point to
symbol + 4.

Changed in PATCH v4:
* Refactor repeated code into a function.
* Add detection for the x86 architecture.

Signed-off-by: Yuan Chen <chenyuan@kylinos.cn>
---
 tools/bpf/bpftool/link.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
index a773e05d5ade..717ca8c5ff83 100644
--- a/tools/bpf/bpftool/link.c
+++ b/tools/bpf/bpftool/link.c
@@ -282,6 +282,28 @@ get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count)
 	return data;
 }
 
+static bool
+symbol_matches_target(__u64 sym_addr, __u64 target_addr)
+{
+	if (sym_addr == target_addr)
+		return true;
+
+#if defined(__i386__) || defined(__x86_64__)
+	/*
+	 * On x86 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 (sym_addr == target_addr - 4)
+		return true;
+#endif
+
+	return false;
+}
+
 static void
 show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
 {
@@ -307,7 +329,7 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
 		goto error;
 
 	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))
 			continue;
 		jsonw_start_object(json_wtr);
 		jsonw_uint_field(json_wtr, "addr", dd.sym_mapping[i].address);
@@ -744,7 +766,7 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
 
 	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))
 			continue;
 		printf("\n\t%016lx %-16llx %s",
 		       dd.sym_mapping[i].address, data[j].cookie, dd.sym_mapping[i].name);
-- 
2.25.1
Re: [PATCH v4] bpftool: Add CET-aware symbol matching for x86/x86_64 architectures
Posted by Quentin Monnet 2 months, 2 weeks ago
2025-07-22 10:00 UTC+0800 ~ chenyuan_fl@163.com
> From: Yuan Chen <chenyuan@kylinos.cn>
> 
> Adjust symbol matching logic to account for Control-flow Enforcement
> Technology (CET) on x86/x86_64 systems. CET prefixes functions with
> a 4-byte 'endbr' instruction, shifting the actual hook entry point to
> symbol + 4.
> 
> Changed in PATCH v4:
> * Refactor repeated code into a function.
> * Add detection for the x86 architecture.
> 
> Signed-off-by: Yuan Chen <chenyuan@kylinos.cn>
> ---
>  tools/bpf/bpftool/link.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
> index a773e05d5ade..717ca8c5ff83 100644
> --- a/tools/bpf/bpftool/link.c
> +++ b/tools/bpf/bpftool/link.c
> @@ -282,6 +282,28 @@ get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count)
>  	return data;
>  }
>  
> +static bool
> +symbol_matches_target(__u64 sym_addr, __u64 target_addr)
> +{
> +	if (sym_addr == target_addr)
> +		return true;
> +
> +#if defined(__i386__) || defined(__x86_64__)


Do you really need it for __i386__ as well? My understanding was that
CET would apply only to 64-bit?

Thanks,
Quentin
Re:Re: [PATCH v4] bpftool: Add CET-aware symbol matching for x86/x86_64 architectures
Posted by chenyuan 2 months, 2 weeks ago
You are absolutely right. My initial assumption was incorrect - while endbr32 can technically be
compiled for i386, I've verified in the kernel configuration that X86_KERNEL_IBT explicitly
depends on X86_64:

.config - Linux/i386 6.16.0-rc3 Kernel Configuration
> Search (X86_KERNEL_IBT) > Processor type and features > Search (X86_KERNEL_IBT)
Symbol: X86_KERNEL_IBT [=n]
Type  : bool
Defined at arch/x86/Kconfig:1771
Prompt: Indirect Branch Tracking
Depends on: X86_64 [=n] && CC_HAS_IBT [=y] && HAVE_OBJTOOL [=n] && (!LD_IS_LLD [=n] || LLD_VERSION [=0]>=140000)

This confirms CET is indeed 64-bit exclusive in the current implementation. I'll revise the patch
immediately to remove i386 support.

Thanks for catching this!
Best regards,
Yuan Chen



At 2025-07-22 22:23:23, "Quentin Monnet" <qmo@kernel.org> wrote:
>2025-07-22 10:00 UTC+0800 ~ chenyuan_fl@163.com
>> From: Yuan Chen <chenyuan@kylinos.cn>
>> 
>> Adjust symbol matching logic to account for Control-flow Enforcement
>> Technology (CET) on x86/x86_64 systems. CET prefixes functions with
>> a 4-byte 'endbr' instruction, shifting the actual hook entry point to
>> symbol + 4.
>> 
>> Changed in PATCH v4:
>> * Refactor repeated code into a function.
>> * Add detection for the x86 architecture.
>> 
>> Signed-off-by: Yuan Chen <chenyuan@kylinos.cn>
>> ---
>>  tools/bpf/bpftool/link.c | 26 ++++++++++++++++++++++++--
>>  1 file changed, 24 insertions(+), 2 deletions(-)
>> 
>> diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
>> index a773e05d5ade..717ca8c5ff83 100644
>> --- a/tools/bpf/bpftool/link.c
>> +++ b/tools/bpf/bpftool/link.c
>> @@ -282,6 +282,28 @@ get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count)
>>  	return data;
>>  }
>>  
>> +static bool
>> +symbol_matches_target(__u64 sym_addr, __u64 target_addr)
>> +{
>> +	if (sym_addr == target_addr)
>> +		return true;
>> +
>> +#if defined(__i386__) || defined(__x86_64__)
>
>
>Do you really need it for __i386__ as well? My understanding was that
>CET would apply only to 64-bit?
>
>Thanks,
>Quentin