Skip to content

Commit 597e0a3

Browse files
alan-maguirekernel-patches-bot
authored andcommitted
bpf: add bpf_snprintf_btf helper
A helper is added to support tracing kernel type information in BPF using the BPF Type Format (BTF). Its signature is long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags); struct btf_ptr * specifies - a pointer to the data to be traced; - the BTF id of the type of data pointed to; or - a string representation of the type of data pointed to - a flags field is provided for future use; these flags are not to be confused with the BTF_F_* flags below that control how the btf_ptr is displayed; the flags member of the struct btf_ptr may be used to disambiguate types in kernel versus module BTF, etc; the main distinction is the flags relate to the type and information needed in identifying it; not how it is displayed. For example a BPF program with a struct sk_buff *skb could do the following: static const char skb_type[] = "struct sk_buff"; static struct btf_ptr b = { }; b.ptr = skb; b.type = skb_type; bpf_snprintf_btf(str, sizeof(str), &b, sizeof(b), 0, 0); Default output looks like this: (struct sk_buff){ .transport_header = (__u16)65535, .mac_header = (__u16)65535, .end = (sk_buff_data_t)192, .head = (unsigned char *)0x000000007524fd8b, .data = (unsigned char *)0x000000007524fd8b, .truesize = (unsigned int)768, .users = (refcount_t){ .refs = (atomic_t){ .counter = (int)1, }, }, } Flags modifying display are as follows: - BTF_F_COMPACT: no formatting around type information - BTF_F_NONAME: no struct/union member names/types - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values; equivalent to %px. - BTF_F_ZERO: show zero-valued struct/union members; they are not displayed by default Signed-off-by: Alan Maguire <[email protected]>
1 parent 3ea1dd4 commit 597e0a3

File tree

8 files changed

+250
-4
lines changed

8 files changed

+250
-4
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto;
17951795
extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
17961796
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
17971797
extern const struct bpf_func_proto bpf_copy_from_user_proto;
1798+
extern const struct bpf_func_proto bpf_snprintf_btf_proto;
17981799

17991800
const struct bpf_func_proto *bpf_tracing_func_proto(
18001801
enum bpf_func_id func_id, const struct bpf_prog *prog);

include/linux/btf.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <linux/types.h>
88
#include <uapi/linux/btf.h>
9+
#include <uapi/linux/bpf.h>
910

1011
#define BTF_TYPE_EMIT(type) ((void)(type *)0)
1112

@@ -59,10 +60,10 @@ const struct btf_type *btf_type_id_size(const struct btf *btf,
5960
* - BTF_SHOW_UNSAFE: skip use of bpf_probe_read() to safely read
6061
* data before displaying it.
6162
*/
62-
#define BTF_SHOW_COMPACT (1ULL << 0)
63-
#define BTF_SHOW_NONAME (1ULL << 1)
64-
#define BTF_SHOW_PTR_RAW (1ULL << 2)
65-
#define BTF_SHOW_ZERO (1ULL << 3)
63+
#define BTF_SHOW_COMPACT BTF_F_COMPACT
64+
#define BTF_SHOW_NONAME BTF_F_NONAME
65+
#define BTF_SHOW_PTR_RAW BTF_F_PTR_RAW
66+
#define BTF_SHOW_ZERO BTF_F_ZERO
6667
#define BTF_SHOW_UNSAFE (1ULL << 4)
6768

6869
void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,

include/uapi/linux/bpf.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,6 +3586,41 @@ union bpf_attr {
35863586
* the data in *dst*. This is a wrapper of **copy_from_user**\ ().
35873587
* Return
35883588
* 0 on success, or a negative error in case of failure.
3589+
*
3590+
* long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags)
3591+
* Description
3592+
* Use BTF to store a string representation of *ptr*->ptr in *str*,
3593+
* using *ptr*->type name or *ptr*->type_id. These values should
3594+
* specify the type *ptr*->ptr points to. Traversing that
3595+
* data structure using BTF, the type information and values are
3596+
* stored in the first *str_size* - 1 bytes of *str*. Safe copy of
3597+
* the pointer data is carried out to avoid kernel crashes during
3598+
* operation. Smaller types can use string space on the stack;
3599+
* larger programs can use map data to store the string
3600+
* representation.
3601+
*
3602+
* The string can be subsequently shared with userspace via
3603+
* bpf_perf_event_output() or ring buffer interfaces.
3604+
* bpf_trace_printk() is to be avoided as it places too small
3605+
* a limit on string size to be useful.
3606+
*
3607+
* *flags* is a combination of
3608+
*
3609+
* **BTF_F_COMPACT**
3610+
* no formatting around type information
3611+
* **BTF_F_NONAME**
3612+
* no struct/union member names/types
3613+
* **BTF_F_PTR_RAW**
3614+
* show raw (unobfuscated) pointer values;
3615+
* equivalent to printk specifier %px.
3616+
* **BTF_F_ZERO**
3617+
* show zero-valued struct/union members; they
3618+
* are not displayed by default
3619+
*
3620+
* Return
3621+
* The number of bytes that were written (or would have been
3622+
* written if output had to be truncated due to string size),
3623+
* or a negative error in cases of failure.
35893624
*/
35903625
#define __BPF_FUNC_MAPPER(FN) \
35913626
FN(unspec), \
@@ -3737,6 +3772,7 @@ union bpf_attr {
37373772
FN(inode_storage_delete), \
37383773
FN(d_path), \
37393774
FN(copy_from_user), \
3775+
FN(snprintf_btf), \
37403776
/* */
37413777

37423778
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -4845,4 +4881,36 @@ struct bpf_sk_lookup {
48454881
__u32 local_port; /* Host byte order */
48464882
};
48474883

4884+
/*
4885+
* struct btf_ptr is used for typed pointer representation; the
4886+
* additional type string/BTF type id are used to render the pointer
4887+
* data as the appropriate type via the bpf_snprintf_btf() helper
4888+
* above. A flags field - potentially to specify additional details
4889+
* about the BTF pointer (rather than its mode of display) - is
4890+
* present for future use. Display flags - BTF_F_* - are
4891+
* passed to bpf_snprintf_btf separately.
4892+
*/
4893+
struct btf_ptr {
4894+
void *ptr;
4895+
const char *type;
4896+
__u32 type_id;
4897+
__u32 flags; /* BTF ptr flags; unused at present. */
4898+
};
4899+
4900+
/*
4901+
* Flags to control bpf_snprintf_btf() behaviour.
4902+
* - BTF_F_COMPACT: no formatting around type information
4903+
* - BTF_F_NONAME: no struct/union member names/types
4904+
* - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values;
4905+
* equivalent to %px.
4906+
* - BTF_F_ZERO: show zero-valued struct/union members; they
4907+
* are not displayed by default
4908+
*/
4909+
enum {
4910+
BTF_F_COMPACT = (1ULL << 0),
4911+
BTF_F_NONAME = (1ULL << 1),
4912+
BTF_F_PTR_RAW = (1ULL << 2),
4913+
BTF_F_ZERO = (1ULL << 3),
4914+
};
4915+
48484916
#endif /* _UAPI__LINUX_BPF_H__ */

kernel/bpf/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,7 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto __weak;
22162216
const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto __weak;
22172217
const struct bpf_func_proto bpf_get_local_storage_proto __weak;
22182218
const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto __weak;
2219+
const struct bpf_func_proto bpf_snprintf_btf_proto __weak;
22192220

22202221
const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void)
22212222
{

kernel/bpf/helpers.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,10 @@ bpf_base_func_proto(enum bpf_func_id func_id)
683683
if (!perfmon_capable())
684684
return NULL;
685685
return bpf_get_trace_printk_proto();
686+
case BPF_FUNC_snprintf_btf:
687+
if (!perfmon_capable())
688+
return NULL;
689+
return &bpf_snprintf_btf_proto;
686690
case BPF_FUNC_jiffies64:
687691
return &bpf_jiffies64_proto;
688692
default:

kernel/trace/bpf_trace.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/slab.h>
88
#include <linux/bpf.h>
99
#include <linux/bpf_perf_event.h>
10+
#include <linux/btf.h>
1011
#include <linux/filter.h>
1112
#include <linux/uaccess.h>
1213
#include <linux/ctype.h>
@@ -16,6 +17,9 @@
1617
#include <linux/error-injection.h>
1718
#include <linux/btf_ids.h>
1819

20+
#include <uapi/linux/bpf.h>
21+
#include <uapi/linux/btf.h>
22+
1923
#include <asm/tlb.h>
2024

2125
#include "trace_probe.h"
@@ -1147,6 +1151,101 @@ static const struct bpf_func_proto bpf_d_path_proto = {
11471151
.allowed = bpf_d_path_allowed,
11481152
};
11491153

1154+
#define BTF_F_ALL (BTF_F_COMPACT | BTF_F_NONAME | \
1155+
BTF_F_PTR_RAW | BTF_F_ZERO)
1156+
1157+
static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
1158+
u64 flags, const struct btf **btf,
1159+
s32 *btf_id)
1160+
{
1161+
u8 btf_kind = BTF_KIND_TYPEDEF;
1162+
char type_name[KSYM_NAME_LEN];
1163+
const struct btf_type *t;
1164+
const char *btf_type;
1165+
int ret;
1166+
1167+
if (unlikely(flags & ~(BTF_F_ALL)))
1168+
return -EINVAL;
1169+
1170+
if (btf_ptr_size != sizeof(struct btf_ptr))
1171+
return -EINVAL;
1172+
1173+
*btf = bpf_get_btf_vmlinux();
1174+
1175+
if (IS_ERR_OR_NULL(*btf))
1176+
return PTR_ERR(*btf);
1177+
1178+
if (ptr->type != NULL) {
1179+
ret = copy_from_kernel_nofault(type_name, ptr->type,
1180+
sizeof(type_name));
1181+
if (ret)
1182+
return ret;
1183+
1184+
btf_type = type_name;
1185+
1186+
if (strncmp(btf_type, "struct ", strlen("struct ")) == 0) {
1187+
btf_kind = BTF_KIND_STRUCT;
1188+
btf_type += strlen("struct ");
1189+
} else if (strncmp(btf_type, "union ", strlen("union ")) == 0) {
1190+
btf_kind = BTF_KIND_UNION;
1191+
btf_type += strlen("union ");
1192+
} else if (strncmp(btf_type, "enum ", strlen("enum ")) == 0) {
1193+
btf_kind = BTF_KIND_ENUM;
1194+
btf_type += strlen("enum ");
1195+
}
1196+
1197+
if (strlen(btf_type) == 0)
1198+
return -EINVAL;
1199+
1200+
/* Assume type specified is a typedef as there's not much
1201+
* benefit in specifying int types other than wasting time
1202+
* on BTF lookups; we optimize for the most useful path.
1203+
*
1204+
* Fall back to BTF_KIND_INT if this fails.
1205+
*/
1206+
*btf_id = btf_find_by_name_kind(*btf, btf_type, btf_kind);
1207+
if (*btf_id < 0)
1208+
*btf_id = btf_find_by_name_kind(*btf, btf_type,
1209+
BTF_KIND_INT);
1210+
} else if (ptr->type_id > 0)
1211+
*btf_id = ptr->type_id;
1212+
else
1213+
return -EINVAL;
1214+
1215+
if (*btf_id > 0)
1216+
t = btf_type_by_id(*btf, *btf_id);
1217+
if (*btf_id <= 0 || !t)
1218+
return -ENOENT;
1219+
1220+
return 0;
1221+
}
1222+
1223+
BPF_CALL_5(bpf_snprintf_btf, char *, str, u32, str_size, struct btf_ptr *, ptr,
1224+
u32, btf_ptr_size, u64, flags)
1225+
{
1226+
const struct btf *btf;
1227+
s32 btf_id;
1228+
int ret;
1229+
1230+
ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id);
1231+
if (ret)
1232+
return ret;
1233+
1234+
return btf_type_snprintf_show(btf, btf_id, ptr->ptr, str, str_size,
1235+
flags);
1236+
}
1237+
1238+
const struct bpf_func_proto bpf_snprintf_btf_proto = {
1239+
.func = bpf_snprintf_btf,
1240+
.gpl_only = false,
1241+
.ret_type = RET_INTEGER,
1242+
.arg1_type = ARG_PTR_TO_MEM,
1243+
.arg2_type = ARG_CONST_SIZE,
1244+
.arg3_type = ARG_PTR_TO_MEM,
1245+
.arg4_type = ARG_CONST_SIZE,
1246+
.arg5_type = ARG_ANYTHING,
1247+
};
1248+
11501249
const struct bpf_func_proto *
11511250
bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
11521251
{
@@ -1233,6 +1332,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
12331332
return &bpf_get_task_stack_proto;
12341333
case BPF_FUNC_copy_from_user:
12351334
return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
1335+
case BPF_FUNC_snprintf_btf:
1336+
return &bpf_snprintf_btf_proto;
12361337
default:
12371338
return NULL;
12381339
}

scripts/bpf_helpers_doc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ class PrinterHelpers(Printer):
433433
'struct sk_msg_md',
434434
'struct xdp_md',
435435
'struct path',
436+
'struct btf_ptr',
436437
]
437438
known_types = {
438439
'...',
@@ -474,6 +475,7 @@ class PrinterHelpers(Printer):
474475
'struct udp6_sock',
475476
'struct task_struct',
476477
'struct path',
478+
'struct btf_ptr',
477479
}
478480
mapped_types = {
479481
'u8': '__u8',

tools/include/uapi/linux/bpf.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,6 +3586,41 @@ union bpf_attr {
35863586
* the data in *dst*. This is a wrapper of **copy_from_user**\ ().
35873587
* Return
35883588
* 0 on success, or a negative error in case of failure.
3589+
*
3590+
* long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags)
3591+
* Description
3592+
* Use BTF to store a string representation of *ptr*->ptr in *str*,
3593+
* using *ptr*->type name or *ptr*->type_id. These values should
3594+
* specify the type *ptr*->ptr points to. Traversing that
3595+
* data structure using BTF, the type information and values are
3596+
* stored in the first *str_size* - 1 bytes of *str*. Safe copy of
3597+
* the pointer data is carried out to avoid kernel crashes during
3598+
* operation. Smaller types can use string space on the stack;
3599+
* larger programs can use map data to store the string
3600+
* representation.
3601+
*
3602+
* The string can be subsequently shared with userspace via
3603+
* bpf_perf_event_output() or ring buffer interfaces.
3604+
* bpf_trace_printk() is to be avoided as it places too small
3605+
* a limit on string size to be useful.
3606+
*
3607+
* *flags* is a combination of
3608+
*
3609+
* **BTF_F_COMPACT**
3610+
* no formatting around type information
3611+
* **BTF_F_NONAME**
3612+
* no struct/union member names/types
3613+
* **BTF_F_PTR_RAW**
3614+
* show raw (unobfuscated) pointer values;
3615+
* equivalent to printk specifier %px.
3616+
* **BTF_F_ZERO**
3617+
* show zero-valued struct/union members; they
3618+
* are not displayed by default
3619+
*
3620+
* Return
3621+
* The number of bytes that were written (or would have been
3622+
* written if output had to be truncated due to string size),
3623+
* or a negative error in cases of failure.
35893624
*/
35903625
#define __BPF_FUNC_MAPPER(FN) \
35913626
FN(unspec), \
@@ -3737,6 +3772,7 @@ union bpf_attr {
37373772
FN(inode_storage_delete), \
37383773
FN(d_path), \
37393774
FN(copy_from_user), \
3775+
FN(snprintf_btf), \
37403776
/* */
37413777

37423778
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -4845,4 +4881,36 @@ struct bpf_sk_lookup {
48454881
__u32 local_port; /* Host byte order */
48464882
};
48474883

4884+
/*
4885+
* struct btf_ptr is used for typed pointer representation; the
4886+
* additional type string/BTF type id are used to render the pointer
4887+
* data as the appropriate type via the bpf_snprintf_btf() helper
4888+
* above. A flags field - potentially to specify additional details
4889+
* about the BTF pointer (rather than its mode of display) - is
4890+
* present for future use. Display flags - BTF_F_* - are
4891+
* passed to bpf_snprintf_btf separately.
4892+
*/
4893+
struct btf_ptr {
4894+
void *ptr;
4895+
const char *type;
4896+
__u32 type_id;
4897+
__u32 flags; /* BTF ptr flags; unused at present. */
4898+
};
4899+
4900+
/*
4901+
* Flags to control bpf_snprintf_btf() behaviour.
4902+
* - BTF_F_COMPACT: no formatting around type information
4903+
* - BTF_F_NONAME: no struct/union member names/types
4904+
* - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values;
4905+
* equivalent to %px.
4906+
* - BTF_F_ZERO: show zero-valued struct/union members; they
4907+
* are not displayed by default
4908+
*/
4909+
enum {
4910+
BTF_F_COMPACT = (1ULL << 0),
4911+
BTF_F_NONAME = (1ULL << 1),
4912+
BTF_F_PTR_RAW = (1ULL << 2),
4913+
BTF_F_ZERO = (1ULL << 3),
4914+
};
4915+
48484916
#endif /* _UAPI__LINUX_BPF_H__ */

0 commit comments

Comments
 (0)