Skip to content

Commit 4c24483

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf: add support for new btf kind BTF_KIND_TAG'
Yonghong Song says: ==================== LLVM14 added support for a new C attribute ([1]) __attribute__((btf_tag("arbitrary_str"))) This attribute will be emitted to dwarf ([2]) and pahole will convert it to BTF. Or for bpf target, this attribute will be emitted to BTF directly ([3], [4]). The attribute is intended to provide additional information for - struct/union type or struct/union member - static/global variables - static/global function or function parameter. This new attribute can be used to add attributes to kernel codes, e.g., pre- or post- conditions, allow/deny info, or any other info in which only the kernel is interested. Such attributes will be processed by clang frontend and emitted to dwarf, converting to BTF by pahole. Ultimiately the verifier can use these information for verification purpose. The new attribute can also be used for bpf programs, e.g., tagging with __user attributes for function parameters, specifying global function preconditions, etc. Such information may help verifier to detect user program bugs. After this series, pahole dwarf->btf converter will be enhanced to support new llvm tag for btf_tag attribute. With pahole support, we will then try to add a few real use case, e.g., __user/__rcu tagging, allow/deny list, some kernel function precondition, etc, in the kernel. In the rest of the series, Patches 1-2 had kernel support. Patches 3-4 added libbpf support. Patch 5 added bpftool support. Patches 6-10 added various selftests. Patch 11 added documentation for the new kind. [1] https://reviews.llvm.org/D106614 [2] https://reviews.llvm.org/D106621 [3] https://reviews.llvm.org/D106622 [4] https://reviews.llvm.org/D109560 Changelog: v2 -> v3: - put NR_BTF_KINDS and BTF_KIND_MAX into enum as well - check component_idx earlier (check_meta stage) in kernel - add more tests - fix misc nits v1 -> v2: - BTF ELF format changed in llvm ([4] above), so cross-board change to use the new format. - Clarified in commit message that BTF_KIND_TAG is not emitted by bpftool btf dump format c. - Fix various comments from Andrii. ==================== Acked-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2 parents 8987ede + 48f5a6c commit 4c24483

File tree

17 files changed

+869
-72
lines changed

17 files changed

+869
-72
lines changed

Documentation/bpf/btf.rst

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ sequentially and type id is assigned to each recognized type starting from id
8585
#define BTF_KIND_VAR 14 /* Variable */
8686
#define BTF_KIND_DATASEC 15 /* Section */
8787
#define BTF_KIND_FLOAT 16 /* Floating point */
88+
#define BTF_KIND_TAG 17 /* Tag */
8889

8990
Note that the type section encodes debug info, not just pure types.
9091
``BTF_KIND_FUNC`` is not a type, and it represents a defined subprogram.
@@ -106,7 +107,7 @@ Each type contains the following common data::
106107
* "size" tells the size of the type it is describing.
107108
*
108109
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
109-
* FUNC and FUNC_PROTO.
110+
* FUNC, FUNC_PROTO and TAG.
110111
* "type" is a type_id referring to another type.
111112
*/
112113
union {
@@ -465,6 +466,32 @@ map definition.
465466

466467
No additional type data follow ``btf_type``.
467468

469+
2.2.17 BTF_KIND_TAG
470+
~~~~~~~~~~~~~~~~~~~
471+
472+
``struct btf_type`` encoding requirement:
473+
* ``name_off``: offset to a non-empty string
474+
* ``info.kind_flag``: 0
475+
* ``info.kind``: BTF_KIND_TAG
476+
* ``info.vlen``: 0
477+
* ``type``: ``struct``, ``union``, ``func`` or ``var``
478+
479+
``btf_type`` is followed by ``struct btf_tag``.::
480+
481+
struct btf_tag {
482+
__u32 component_idx;
483+
};
484+
485+
The ``name_off`` encodes btf_tag attribute string.
486+
The ``type`` should be ``struct``, ``union``, ``func`` or ``var``.
487+
For ``var`` type, ``btf_tag.component_idx`` must be ``-1``.
488+
For the other three types, if the btf_tag attribute is
489+
applied to the ``struct``, ``union`` or ``func`` itself,
490+
``btf_tag.component_idx`` must be ``-1``. Otherwise,
491+
the attribute is applied to a ``struct``/``union`` member or
492+
a ``func`` argument, and ``btf_tag.component_idx`` should be a
493+
valid index (starting from 0) pointing to a member or an argument.
494+
468495
3. BTF Kernel API
469496
*****************
470497

include/uapi/linux/btf.h

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ struct btf_type {
4343
* "size" tells the size of the type it is describing.
4444
*
4545
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
46-
* FUNC, FUNC_PROTO and VAR.
46+
* FUNC, FUNC_PROTO, VAR and TAG.
4747
* "type" is a type_id referring to another type.
4848
*/
4949
union {
@@ -56,25 +56,29 @@ struct btf_type {
5656
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
5757
#define BTF_INFO_KFLAG(info) ((info) >> 31)
5858

59-
#define BTF_KIND_UNKN 0 /* Unknown */
60-
#define BTF_KIND_INT 1 /* Integer */
61-
#define BTF_KIND_PTR 2 /* Pointer */
62-
#define BTF_KIND_ARRAY 3 /* Array */
63-
#define BTF_KIND_STRUCT 4 /* Struct */
64-
#define BTF_KIND_UNION 5 /* Union */
65-
#define BTF_KIND_ENUM 6 /* Enumeration */
66-
#define BTF_KIND_FWD 7 /* Forward */
67-
#define BTF_KIND_TYPEDEF 8 /* Typedef */
68-
#define BTF_KIND_VOLATILE 9 /* Volatile */
69-
#define BTF_KIND_CONST 10 /* Const */
70-
#define BTF_KIND_RESTRICT 11 /* Restrict */
71-
#define BTF_KIND_FUNC 12 /* Function */
72-
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
73-
#define BTF_KIND_VAR 14 /* Variable */
74-
#define BTF_KIND_DATASEC 15 /* Section */
75-
#define BTF_KIND_FLOAT 16 /* Floating point */
76-
#define BTF_KIND_MAX BTF_KIND_FLOAT
77-
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
59+
enum {
60+
BTF_KIND_UNKN = 0, /* Unknown */
61+
BTF_KIND_INT = 1, /* Integer */
62+
BTF_KIND_PTR = 2, /* Pointer */
63+
BTF_KIND_ARRAY = 3, /* Array */
64+
BTF_KIND_STRUCT = 4, /* Struct */
65+
BTF_KIND_UNION = 5, /* Union */
66+
BTF_KIND_ENUM = 6, /* Enumeration */
67+
BTF_KIND_FWD = 7, /* Forward */
68+
BTF_KIND_TYPEDEF = 8, /* Typedef */
69+
BTF_KIND_VOLATILE = 9, /* Volatile */
70+
BTF_KIND_CONST = 10, /* Const */
71+
BTF_KIND_RESTRICT = 11, /* Restrict */
72+
BTF_KIND_FUNC = 12, /* Function */
73+
BTF_KIND_FUNC_PROTO = 13, /* Function Proto */
74+
BTF_KIND_VAR = 14, /* Variable */
75+
BTF_KIND_DATASEC = 15, /* Section */
76+
BTF_KIND_FLOAT = 16, /* Floating point */
77+
BTF_KIND_TAG = 17, /* Tag */
78+
79+
NR_BTF_KINDS,
80+
BTF_KIND_MAX = NR_BTF_KINDS - 1,
81+
};
7882

7983
/* For some specific BTF_KIND, "struct btf_type" is immediately
8084
* followed by extra data.
@@ -170,4 +174,15 @@ struct btf_var_secinfo {
170174
__u32 size;
171175
};
172176

177+
/* BTF_KIND_TAG is followed by a single "struct btf_tag" to describe
178+
* additional information related to the tag applied location.
179+
* If component_idx == -1, the tag is applied to a struct, union,
180+
* variable or function. Otherwise, it is applied to a struct/union
181+
* member or a func argument, and component_idx indicates which member
182+
* or argument (0 ... vlen-1).
183+
*/
184+
struct btf_tag {
185+
__s32 component_idx;
186+
};
187+
173188
#endif /* _UAPI__LINUX_BTF_H__ */

kernel/bpf/btf.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
281281
[BTF_KIND_VAR] = "VAR",
282282
[BTF_KIND_DATASEC] = "DATASEC",
283283
[BTF_KIND_FLOAT] = "FLOAT",
284+
[BTF_KIND_TAG] = "TAG",
284285
};
285286

286287
const char *btf_type_str(const struct btf_type *t)
@@ -459,6 +460,17 @@ static bool btf_type_is_datasec(const struct btf_type *t)
459460
return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;
460461
}
461462

463+
static bool btf_type_is_tag(const struct btf_type *t)
464+
{
465+
return BTF_INFO_KIND(t->info) == BTF_KIND_TAG;
466+
}
467+
468+
static bool btf_type_is_tag_target(const struct btf_type *t)
469+
{
470+
return btf_type_is_func(t) || btf_type_is_struct(t) ||
471+
btf_type_is_var(t);
472+
}
473+
462474
u32 btf_nr_types(const struct btf *btf)
463475
{
464476
u32 total = 0;
@@ -537,6 +549,7 @@ const struct btf_type *btf_type_resolve_func_ptr(const struct btf *btf,
537549
static bool btf_type_is_resolve_source_only(const struct btf_type *t)
538550
{
539551
return btf_type_is_var(t) ||
552+
btf_type_is_tag(t) ||
540553
btf_type_is_datasec(t);
541554
}
542555

@@ -563,6 +576,7 @@ static bool btf_type_needs_resolve(const struct btf_type *t)
563576
btf_type_is_struct(t) ||
564577
btf_type_is_array(t) ||
565578
btf_type_is_var(t) ||
579+
btf_type_is_tag(t) ||
566580
btf_type_is_datasec(t);
567581
}
568582

@@ -616,6 +630,11 @@ static const struct btf_var *btf_type_var(const struct btf_type *t)
616630
return (const struct btf_var *)(t + 1);
617631
}
618632

633+
static const struct btf_tag *btf_type_tag(const struct btf_type *t)
634+
{
635+
return (const struct btf_tag *)(t + 1);
636+
}
637+
619638
static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
620639
{
621640
return kind_ops[BTF_INFO_KIND(t->info)];
@@ -3801,6 +3820,110 @@ static const struct btf_kind_operations float_ops = {
38013820
.show = btf_df_show,
38023821
};
38033822

3823+
static s32 btf_tag_check_meta(struct btf_verifier_env *env,
3824+
const struct btf_type *t,
3825+
u32 meta_left)
3826+
{
3827+
const struct btf_tag *tag;
3828+
u32 meta_needed = sizeof(*tag);
3829+
s32 component_idx;
3830+
const char *value;
3831+
3832+
if (meta_left < meta_needed) {
3833+
btf_verifier_log_basic(env, t,
3834+
"meta_left:%u meta_needed:%u",
3835+
meta_left, meta_needed);
3836+
return -EINVAL;
3837+
}
3838+
3839+
value = btf_name_by_offset(env->btf, t->name_off);
3840+
if (!value || !value[0]) {
3841+
btf_verifier_log_type(env, t, "Invalid value");
3842+
return -EINVAL;
3843+
}
3844+
3845+
if (btf_type_vlen(t)) {
3846+
btf_verifier_log_type(env, t, "vlen != 0");
3847+
return -EINVAL;
3848+
}
3849+
3850+
if (btf_type_kflag(t)) {
3851+
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
3852+
return -EINVAL;
3853+
}
3854+
3855+
component_idx = btf_type_tag(t)->component_idx;
3856+
if (component_idx < -1) {
3857+
btf_verifier_log_type(env, t, "Invalid component_idx");
3858+
return -EINVAL;
3859+
}
3860+
3861+
btf_verifier_log_type(env, t, NULL);
3862+
3863+
return meta_needed;
3864+
}
3865+
3866+
static int btf_tag_resolve(struct btf_verifier_env *env,
3867+
const struct resolve_vertex *v)
3868+
{
3869+
const struct btf_type *next_type;
3870+
const struct btf_type *t = v->t;
3871+
u32 next_type_id = t->type;
3872+
struct btf *btf = env->btf;
3873+
s32 component_idx;
3874+
u32 vlen;
3875+
3876+
next_type = btf_type_by_id(btf, next_type_id);
3877+
if (!next_type || !btf_type_is_tag_target(next_type)) {
3878+
btf_verifier_log_type(env, v->t, "Invalid type_id");
3879+
return -EINVAL;
3880+
}
3881+
3882+
if (!env_type_is_resolve_sink(env, next_type) &&
3883+
!env_type_is_resolved(env, next_type_id))
3884+
return env_stack_push(env, next_type, next_type_id);
3885+
3886+
component_idx = btf_type_tag(t)->component_idx;
3887+
if (component_idx != -1) {
3888+
if (btf_type_is_var(next_type)) {
3889+
btf_verifier_log_type(env, v->t, "Invalid component_idx");
3890+
return -EINVAL;
3891+
}
3892+
3893+
if (btf_type_is_struct(next_type)) {
3894+
vlen = btf_type_vlen(next_type);
3895+
} else {
3896+
/* next_type should be a function */
3897+
next_type = btf_type_by_id(btf, next_type->type);
3898+
vlen = btf_type_vlen(next_type);
3899+
}
3900+
3901+
if ((u32)component_idx >= vlen) {
3902+
btf_verifier_log_type(env, v->t, "Invalid component_idx");
3903+
return -EINVAL;
3904+
}
3905+
}
3906+
3907+
env_stack_pop_resolved(env, next_type_id, 0);
3908+
3909+
return 0;
3910+
}
3911+
3912+
static void btf_tag_log(struct btf_verifier_env *env, const struct btf_type *t)
3913+
{
3914+
btf_verifier_log(env, "type=%u component_idx=%d", t->type,
3915+
btf_type_tag(t)->component_idx);
3916+
}
3917+
3918+
static const struct btf_kind_operations tag_ops = {
3919+
.check_meta = btf_tag_check_meta,
3920+
.resolve = btf_tag_resolve,
3921+
.check_member = btf_df_check_member,
3922+
.check_kflag_member = btf_df_check_kflag_member,
3923+
.log_details = btf_tag_log,
3924+
.show = btf_df_show,
3925+
};
3926+
38043927
static int btf_func_proto_check(struct btf_verifier_env *env,
38053928
const struct btf_type *t)
38063929
{
@@ -3935,6 +4058,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = {
39354058
[BTF_KIND_VAR] = &var_ops,
39364059
[BTF_KIND_DATASEC] = &datasec_ops,
39374060
[BTF_KIND_FLOAT] = &float_ops,
4061+
[BTF_KIND_TAG] = &tag_ops,
39384062
};
39394063

39404064
static s32 btf_check_meta(struct btf_verifier_env *env,
@@ -4019,6 +4143,10 @@ static bool btf_resolve_valid(struct btf_verifier_env *env,
40194143
return !btf_resolved_type_id(btf, type_id) &&
40204144
!btf_resolved_type_size(btf, type_id);
40214145

4146+
if (btf_type_is_tag(t))
4147+
return btf_resolved_type_id(btf, type_id) &&
4148+
!btf_resolved_type_size(btf, type_id);
4149+
40224150
if (btf_type_is_modifier(t) || btf_type_is_ptr(t) ||
40234151
btf_type_is_var(t)) {
40244152
t = btf_type_id_resolve(btf, &type_id);

tools/bpf/bpftool/btf.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
3737
[BTF_KIND_VAR] = "VAR",
3838
[BTF_KIND_DATASEC] = "DATASEC",
3939
[BTF_KIND_FLOAT] = "FLOAT",
40+
[BTF_KIND_TAG] = "TAG",
4041
};
4142

4243
struct btf_attach_table {
@@ -347,6 +348,17 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
347348
printf(" size=%u", t->size);
348349
break;
349350
}
351+
case BTF_KIND_TAG: {
352+
const struct btf_tag *tag = (const void *)(t + 1);
353+
354+
if (json_output) {
355+
jsonw_uint_field(w, "type_id", t->type);
356+
jsonw_int_field(w, "component_idx", tag->component_idx);
357+
} else {
358+
printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
359+
}
360+
break;
361+
}
350362
default:
351363
break;
352364
}

0 commit comments

Comments
 (0)