Skip to content

Commit 693bfba

Browse files
Donglin PengKernel Patches Daemon
authored andcommitted
btf: Add sorting validation for binary search
Implement validation of BTF type ordering to enable efficient binary search for sorted BTF. Cc: Eduard Zingerman <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Alan Maguire <[email protected]> Cc: Song Liu <[email protected]> Cc: Xiaoqin Zhang <[email protected]> Signed-off-by: Donglin Peng <[email protected]>
1 parent bb782ae commit 693bfba

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

kernel/bpf/btf.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,66 @@ u32 btf_nr_types(const struct btf *btf)
550550
return total;
551551
}
552552

553+
/* Anonymous types (with empty names) are considered greater than named types
554+
* and are sorted after them. Two anonymous types are considered equal. Named
555+
* types are compared lexicographically.
556+
*/
557+
static int btf_compare_type_names(const void *a, const void *b, void *priv)
558+
{
559+
struct btf *btf = (struct btf *)priv;
560+
const struct btf_type *ta = btf_type_by_id(btf, *(__u32 *)a);
561+
const struct btf_type *tb = btf_type_by_id(btf, *(__u32 *)b);
562+
const char *na, *nb;
563+
564+
if (!ta->name_off && tb->name_off)
565+
return 1;
566+
if (ta->name_off && !tb->name_off)
567+
return -1;
568+
if (!ta->name_off && !tb->name_off)
569+
return 0;
570+
571+
na = btf_name_by_offset(btf, ta->name_off);
572+
nb = btf_name_by_offset(btf, tb->name_off);
573+
return strcmp(na, nb);
574+
}
575+
576+
/* Verifies that BTF types are sorted in ascending order according to their
577+
* names, with named types appearing before anonymous types. If the ordering
578+
* is correct, counts the number of named types and updates the BTF object's
579+
* nr_sorted_types field. Note that vmlinux and kernel module BTFs are sorted
580+
* during the building phase, so the validation logic only needs to count the
581+
* named types.
582+
*/
583+
static void btf_check_sorted(struct btf *btf)
584+
{
585+
const struct btf_type *t;
586+
int i, n, k = 0, nr_sorted_types;
587+
bool skip_cmp = btf_is_kernel(btf);
588+
589+
if (btf->nr_types < 2)
590+
return;
591+
592+
nr_sorted_types = 0;
593+
n = btf_nr_types(btf) - 1;
594+
for (i = btf_start_id(btf); i < n; i++) {
595+
k = i + 1;
596+
if (!skip_cmp && btf_compare_type_names(&i, &k, btf) > 0)
597+
return;
598+
599+
t = btf_type_by_id(btf, i);
600+
if (t->name_off)
601+
nr_sorted_types++;
602+
else if (skip_cmp)
603+
break;
604+
}
605+
606+
t = btf_type_by_id(btf, k);
607+
if (t->name_off)
608+
nr_sorted_types++;
609+
if (nr_sorted_types)
610+
btf->nr_sorted_types = nr_sorted_types;
611+
}
612+
553613
static s32 btf_find_by_name_kind_bsearch(const struct btf *btf, const char *name,
554614
s32 start_id, s32 end_id)
555615
{
@@ -5885,6 +5945,8 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
58855945
if (err)
58865946
goto errout;
58875947

5948+
btf_check_sorted(btf);
5949+
58885950
struct_meta_tab = btf_parse_struct_metas(&env->log, btf);
58895951
if (IS_ERR(struct_meta_tab)) {
58905952
err = PTR_ERR(struct_meta_tab);
@@ -6292,6 +6354,7 @@ static struct btf *btf_parse_base(struct btf_verifier_env *env, const char *name
62926354
if (err)
62936355
goto errout;
62946356

6357+
btf_check_sorted(btf);
62956358
refcount_set(&btf->refcnt, 1);
62966359

62976360
return btf;
@@ -6426,6 +6489,7 @@ static struct btf *btf_parse_module(const char *module_name, const void *data,
64266489
}
64276490

64286491
btf_verifier_env_free(env);
6492+
btf_check_sorted(btf);
64296493
refcount_set(&btf->refcnt, 1);
64306494
return btf;
64316495

0 commit comments

Comments
 (0)