public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
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


  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