Skip to content

Commit b082af7

Browse files
committed
Merge branch 'bpf-ctx-info-out-of-verifier'
Jakub Kicinski says: ==================== bpf: move context info out of the verifier Daniel pointed out during the review of my previous patchset that the knowledge about context doesn't really belong directly in the verifier. This patch set takes a bit of a drastic approach to move the info out of there. I want to be able to use different set of verifier_ops for program analysis. To do that, I have to first move the test_run callback to a separate structure. Then verifier ops can be declared in the verifier directly and different sets can be picked for verification vs analysis. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 386fd5d + 29d1b33 commit b082af7

File tree

7 files changed

+150
-76
lines changed

7 files changed

+150
-76
lines changed

include/linux/bpf.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ bpf_ctx_record_field_size(struct bpf_insn_access_aux *aux, u32 size)
157157
aux->ctx_field_size = size;
158158
}
159159

160+
struct bpf_prog_ops {
161+
int (*test_run)(struct bpf_prog *prog, const union bpf_attr *kattr,
162+
union bpf_attr __user *uattr);
163+
};
164+
160165
struct bpf_verifier_ops {
161166
/* return eBPF function prototype for verification */
162167
const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id);
@@ -172,8 +177,6 @@ struct bpf_verifier_ops {
172177
const struct bpf_insn *src,
173178
struct bpf_insn *dst,
174179
struct bpf_prog *prog, u32 *target_size);
175-
int (*test_run)(struct bpf_prog *prog, const union bpf_attr *kattr,
176-
union bpf_attr __user *uattr);
177180
};
178181

179182
struct bpf_prog_aux {
@@ -184,7 +187,7 @@ struct bpf_prog_aux {
184187
u32 id;
185188
struct latch_tree_node ksym_tnode;
186189
struct list_head ksym_lnode;
187-
const struct bpf_verifier_ops *ops;
190+
const struct bpf_prog_ops *ops;
188191
struct bpf_map **used_maps;
189192
struct bpf_prog *prog;
190193
struct user_struct *user;
@@ -279,14 +282,18 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
279282
#ifdef CONFIG_BPF_SYSCALL
280283
DECLARE_PER_CPU(int, bpf_prog_active);
281284

282-
#define BPF_PROG_TYPE(_id, _ops) \
283-
extern const struct bpf_verifier_ops _ops;
285+
#define BPF_PROG_TYPE(_id, _name) \
286+
extern const struct bpf_prog_ops _name ## _prog_ops; \
287+
extern const struct bpf_verifier_ops _name ## _verifier_ops;
284288
#define BPF_MAP_TYPE(_id, _ops) \
285289
extern const struct bpf_map_ops _ops;
286290
#include <linux/bpf_types.h>
287291
#undef BPF_PROG_TYPE
288292
#undef BPF_MAP_TYPE
289293

294+
extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops;
295+
extern const struct bpf_verifier_ops xdp_analyzer_ops;
296+
290297
struct bpf_prog *bpf_prog_get(u32 ufd);
291298
struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type);
292299
struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, int i);

include/linux/bpf_types.h

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
/* internal file - do not include directly */
22

33
#ifdef CONFIG_NET
4-
BPF_PROG_TYPE(BPF_PROG_TYPE_SOCKET_FILTER, sk_filter_prog_ops)
5-
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_CLS, tc_cls_act_prog_ops)
6-
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_ACT, tc_cls_act_prog_ops)
7-
BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp_prog_ops)
8-
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SKB, cg_skb_prog_ops)
9-
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK, cg_sock_prog_ops)
10-
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_inout_prog_ops)
11-
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_inout_prog_ops)
12-
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit_prog_ops)
13-
BPF_PROG_TYPE(BPF_PROG_TYPE_SOCK_OPS, sock_ops_prog_ops)
14-
BPF_PROG_TYPE(BPF_PROG_TYPE_SK_SKB, sk_skb_prog_ops)
4+
BPF_PROG_TYPE(BPF_PROG_TYPE_SOCKET_FILTER, sk_filter)
5+
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_CLS, tc_cls_act)
6+
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_ACT, tc_cls_act)
7+
BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp)
8+
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SKB, cg_skb)
9+
BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK, cg_sock)
10+
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_inout)
11+
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_inout)
12+
BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit)
13+
BPF_PROG_TYPE(BPF_PROG_TYPE_SOCK_OPS, sock_ops)
14+
BPF_PROG_TYPE(BPF_PROG_TYPE_SK_SKB, sk_skb)
1515
#endif
1616
#ifdef CONFIG_BPF_EVENTS
17-
BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe_prog_ops)
18-
BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint_prog_ops)
19-
BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event_prog_ops)
17+
BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe)
18+
BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint)
19+
BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event)
2020
#endif
2121

2222
BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)

include/linux/bpf_verifier.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ struct bpf_ext_analyzer_ops {
141141
*/
142142
struct bpf_verifier_env {
143143
struct bpf_prog *prog; /* eBPF program being verified */
144+
const struct bpf_verifier_ops *ops;
144145
struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */
145146
int stack_size; /* number of states to be processed */
146147
bool strict_alignment; /* perform strict pointer alignment checks */

kernel/bpf/syscall.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -739,9 +739,9 @@ static int map_get_next_key(union bpf_attr *attr)
739739
return err;
740740
}
741741

742-
static const struct bpf_verifier_ops * const bpf_prog_types[] = {
743-
#define BPF_PROG_TYPE(_id, _ops) \
744-
[_id] = &_ops,
742+
static const struct bpf_prog_ops * const bpf_prog_types[] = {
743+
#define BPF_PROG_TYPE(_id, _name) \
744+
[_id] = & _name ## _prog_ops,
745745
#define BPF_MAP_TYPE(_id, _ops)
746746
#include <linux/bpf_types.h>
747747
#undef BPF_PROG_TYPE

kernel/bpf/verifier.c

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@
2323

2424
#include "disasm.h"
2525

26+
static const struct bpf_verifier_ops * const bpf_verifier_ops[] = {
27+
#define BPF_PROG_TYPE(_id, _name) \
28+
[_id] = & _name ## _verifier_ops,
29+
#define BPF_MAP_TYPE(_id, _ops)
30+
#include <linux/bpf_types.h>
31+
#undef BPF_PROG_TYPE
32+
#undef BPF_MAP_TYPE
33+
};
34+
2635
/* bpf_check() is a static code analyzer that walks eBPF program
2736
* instruction by instruction and updates register/stack state.
2837
* All paths of conditional branches are analyzed until 'bpf_exit' insn.
@@ -813,36 +822,6 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
813822
return err;
814823
}
815824

816-
static bool analyzer_is_valid_access(struct bpf_verifier_env *env, int off,
817-
struct bpf_insn_access_aux *info)
818-
{
819-
switch (env->prog->type) {
820-
case BPF_PROG_TYPE_XDP:
821-
switch (off) {
822-
case offsetof(struct xdp_buff, data):
823-
info->reg_type = PTR_TO_PACKET;
824-
return true;
825-
case offsetof(struct xdp_buff, data_end):
826-
info->reg_type = PTR_TO_PACKET_END;
827-
return true;
828-
}
829-
return false;
830-
case BPF_PROG_TYPE_SCHED_CLS:
831-
switch (off) {
832-
case offsetof(struct sk_buff, data):
833-
info->reg_type = PTR_TO_PACKET;
834-
return true;
835-
case offsetof(struct sk_buff, cb) +
836-
offsetof(struct bpf_skb_data_end, data_end):
837-
info->reg_type = PTR_TO_PACKET_END;
838-
return true;
839-
}
840-
return false;
841-
default:
842-
return false;
843-
}
844-
}
845-
846825
/* check access to 'struct bpf_context' fields. Supports fixed offsets only */
847826
static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, int size,
848827
enum bpf_access_type t, enum bpf_reg_type *reg_type)
@@ -851,23 +830,21 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off,
851830
.reg_type = *reg_type,
852831
};
853832

854-
if (env->analyzer_ops) {
855-
if (analyzer_is_valid_access(env, off, &info)) {
856-
*reg_type = info.reg_type;
857-
return 0;
858-
}
859-
} else if (env->prog->aux->ops->is_valid_access &&
860-
env->prog->aux->ops->is_valid_access(off, size, t, &info)) {
833+
if (env->ops->is_valid_access &&
834+
env->ops->is_valid_access(off, size, t, &info)) {
861835
/* A non zero info.ctx_field_size indicates that this field is a
862836
* candidate for later verifier transformation to load the whole
863837
* field and then apply a mask when accessed with a narrower
864838
* access than actual ctx access size. A zero info.ctx_field_size
865839
* will only allow for whole field access and rejects any other
866840
* type of narrower access.
867841
*/
868-
env->insn_aux_data[insn_idx].ctx_field_size = info.ctx_field_size;
869842
*reg_type = info.reg_type;
870843

844+
if (env->analyzer_ops)
845+
return 0;
846+
847+
env->insn_aux_data[insn_idx].ctx_field_size = info.ctx_field_size;
871848
/* remember the offset of last byte accessed in ctx */
872849
if (env->prog->aux->max_ctx_offset < off + size)
873850
env->prog->aux->max_ctx_offset = off + size;
@@ -1565,8 +1542,8 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx)
15651542
return -EINVAL;
15661543
}
15671544

1568-
if (env->prog->aux->ops->get_func_proto)
1569-
fn = env->prog->aux->ops->get_func_proto(func_id);
1545+
if (env->ops->get_func_proto)
1546+
fn = env->ops->get_func_proto(func_id);
15701547

15711548
if (!fn) {
15721549
verbose(env, "unknown func %s#%d\n", func_id_name(func_id),
@@ -4035,7 +4012,7 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
40354012
*/
40364013
static int convert_ctx_accesses(struct bpf_verifier_env *env)
40374014
{
4038-
const struct bpf_verifier_ops *ops = env->prog->aux->ops;
4015+
const struct bpf_verifier_ops *ops = env->ops;
40394016
int i, cnt, size, ctx_field_size, delta = 0;
40404017
const int insn_cnt = env->prog->len;
40414018
struct bpf_insn insn_buf[16], *insn;
@@ -4236,7 +4213,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
42364213
insn = new_prog->insnsi + i + delta;
42374214
}
42384215
patch_call_imm:
4239-
fn = prog->aux->ops->get_func_proto(insn->imm);
4216+
fn = env->ops->get_func_proto(insn->imm);
42404217
/* all functions that have prototype and verifier allowed
42414218
* programs to call them, must be real in-kernel functions
42424219
*/
@@ -4294,6 +4271,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
42944271
if (!env->insn_aux_data)
42954272
goto err_free_env;
42964273
env->prog = *prog;
4274+
env->ops = bpf_verifier_ops[env->prog->type];
42974275

42984276
/* grab the mutex to protect few globals used by verifier */
42994277
mutex_lock(&bpf_verifier_lock);
@@ -4390,12 +4368,21 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
43904368
return ret;
43914369
}
43924370

4371+
static const struct bpf_verifier_ops * const bpf_analyzer_ops[] = {
4372+
[BPF_PROG_TYPE_XDP] = &xdp_analyzer_ops,
4373+
[BPF_PROG_TYPE_SCHED_CLS] = &tc_cls_act_analyzer_ops,
4374+
};
4375+
43934376
int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
43944377
void *priv)
43954378
{
43964379
struct bpf_verifier_env *env;
43974380
int ret;
43984381

4382+
if (prog->type >= ARRAY_SIZE(bpf_analyzer_ops) ||
4383+
!bpf_analyzer_ops[prog->type])
4384+
return -EOPNOTSUPP;
4385+
43994386
env = kzalloc(sizeof(struct bpf_verifier_env), GFP_KERNEL);
44004387
if (!env)
44014388
return -ENOMEM;
@@ -4406,6 +4393,7 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
44064393
if (!env->insn_aux_data)
44074394
goto err_free_env;
44084395
env->prog = prog;
4396+
env->ops = bpf_analyzer_ops[env->prog->type];
44094397
env->analyzer_ops = ops;
44104398
env->analyzer_priv = priv;
44114399

kernel/trace/bpf_trace.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,11 +561,14 @@ static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type
561561
return true;
562562
}
563563

564-
const struct bpf_verifier_ops kprobe_prog_ops = {
564+
const struct bpf_verifier_ops kprobe_verifier_ops = {
565565
.get_func_proto = kprobe_prog_func_proto,
566566
.is_valid_access = kprobe_prog_is_valid_access,
567567
};
568568

569+
const struct bpf_prog_ops kprobe_prog_ops = {
570+
};
571+
569572
BPF_CALL_5(bpf_perf_event_output_tp, void *, tp_buff, struct bpf_map *, map,
570573
u64, flags, void *, data, u64, size)
571574
{
@@ -667,11 +670,14 @@ static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type
667670
return true;
668671
}
669672

670-
const struct bpf_verifier_ops tracepoint_prog_ops = {
673+
const struct bpf_verifier_ops tracepoint_verifier_ops = {
671674
.get_func_proto = tp_prog_func_proto,
672675
.is_valid_access = tp_prog_is_valid_access,
673676
};
674677

678+
const struct bpf_prog_ops tracepoint_prog_ops = {
679+
};
680+
675681
static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
676682
struct bpf_insn_access_aux *info)
677683
{
@@ -727,8 +733,11 @@ static u32 pe_prog_convert_ctx_access(enum bpf_access_type type,
727733
return insn - insn_buf;
728734
}
729735

730-
const struct bpf_verifier_ops perf_event_prog_ops = {
736+
const struct bpf_verifier_ops perf_event_verifier_ops = {
731737
.get_func_proto = tp_prog_func_proto,
732738
.is_valid_access = pe_prog_is_valid_access,
733739
.convert_ctx_access = pe_prog_convert_ctx_access,
734740
};
741+
742+
const struct bpf_prog_ops perf_event_prog_ops = {
743+
};

0 commit comments

Comments
 (0)