From: Timur Chernykh <tim.cherry.co@gmail.com>
To: bpf@vger.kernel.org
Cc: mykyta.yatsenko5@gmail.com, Timur Chernykh <tim.cherry.co@gmail.com>
Subject: [PATCH v2 2/2] libbpf: add kind flag sanitizing
Date: Mon, 7 Apr 2025 22:01:38 +0300 [thread overview]
Message-ID: <20250407190158.351783-3-tim.cherry.co@gmail.com> (raw)
In-Reply-To: <20250407190158.351783-1-tim.cherry.co@gmail.com>
Fix missed check whether kernel supports the kind flag or not.
The fix includes:
- The feature check whether kernel supports the kind flag or not
- Kind flag sanitizing if kernel doesn't support one
- Struct/enum bitfield members sanitizing by generation a proper
replacement for the type of bitfield with corresponding integer
type with same bit size
Signed-off-by: Timur Chernykh <tim.cherry.co@gmail.com>
---
tools/lib/bpf/features.c | 30 +++++++++++++
tools/lib/bpf/libbpf.c | 74 ++++++++++++++++++++++++++++++++-
tools/lib/bpf/libbpf_internal.h | 2 +
3 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c
index 760657f5224c..b40a3fadb68b 100644
--- a/tools/lib/bpf/features.c
+++ b/tools/lib/bpf/features.c
@@ -507,6 +507,33 @@ static int probe_kern_arg_ctx_tag(int token_fd)
return probe_fd(prog_fd);
}
+static int probe_kern_btf_type_kind_flag(int token_fd)
+{
+ static const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l";
+ /* struct bpf_spin_lock {
+ * int val;
+ * };
+ * struct val {
+ * int cnt;
+ * struct bpf_spin_lock l;
+ * };
+ */
+ __u32 types[] = {
+ /* int */
+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
+ /* struct bpf_spin_lock */ /* [2] */
+ BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 1 /* kind bit */, 1), 4),
+ BTF_MEMBER_ENC(15, 1, 0), /* int val; */
+ /* struct val */ /* [3] */
+ BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 1 /* kind bit */, 2), 8),
+ BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
+ BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
+ };
+
+ return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
+ strs, sizeof(strs), token_fd));
+}
+
typedef int (*feature_probe_fn)(int /* token_fd */);
static struct kern_feature_cache feature_cache;
@@ -582,6 +609,9 @@ static struct kern_feature_desc {
[FEAT_BTF_QMARK_DATASEC] = {
"BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
},
+ [FEAT_BTF_TYPE_KIND_FLAG] = {
+ "BTF btf_type can have the kind flags set", probe_kern_btf_type_kind_flag,
+ },
};
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index c2369b6f3260..b1d4530bd9ed 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3113,9 +3113,11 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC);
+ bool has_kind_bit_support = kernel_supports(obj, FEAT_BTF_TYPE_KIND_FLAG);
return !has_func || !has_datasec || !has_func_global || !has_float ||
- !has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec;
+ !has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec ||
+ !has_kind_bit_support;
}
static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
@@ -3128,6 +3130,7 @@ static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC);
+ bool has_kind_bit_support = kernel_supports(obj, FEAT_BTF_TYPE_KIND_FLAG);
char name_gen_buff[32] = {0};
int enum64_placeholder_id = 0;
@@ -3263,6 +3266,75 @@ static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
m->type = enum64_placeholder_id;
m->offset = 0;
}
+ } else if (!has_kind_bit_support &&
+ (btf_is_composite(t) || btf_is_fwd(t) || btf_is_enum(t) || btf_is_enum64(t))) {
+ vlen = btf_vlen(t);
+
+ /* type encoded with a kind flag */
+ if (btf_kflag(t))
+ continue;
+
+ /* unset kind flag anyway */
+ t->info = BTF_INFO_ENC(btf_kind(t), 0, btf_vlen(t));
+
+ /* compisite types has a different bitfield processing if kind flag is set */
+ if (btf_is_composite(t)) {
+ struct btf_member *members = btf_members(t);
+
+ struct btf_type *curr_type = NULL; /* current member type */
+ struct btf_type *new_type = NULL; /* replacement for current member type */
+ int curr_tid = 0;
+ int new_tid = 0;
+ __u32 *new_type_data = NULL;
+ int encoding = 0;
+
+ for (j = 0; j < vlen; j++) {
+ struct btf_member *member = &members[j];
+
+ /* unwrap typedefs, volatiles, etc. */
+ curr_tid = btf__resolve_type(btf, member->type);
+
+ if (curr_tid < 0) {
+ pr_warn("Error resolving type [%d] for member %d of [%d]\n",
+ member->type, j, i);
+ return curr_tid;
+ }
+
+ curr_type = btf_type_by_id(btf, curr_tid);
+
+ /* bitfields can be only int or enum values */
+ if (!(btf_is_int(curr_type) || btf_is_enum(curr_type)))
+ continue;
+
+ encoding = btf_int_encoding(curr_type);
+
+ /* enum value encodes integer signed/unsigned info in the kind flag */
+ if (btf_is_enum(curr_type) && btf_kflag(curr_type))
+ encoding = BTF_INT_SIGNED;
+
+ /* create new integral type with the same info */
+ snprintf(name_gen_buff, sizeof(name_gen_buff), "__int_%d_%d", i, j);
+ new_tid = btf__add_int(btf, name_gen_buff, curr_type->size, encoding);
+
+ if (new_tid < 0) {
+ pr_warn("Error adding integer type for a bitfield %d of [%d]\n", j, i);
+ return new_tid;
+ }
+
+ new_type = btf_type_by_id(btf, new_tid);
+
+ /* encode int in legacy way,
+ * keep offset 0 and specify bit size as set in the member
+ */
+ new_type_data = (__u32 *)(new_type + 1);
+ *new_type_data = BTF_INT_ENC(encoding, 0,
+ BTF_MEMBER_BITFIELD_SIZE(member->offset));
+
+ /* old kernels looks only on offset */
+ member->offset = BTF_MEMBER_BIT_OFFSET(member->offset);
+ member->type = new_tid;
+ }
+ }
}
}
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index 76669c73dcd1..6369c5520fce 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -380,6 +380,8 @@ enum kern_feature_id {
FEAT_ARG_CTX_TAG,
/* Kernel supports '?' at the front of datasec names */
FEAT_BTF_QMARK_DATASEC,
+ /* Kernel supports kind flag */
+ FEAT_BTF_TYPE_KIND_FLAG,
__FEAT_CNT,
};
--
2.49.0
next prev parent reply other threads:[~2025-04-07 19:02 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-07 19:01 Improvements of BTF sanitizing for old kernels Timur Chernykh
2025-04-07 19:01 ` [PATCH v2 1/2] libbpf: add proto_func param name generation Timur Chernykh
2025-04-09 23:51 ` Andrii Nakryiko
2025-04-07 19:01 ` Timur Chernykh [this message]
2025-04-10 0:02 ` [PATCH v2 2/2] libbpf: add kind flag sanitizing Andrii Nakryiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250407190158.351783-3-tim.cherry.co@gmail.com \
--to=tim.cherry.co@gmail.com \
--cc=20250331201016.345704-1-tim.cherry.co@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=mykyta.yatsenko5@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox