mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	bpf: Annotate context types
Annotate BPF program context types with program-side type and kernel-side type.
This type information is used by the verifier. btf_get_prog_ctx_type() is
used in the later patches to verify that BTF type of ctx in BPF program matches to
kernel expected ctx type. For example, the XDP program type is:
BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp, struct xdp_md, struct xdp_buff)
That means that XDP program should be written as:
int xdp_prog(struct xdp_md *ctx) { ... }
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Song Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20191114185720.1641606-16-ast@kernel.org
			
			
This commit is contained in:
		
							parent
							
								
									9cc31b3a09
								
							
						
					
					
						commit
						91cc1a9974
					
				
					 6 changed files with 176 additions and 43 deletions
				
			
		|  | @ -747,7 +747,7 @@ DECLARE_PER_CPU(int, bpf_prog_active); | |||
| extern const struct file_operations bpf_map_fops; | ||||
| extern const struct file_operations bpf_prog_fops; | ||||
| 
 | ||||
| #define BPF_PROG_TYPE(_id, _name) \ | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ | ||||
| 	extern const struct bpf_prog_ops _name ## _prog_ops; \ | ||||
| 	extern const struct bpf_verifier_ops _name ## _verifier_ops; | ||||
| #define BPF_MAP_TYPE(_id, _ops) \ | ||||
|  | @ -1213,6 +1213,15 @@ static inline u32 bpf_sock_convert_ctx_access(enum bpf_access_type type, | |||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_INET | ||||
| struct sk_reuseport_kern { | ||||
| 	struct sk_buff *skb; | ||||
| 	struct sock *sk; | ||||
| 	struct sock *selected_sk; | ||||
| 	void *data_end; | ||||
| 	u32 hash; | ||||
| 	u32 reuseport_id; | ||||
| 	bool bind_inany; | ||||
| }; | ||||
| bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type, | ||||
| 				  struct bpf_insn_access_aux *info); | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,42 +2,68 @@ | |||
| /* internal file - do not include directly */ | ||||
| 
 | ||||
| #ifdef CONFIG_NET | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SOCKET_FILTER, sk_filter) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_CLS, tc_cls_act) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_ACT, tc_cls_act) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SOCKET_FILTER, sk_filter, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_CLS, tc_cls_act, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED_ACT, tc_cls_act, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_XDP, xdp, | ||||
| 	      struct xdp_md, struct xdp_buff) | ||||
| #ifdef CONFIG_CGROUP_BPF | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SKB, cg_skb) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK, cg_sock) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, cg_sock_addr) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SKB, cg_skb, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK, cg_sock, | ||||
| 	      struct bpf_sock, struct sock) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, cg_sock_addr, | ||||
| 	      struct bpf_sock_addr, struct bpf_sock_addr_kern) | ||||
| #endif | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_in) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_out) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_SEG6LOCAL, lwt_seg6local) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SOCK_OPS, sock_ops) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SK_SKB, sk_skb) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SK_MSG, sk_msg) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_FLOW_DISSECTOR, flow_dissector) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_in, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_out, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_SEG6LOCAL, lwt_seg6local, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SOCK_OPS, sock_ops, | ||||
| 	      struct bpf_sock_ops, struct bpf_sock_ops_kern) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SK_SKB, sk_skb, | ||||
| 	      struct __sk_buff, struct sk_buff) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SK_MSG, sk_msg, | ||||
| 	      struct sk_msg_md, struct sk_msg) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_FLOW_DISSECTOR, flow_dissector, | ||||
| 	      struct __sk_buff, struct bpf_flow_dissector) | ||||
| #endif | ||||
| #ifdef CONFIG_BPF_EVENTS | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_RAW_TRACEPOINT, raw_tracepoint) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, raw_tracepoint_writable) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_TRACING, tracing) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe, | ||||
| 	      bpf_user_pt_regs_t, struct pt_regs) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint, | ||||
| 	      __u64, u64) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event, | ||||
| 	      struct bpf_perf_event_data, struct bpf_perf_event_data_kern) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_RAW_TRACEPOINT, raw_tracepoint, | ||||
| 	      struct bpf_raw_tracepoint_args, u64) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, raw_tracepoint_writable, | ||||
| 	      struct bpf_raw_tracepoint_args, u64) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_TRACING, tracing, | ||||
| 	      void *, void *) | ||||
| #endif | ||||
| #ifdef CONFIG_CGROUP_BPF | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_DEVICE, cg_dev) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SYSCTL, cg_sysctl) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCKOPT, cg_sockopt) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_DEVICE, cg_dev, | ||||
| 	      struct bpf_cgroup_dev_ctx, struct bpf_cgroup_dev_ctx) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SYSCTL, cg_sysctl, | ||||
| 	      struct bpf_sysctl, struct bpf_sysctl_kern) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCKOPT, cg_sockopt, | ||||
| 	      struct bpf_sockopt, struct bpf_sockopt_kern) | ||||
| #endif | ||||
| #ifdef CONFIG_BPF_LIRC_MODE2 | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LIRC_MODE2, lirc_mode2) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_LIRC_MODE2, lirc_mode2, | ||||
| 	      __u32, u32) | ||||
| #endif | ||||
| #ifdef CONFIG_INET | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport) | ||||
| BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport, | ||||
| 	      struct sk_reuseport_md, struct sk_reuseport_kern) | ||||
| #endif | ||||
| 
 | ||||
| BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) | ||||
|  |  | |||
							
								
								
									
										114
									
								
								kernel/bpf/btf.c
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								kernel/bpf/btf.c
									
									
									
									
									
								
							|  | @ -2,6 +2,8 @@ | |||
| /* Copyright (c) 2018 Facebook */ | ||||
| 
 | ||||
| #include <uapi/linux/btf.h> | ||||
| #include <uapi/linux/bpf.h> | ||||
| #include <uapi/linux/bpf_perf_event.h> | ||||
| #include <uapi/linux/types.h> | ||||
| #include <linux/seq_file.h> | ||||
| #include <linux/compiler.h> | ||||
|  | @ -16,6 +18,9 @@ | |||
| #include <linux/sort.h> | ||||
| #include <linux/bpf_verifier.h> | ||||
| #include <linux/btf.h> | ||||
| #include <linux/skmsg.h> | ||||
| #include <linux/perf_event.h> | ||||
| #include <net/sock.h> | ||||
| 
 | ||||
| /* BTF (BPF Type Format) is the meta data format which describes
 | ||||
|  * the data types of BPF program/map.  Hence, it basically focus | ||||
|  | @ -3439,13 +3444,98 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, | |||
| 
 | ||||
| extern char __weak _binary__btf_vmlinux_bin_start[]; | ||||
| extern char __weak _binary__btf_vmlinux_bin_end[]; | ||||
| extern struct btf *btf_vmlinux; | ||||
| 
 | ||||
| #define BPF_MAP_TYPE(_id, _ops) | ||||
| static union { | ||||
| 	struct bpf_ctx_convert { | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ | ||||
| 	prog_ctx_type _id##_prog; \ | ||||
| 	kern_ctx_type _id##_kern; | ||||
| #include <linux/bpf_types.h> | ||||
| #undef BPF_PROG_TYPE | ||||
| 	} *__t; | ||||
| 	/* 't' is written once under lock. Read many times. */ | ||||
| 	const struct btf_type *t; | ||||
| } bpf_ctx_convert; | ||||
| enum { | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ | ||||
| 	__ctx_convert##_id, | ||||
| #include <linux/bpf_types.h> | ||||
| #undef BPF_PROG_TYPE | ||||
| }; | ||||
| static u8 bpf_ctx_convert_map[] = { | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ | ||||
| 	[_id] = __ctx_convert##_id, | ||||
| #include <linux/bpf_types.h> | ||||
| #undef BPF_PROG_TYPE | ||||
| }; | ||||
| #undef BPF_MAP_TYPE | ||||
| 
 | ||||
| static const struct btf_member * | ||||
| btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf, | ||||
| 		      const struct btf_type *t, enum bpf_prog_type prog_type) | ||||
| { | ||||
| 	const struct btf_type *conv_struct; | ||||
| 	const struct btf_type *ctx_struct; | ||||
| 	const struct btf_member *ctx_type; | ||||
| 	const char *tname, *ctx_tname; | ||||
| 
 | ||||
| 	conv_struct = bpf_ctx_convert.t; | ||||
| 	if (!conv_struct) { | ||||
| 		bpf_log(log, "btf_vmlinux is malformed\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	t = btf_type_by_id(btf, t->type); | ||||
| 	while (btf_type_is_modifier(t)) | ||||
| 		t = btf_type_by_id(btf, t->type); | ||||
| 	if (!btf_type_is_struct(t)) { | ||||
| 		/* Only pointer to struct is supported for now.
 | ||||
| 		 * That means that BPF_PROG_TYPE_TRACEPOINT with BTF | ||||
| 		 * is not supported yet. | ||||
| 		 * BPF_PROG_TYPE_RAW_TRACEPOINT is fine. | ||||
| 		 */ | ||||
| 		bpf_log(log, "BPF program ctx type is not a struct\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	tname = btf_name_by_offset(btf, t->name_off); | ||||
| 	if (!tname) { | ||||
| 		bpf_log(log, "BPF program ctx struct doesn't have a name\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	/* prog_type is valid bpf program type. No need for bounds check. */ | ||||
| 	ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2; | ||||
| 	/* ctx_struct is a pointer to prog_ctx_type in vmlinux.
 | ||||
| 	 * Like 'struct __sk_buff' | ||||
| 	 */ | ||||
| 	ctx_struct = btf_type_by_id(btf_vmlinux, ctx_type->type); | ||||
| 	if (!ctx_struct) | ||||
| 		/* should not happen */ | ||||
| 		return NULL; | ||||
| 	ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_struct->name_off); | ||||
| 	if (!ctx_tname) { | ||||
| 		/* should not happen */ | ||||
| 		bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	/* only compare that prog's ctx type name is the same as
 | ||||
| 	 * kernel expects. No need to compare field by field. | ||||
| 	 * It's ok for bpf prog to do: | ||||
| 	 * struct __sk_buff {}; | ||||
| 	 * int socket_filter_bpf_prog(struct __sk_buff *skb) | ||||
| 	 * { // no fields of skb are ever used }
 | ||||
| 	 */ | ||||
| 	if (strcmp(ctx_tname, tname)) | ||||
| 		return NULL; | ||||
| 	return ctx_type; | ||||
| } | ||||
| 
 | ||||
| struct btf *btf_parse_vmlinux(void) | ||||
| { | ||||
| 	struct btf_verifier_env *env = NULL; | ||||
| 	struct bpf_verifier_log *log; | ||||
| 	struct btf *btf = NULL; | ||||
| 	int err; | ||||
| 	int err, i; | ||||
| 
 | ||||
| 	env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); | ||||
| 	if (!env) | ||||
|  | @ -3479,6 +3569,26 @@ struct btf *btf_parse_vmlinux(void) | |||
| 	if (err) | ||||
| 		goto errout; | ||||
| 
 | ||||
| 	/* find struct bpf_ctx_convert for type checking later */ | ||||
| 	for (i = 1; i <= btf->nr_types; i++) { | ||||
| 		const struct btf_type *t; | ||||
| 		const char *tname; | ||||
| 
 | ||||
| 		t = btf_type_by_id(btf, i); | ||||
| 		if (!__btf_type_is_struct(t)) | ||||
| 			continue; | ||||
| 		tname = __btf_name_by_offset(btf, t->name_off); | ||||
| 		if (!strcmp(tname, "bpf_ctx_convert")) { | ||||
| 			/* btf_parse_vmlinux() runs under bpf_verifier_lock */ | ||||
| 			bpf_ctx_convert.t = t; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (i > btf->nr_types) { | ||||
| 		err = -ENOENT; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 
 | ||||
| 	btf_verifier_env_free(env); | ||||
| 	refcount_set(&btf->refcnt, 1); | ||||
| 	return btf; | ||||
|  | @ -3492,8 +3602,6 @@ struct btf *btf_parse_vmlinux(void) | |||
| 	return ERR_PTR(err); | ||||
| } | ||||
| 
 | ||||
| extern struct btf *btf_vmlinux; | ||||
| 
 | ||||
| bool btf_ctx_access(int off, int size, enum bpf_access_type type, | ||||
| 		    const struct bpf_prog *prog, | ||||
| 		    struct bpf_insn_access_aux *info) | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ static DEFINE_SPINLOCK(map_idr_lock); | |||
| int sysctl_unprivileged_bpf_disabled __read_mostly; | ||||
| 
 | ||||
| static const struct bpf_map_ops * const bpf_map_types[] = { | ||||
| #define BPF_PROG_TYPE(_id, _ops) | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) | ||||
| #define BPF_MAP_TYPE(_id, _ops) \ | ||||
| 	[_id] = &_ops, | ||||
| #include <linux/bpf_types.h> | ||||
|  | @ -1189,7 +1189,7 @@ static int map_freeze(const union bpf_attr *attr) | |||
| } | ||||
| 
 | ||||
| static const struct bpf_prog_ops * const bpf_prog_types[] = { | ||||
| #define BPF_PROG_TYPE(_id, _name) \ | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ | ||||
| 	[_id] = & _name ## _prog_ops, | ||||
| #define BPF_MAP_TYPE(_id, _ops) | ||||
| #include <linux/bpf_types.h> | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ | |||
| #include "disasm.h" | ||||
| 
 | ||||
| static const struct bpf_verifier_ops * const bpf_verifier_ops[] = { | ||||
| #define BPF_PROG_TYPE(_id, _name) \ | ||||
| #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ | ||||
| 	[_id] = & _name ## _verifier_ops, | ||||
| #define BPF_MAP_TYPE(_id, _ops) | ||||
| #include <linux/bpf_types.h> | ||||
|  |  | |||
|  | @ -8684,16 +8684,6 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, | |||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_INET | ||||
| struct sk_reuseport_kern { | ||||
| 	struct sk_buff *skb; | ||||
| 	struct sock *sk; | ||||
| 	struct sock *selected_sk; | ||||
| 	void *data_end; | ||||
| 	u32 hash; | ||||
| 	u32 reuseport_id; | ||||
| 	bool bind_inany; | ||||
| }; | ||||
| 
 | ||||
| static void bpf_init_reuseport_kern(struct sk_reuseport_kern *reuse_kern, | ||||
| 				    struct sock_reuseport *reuse, | ||||
| 				    struct sock *sk, struct sk_buff *skb, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Alexei Starovoitov
						Alexei Starovoitov