Skip to content

Commit fdfd9d8

Browse files
author
Martin KaFai Lau
committed
Merge branch 'bpf: Allow skb dynptr for tp_btf'
Philo Lu says: ==================== This makes bpf_dynptr_from_skb usable for tp_btf, so that we can easily parse skb in tracepoints. This has been discussed in [0], and Martin suggested to use dynptr (instead of helpers like bpf_skb_load_bytes). For safety, skb dynptr shouldn't be used in fentry/fexit. This is achieved by add KF_TRUSTED_ARGS flag in bpf_dynptr_from_skb defination, because pointers passed by tracepoint are trusted (PTR_TRUSTED) while those of fentry/fexit are not. Another problem raises that NULL pointers could be passed to tracepoint, such as trace_tcp_send_reset, and we need to recognize them. This is done by add a "__nullable" suffix in the func_proto of the tracepoint, discussed in [1]. 2 Test cases are added, one for "__nullable" suffix, and the other for using skb dynptr in tp_btf. changelog v2 -> v3 (Andrii Nakryiko): Patch 1: - Remove prog type check in prog_arg_maybe_null() - Add bpf_put_raw_tracepoint() after get() - Use kallsyms_lookup() instead of sprintf("%ps") Patch 2: Add separate test "tp_btf_nullable", and use full failure msg v1 -> v2: - Add "__nullable" suffix support (Alexei Starovoitov) - Replace "struct __sk_buff*" with "void*" in test (Martin KaFai Lau) [0] https://lore.kernel.org/all/[email protected]/T/ [1] https://lore.kernel.org/all/[email protected]/T/ ==================== Signed-off-by: Martin KaFai Lau <[email protected]>
2 parents 23dc986 + 83dff60 commit fdfd9d8

File tree

11 files changed

+172
-13
lines changed

11 files changed

+172
-13
lines changed

include/trace/events/tcp.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ DEFINE_RST_REASON(FN, FN)
9191
TRACE_EVENT(tcp_send_reset,
9292

9393
TP_PROTO(const struct sock *sk,
94-
const struct sk_buff *skb,
94+
const struct sk_buff *skb__nullable,
9595
const enum sk_rst_reason reason),
9696

97-
TP_ARGS(sk, skb, reason),
97+
TP_ARGS(sk, skb__nullable, reason),
9898

9999
TP_STRUCT__entry(
100100
__field(const void *, skbaddr)
@@ -106,7 +106,7 @@ TRACE_EVENT(tcp_send_reset,
106106
),
107107

108108
TP_fast_assign(
109-
__entry->skbaddr = skb;
109+
__entry->skbaddr = skb__nullable;
110110
__entry->skaddr = sk;
111111
/* Zero means unknown state. */
112112
__entry->state = sk ? sk->sk_state : 0;
@@ -118,13 +118,13 @@ TRACE_EVENT(tcp_send_reset,
118118
const struct inet_sock *inet = inet_sk(sk);
119119

120120
TP_STORE_ADDR_PORTS(__entry, inet, sk);
121-
} else if (skb) {
122-
const struct tcphdr *th = (const struct tcphdr *)skb->data;
121+
} else if (skb__nullable) {
122+
const struct tcphdr *th = (const struct tcphdr *)skb__nullable->data;
123123
/*
124124
* We should reverse the 4-tuple of skb, so later
125125
* it can print the right flow direction of rst.
126126
*/
127-
TP_STORE_ADDR_PORTS_SKB(skb, th, entry->daddr, entry->saddr);
127+
TP_STORE_ADDR_PORTS_SKB(skb__nullable, th, entry->daddr, entry->saddr);
128128
}
129129
__entry->reason = reason;
130130
),

kernel/bpf/btf.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6523,6 +6523,9 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
65236523
if (prog_args_trusted(prog))
65246524
info->reg_type |= PTR_TRUSTED;
65256525

6526+
if (btf_param_match_suffix(btf, &args[arg], "__nullable"))
6527+
info->reg_type |= PTR_MAYBE_NULL;
6528+
65266529
if (tgt_prog) {
65276530
enum bpf_prog_type tgt_type;
65286531

kernel/bpf/verifier.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <linux/cpumask.h>
2929
#include <linux/bpf_mem_alloc.h>
3030
#include <net/xdp.h>
31+
#include <linux/trace_events.h>
32+
#include <linux/kallsyms.h>
3133

3234
#include "disasm.h"
3335

@@ -21154,11 +21156,13 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
2115421156
{
2115521157
bool prog_extension = prog->type == BPF_PROG_TYPE_EXT;
2115621158
bool prog_tracing = prog->type == BPF_PROG_TYPE_TRACING;
21159+
char trace_symbol[KSYM_SYMBOL_LEN];
2115721160
const char prefix[] = "btf_trace_";
21161+
struct bpf_raw_event_map *btp;
2115821162
int ret = 0, subprog = -1, i;
2115921163
const struct btf_type *t;
2116021164
bool conservative = true;
21161-
const char *tname;
21165+
const char *tname, *fname;
2116221166
struct btf *btf;
2116321167
long addr = 0;
2116421168
struct module *mod = NULL;
@@ -21289,10 +21293,34 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
2128921293
return -EINVAL;
2129021294
}
2129121295
tname += sizeof(prefix) - 1;
21292-
t = btf_type_by_id(btf, t->type);
21293-
if (!btf_type_is_ptr(t))
21294-
/* should never happen in valid vmlinux build */
21296+
21297+
/* The func_proto of "btf_trace_##tname" is generated from typedef without argument
21298+
* names. Thus using bpf_raw_event_map to get argument names.
21299+
*/
21300+
btp = bpf_get_raw_tracepoint(tname);
21301+
if (!btp)
2129521302
return -EINVAL;
21303+
fname = kallsyms_lookup((unsigned long)btp->bpf_func, NULL, NULL, NULL,
21304+
trace_symbol);
21305+
bpf_put_raw_tracepoint(btp);
21306+
21307+
if (fname)
21308+
ret = btf_find_by_name_kind(btf, fname, BTF_KIND_FUNC);
21309+
21310+
if (!fname || ret < 0) {
21311+
bpf_log(log, "Cannot find btf of tracepoint template, fall back to %s%s.\n",
21312+
prefix, tname);
21313+
t = btf_type_by_id(btf, t->type);
21314+
if (!btf_type_is_ptr(t))
21315+
/* should never happen in valid vmlinux build */
21316+
return -EINVAL;
21317+
} else {
21318+
t = btf_type_by_id(btf, ret);
21319+
if (!btf_type_is_func(t))
21320+
/* should never happen in valid vmlinux build */
21321+
return -EINVAL;
21322+
}
21323+
2129621324
t = btf_type_by_id(btf, t->type);
2129721325
if (!btf_type_is_func_proto(t))
2129821326
/* should never happen in valid vmlinux build */

net/core/filter.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12063,7 +12063,7 @@ int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
1206312063
}
1206412064

1206512065
BTF_KFUNCS_START(bpf_kfunc_check_set_skb)
12066-
BTF_ID_FLAGS(func, bpf_dynptr_from_skb)
12066+
BTF_ID_FLAGS(func, bpf_dynptr_from_skb, KF_TRUSTED_ARGS)
1206712067
BTF_KFUNCS_END(bpf_kfunc_check_set_skb)
1206812068

1206912069
BTF_KFUNCS_START(bpf_kfunc_check_set_xdp)
@@ -12112,6 +12112,7 @@ static int __init bpf_kfunc_init(void)
1211212112
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LWT_XMIT, &bpf_kfunc_set_skb);
1211312113
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LWT_SEG6LOCAL, &bpf_kfunc_set_skb);
1211412114
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_NETFILTER, &bpf_kfunc_set_skb);
12115+
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_kfunc_set_skb);
1211512116
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &bpf_kfunc_set_xdp);
1211612117
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
1211712118
&bpf_kfunc_set_sock_addr);

tools/testing/selftests/bpf/bpf_testmod/bpf_testmod-events.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ DECLARE_TRACE(bpf_testmod_test_write_bare,
3434
TP_ARGS(task, ctx)
3535
);
3636

37+
/* Used in bpf_testmod_test_read() to test __nullable suffix */
38+
DECLARE_TRACE(bpf_testmod_test_nullable_bare,
39+
TP_PROTO(struct bpf_testmod_test_read_ctx *ctx__nullable),
40+
TP_ARGS(ctx__nullable)
41+
);
42+
3743
#undef BPF_TESTMOD_DECLARE_TRACE
3844
#ifdef DECLARE_TRACE_WRITABLE
3945
#define BPF_TESTMOD_DECLARE_TRACE(call, proto, args, size) \

tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
356356
if (bpf_testmod_loop_test(101) > 100)
357357
trace_bpf_testmod_test_read(current, &ctx);
358358

359+
trace_bpf_testmod_test_nullable_bare(NULL);
360+
359361
/* Magic number to enable writable tp */
360362
if (len == 64) {
361363
struct bpf_testmod_test_writable_ctx writable = {

tools/testing/selftests/bpf/prog_tests/dynptr.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
enum test_setup_type {
1010
SETUP_SYSCALL_SLEEP,
1111
SETUP_SKB_PROG,
12+
SETUP_SKB_PROG_TP,
1213
};
1314

1415
static struct {
@@ -28,14 +29,15 @@ static struct {
2829
{"test_dynptr_clone", SETUP_SKB_PROG},
2930
{"test_dynptr_skb_no_buff", SETUP_SKB_PROG},
3031
{"test_dynptr_skb_strcmp", SETUP_SKB_PROG},
32+
{"test_dynptr_skb_tp_btf", SETUP_SKB_PROG_TP},
3133
};
3234

3335
static void verify_success(const char *prog_name, enum test_setup_type setup_type)
3436
{
3537
struct dynptr_success *skel;
3638
struct bpf_program *prog;
3739
struct bpf_link *link;
38-
int err;
40+
int err;
3941

4042
skel = dynptr_success__open();
4143
if (!ASSERT_OK_PTR(skel, "dynptr_success__open"))
@@ -47,7 +49,7 @@ static void verify_success(const char *prog_name, enum test_setup_type setup_typ
4749
if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
4850
goto cleanup;
4951

50-
bpf_program__set_autoload(prog, true);
52+
bpf_program__set_autoload(prog, true);
5153

5254
err = dynptr_success__load(skel);
5355
if (!ASSERT_OK(err, "dynptr_success__load"))
@@ -87,6 +89,37 @@ static void verify_success(const char *prog_name, enum test_setup_type setup_typ
8789

8890
break;
8991
}
92+
case SETUP_SKB_PROG_TP:
93+
{
94+
struct __sk_buff skb = {};
95+
struct bpf_object *obj;
96+
int aux_prog_fd;
97+
98+
/* Just use its test_run to trigger kfree_skb tracepoint */
99+
err = bpf_prog_test_load("./test_pkt_access.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
100+
&obj, &aux_prog_fd);
101+
if (!ASSERT_OK(err, "prog_load sched cls"))
102+
goto cleanup;
103+
104+
LIBBPF_OPTS(bpf_test_run_opts, topts,
105+
.data_in = &pkt_v4,
106+
.data_size_in = sizeof(pkt_v4),
107+
.ctx_in = &skb,
108+
.ctx_size_in = sizeof(skb),
109+
);
110+
111+
link = bpf_program__attach(prog);
112+
if (!ASSERT_OK_PTR(link, "bpf_program__attach"))
113+
goto cleanup;
114+
115+
err = bpf_prog_test_run_opts(aux_prog_fd, &topts);
116+
bpf_link__destroy(link);
117+
118+
if (!ASSERT_OK(err, "test_run"))
119+
goto cleanup;
120+
121+
break;
122+
}
90123
}
91124

92125
ASSERT_EQ(skel->bss->err, 0, "err");
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <test_progs.h>
4+
#include "test_tp_btf_nullable.skel.h"
5+
6+
void test_tp_btf_nullable(void)
7+
{
8+
if (!env.has_testmod) {
9+
test__skip();
10+
return;
11+
}
12+
13+
RUN_TESTS(test_tp_btf_nullable);
14+
}

tools/testing/selftests/bpf/progs/dynptr_fail.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <stdbool.h>
77
#include <linux/bpf.h>
88
#include <bpf/bpf_helpers.h>
9+
#include <bpf/bpf_tracing.h>
910
#include <linux/if_ether.h>
1011
#include "bpf_misc.h"
1112
#include "bpf_kfuncs.h"
@@ -1254,6 +1255,30 @@ int skb_invalid_ctx(void *ctx)
12541255
return 0;
12551256
}
12561257

1258+
SEC("fentry/skb_tx_error")
1259+
__failure __msg("must be referenced or trusted")
1260+
int BPF_PROG(skb_invalid_ctx_fentry, void *skb)
1261+
{
1262+
struct bpf_dynptr ptr;
1263+
1264+
/* this should fail */
1265+
bpf_dynptr_from_skb(skb, 0, &ptr);
1266+
1267+
return 0;
1268+
}
1269+
1270+
SEC("fexit/skb_tx_error")
1271+
__failure __msg("must be referenced or trusted")
1272+
int BPF_PROG(skb_invalid_ctx_fexit, void *skb)
1273+
{
1274+
struct bpf_dynptr ptr;
1275+
1276+
/* this should fail */
1277+
bpf_dynptr_from_skb(skb, 0, &ptr);
1278+
1279+
return 0;
1280+
}
1281+
12571282
/* Reject writes to dynptr slot for uninit arg */
12581283
SEC("?raw_tp")
12591284
__failure __msg("potential write to dynptr at off=-16")

tools/testing/selftests/bpf/progs/dynptr_success.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <stdbool.h>
66
#include <linux/bpf.h>
77
#include <bpf/bpf_helpers.h>
8+
#include <bpf/bpf_tracing.h>
89
#include "bpf_misc.h"
910
#include "bpf_kfuncs.h"
1011
#include "errno.h"
@@ -544,3 +545,25 @@ int test_dynptr_skb_strcmp(struct __sk_buff *skb)
544545

545546
return 1;
546547
}
548+
549+
SEC("tp_btf/kfree_skb")
550+
int BPF_PROG(test_dynptr_skb_tp_btf, void *skb, void *location)
551+
{
552+
__u8 write_data[2] = {1, 2};
553+
struct bpf_dynptr ptr;
554+
int ret;
555+
556+
if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
557+
err = 1;
558+
return 1;
559+
}
560+
561+
/* since tp_btf skbs are read only, writes should fail */
562+
ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
563+
if (ret != -EINVAL) {
564+
err = 2;
565+
return 1;
566+
}
567+
568+
return 1;
569+
}

0 commit comments

Comments
 (0)