summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-10-02 12:47:04 +0000
committerKumar Kartikeya Dwivedi <memxor@gmail.com>2026-10-03 16:08:17 +0200
commitbed1986a1932942e9db17fbdb2a19d0c4160a1f5 (patch)
tree0a53b5efad4ba264aa687a41b0edb2b912a35559
parentb233f937b98f8e5c88e2978ef36321f888076274 (diff)
bpf: Allow names of Rust types and functions in BTF
Names of types and functions in BTF that LLVM makes for a Rust program are not C identifiers: [69] STRUCT 'NonNull<str>' size=16 vlen=1 [147] FUNC 'write_fmt<scx_cosmos::BpfStream>' type_id=146 and the kernel rejects such BTF with "Invalid name". scx_simple and scx_cosmos schedulers written in Rust have them in STRUCT, FWD and FUNC, made of letters, digits and " #&()*,:;<>[]{}", 430 characters at most. Allow any printable character in btf_name_valid_identifier(), like it's done for DATASEC. It checks names of types, functions, members, enumerators, variables and arguments, so all of them can have such characters now. The limit of KSYM_NAME_LEN stays. The name of FUNC is a part of the name of the program in kallsyms, where a space would break the parsers. Replace what is not a character of an identifier with '_' there. Tests in prog_tests/btf.c expect "Invalid name" for names with '!' and '*', which are valid now. Put a character that is not printable there. The type name '?foo' is expected to load. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20261002124714.180012-6-alexei.starovoitov@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
-rw-r--r--kernel/bpf/btf.c15
-rw-r--r--kernel/bpf/core.c5
-rw-r--r--tools/testing/selftests/bpf/prog_tests/btf.c52
3 files changed, 33 insertions, 39 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 8cc17a1cd25c..d27af5d8e495 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -901,16 +901,6 @@ static bool btf_name_offset_valid(const struct btf *btf, u32 offset)
return offset < btf->hdr.str_len;
}
-static bool __btf_name_char_ok(char c, bool first)
-{
- if ((first ? !isalpha(c) :
- !isalnum(c)) &&
- c != '_' &&
- c != '.')
- return false;
- return true;
-}
-
const char *btf_str_by_offset(const struct btf *btf, u32 offset)
{
while (offset < btf->start_str_off)
@@ -923,20 +913,21 @@ const char *btf_str_by_offset(const struct btf *btf, u32 offset)
return NULL;
}
+/* Names in BTF of Rust are not C identifiers. Allow any printable character */
static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
{
/* offset must be valid */
const char *src = btf_str_by_offset(btf, offset);
const char *src_limit;
- if (!__btf_name_char_ok(*src, true))
+ if (!isprint(*src))
return false;
/* set a limit on identifier length */
src_limit = src + KSYM_NAME_LEN;
src++;
while (*src && src < src_limit) {
- if (!__btf_name_char_ok(*src, false))
+ if (!isprint(*src))
return false;
src++;
}
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 92a87c73aa44..05c89396119a 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -18,6 +18,7 @@
*/
#include <uapi/linux/btf.h>
+#include <linux/ctype.h>
#include <linux/filter.h>
#include <linux/sched/signal.h>
#include <linux/skbuff.h>
@@ -589,6 +590,10 @@ bpf_prog_ksym_set_name(struct bpf_prog *prog)
prog->aux->func_info[prog->aux->func_idx].type_id);
func_name = btf_name_by_offset(prog->aux->btf, type->name_off);
snprintf(sym, (size_t)(end - sym), "_%s", func_name);
+ /* the name of a function of Rust is not an identifier */
+ for (; *sym; sym++)
+ if (!isalnum(*sym) && *sym != '_' && *sym != '.')
+ *sym = '_';
return;
}
diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index df6ad38d287d..87b554067071 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -1987,14 +1987,14 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "typedef (invalid name, invalid identifier)",
+ .descr = "typedef (invalid name, not printable)",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPEDEF_ENC(NAME_TBD, 1), /* [2] */
BTF_END_RAW,
},
- .str_sec = "\0__!int",
- .str_sec_size = sizeof("\0__!int"),
+ .str_sec = "\0__\7int",
+ .str_sec_size = sizeof("\0__\7int"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "typedef_check_btf",
.key_size = sizeof(int),
@@ -2112,15 +2112,15 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "fwd type (invalid name, invalid identifier)",
+ .descr = "fwd type (invalid name, not printable)",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(NAME_TBD,
BTF_INFO_ENC(BTF_KIND_FWD, 0, 0), 0), /* [2] */
BTF_END_RAW,
},
- .str_sec = "\0__!skb",
- .str_sec_size = sizeof("\0__!skb"),
+ .str_sec = "\0__\7skb",
+ .str_sec_size = sizeof("\0__\7skb"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "fwd_type_check_btf",
.key_size = sizeof(int),
@@ -2175,7 +2175,7 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "struct type (invalid name, invalid identifier)",
+ .descr = "struct type (invalid name, not printable)",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(NAME_TBD,
@@ -2183,8 +2183,8 @@ static struct btf_raw_test raw_tests[] = {
BTF_MEMBER_ENC(NAME_TBD, 1, 0),
BTF_END_RAW,
},
- .str_sec = "\0A!\0B",
- .str_sec_size = sizeof("\0A!\0B"),
+ .str_sec = "\0A\7\0B",
+ .str_sec_size = sizeof("\0A\7\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
@@ -2217,7 +2217,7 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "struct member (invalid name, invalid identifier)",
+ .descr = "struct member (invalid name, not printable)",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(NAME_TBD,
@@ -2225,8 +2225,8 @@ static struct btf_raw_test raw_tests[] = {
BTF_MEMBER_ENC(NAME_TBD, 1, 0),
BTF_END_RAW,
},
- .str_sec = "\0A\0B*",
- .str_sec_size = sizeof("\0A\0B*"),
+ .str_sec = "\0A\0B\7",
+ .str_sec_size = sizeof("\0A\0B\7"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
@@ -2260,7 +2260,7 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "enum type (invalid name, invalid identifier)",
+ .descr = "enum type (invalid name, not printable)",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(NAME_TBD,
@@ -2269,8 +2269,8 @@ static struct btf_raw_test raw_tests[] = {
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_END_RAW,
},
- .str_sec = "\0A!\0B",
- .str_sec_size = sizeof("\0A!\0B"),
+ .str_sec = "\0A\7\0B",
+ .str_sec_size = sizeof("\0A\7\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "enum_type_check_btf",
.key_size = sizeof(int),
@@ -2306,7 +2306,7 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "enum member (invalid name, invalid identifier)",
+ .descr = "enum member (invalid name, not printable)",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0,
@@ -2315,8 +2315,8 @@ static struct btf_raw_test raw_tests[] = {
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_END_RAW,
},
- .str_sec = "\0A!",
- .str_sec_size = sizeof("\0A!"),
+ .str_sec = "\0A\7",
+ .str_sec_size = sizeof("\0A\7"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "enum_type_check_btf",
.key_size = sizeof(int),
@@ -2625,14 +2625,14 @@ static struct btf_raw_test raw_tests[] = {
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */
- /* void (*)(int a, unsigned int !!!) */
+ /* void (*)(int a, unsigned int \7) */
BTF_FUNC_PROTO_ENC(0, 2), /* [3] */
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
BTF_END_RAW,
},
- .str_sec = "\0a\0!!!",
- .str_sec_size = sizeof("\0a\0!!!"),
+ .str_sec = "\0a\0\7",
+ .str_sec_size = sizeof("\0a\0\7"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "func_proto_type_check_btf",
.key_size = sizeof(int),
@@ -2775,12 +2775,12 @@ static struct btf_raw_test raw_tests[] = {
BTF_FUNC_PROTO_ENC(0, 2), /* [3] */
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
- /* void !!!(int a, unsigned int b) */
+ /* void \7(int a, unsigned int b) */
BTF_FUNC_ENC(NAME_TBD, 3), /* [4] */
BTF_END_RAW,
},
- .str_sec = "\0a\0b\0!!!",
- .str_sec_size = sizeof("\0a\0b\0!!!"),
+ .str_sec = "\0a\0b\0\7",
+ .str_sec_size = sizeof("\0a\0b\0\7"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "func_type_check_btf",
.key_size = sizeof(int),
@@ -3585,15 +3585,13 @@ static struct btf_raw_test raw_tests[] = {
.btf_load_err = true,
},
{
- .descr = "type name '?foo' is not ok",
+ .descr = "type name '?foo' is ok",
.raw_types = {
/* union ?foo; */
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_FWD, 1, 0), 0), /* [1] */
BTF_END_RAW,
},
BTF_STR_SEC("\0?foo"),
- .err_str = "Invalid name",
- .btf_load_err = true,
},
{