On Mon, Dec 6, 2021 at 3:22 PM Hao Luo <haoluo@xxxxxxxxxx> wrote: > > We have introduced a new type to make bpf_reg composable, by > allocating bits in the type to represent flags. > > One of the flags is PTR_MAYBE_NULL which indicates a pointer > may be NULL. This patch switches the qualified reg_types to > use this flag. The reg_types changed in this patch include: > > 1. PTR_TO_MAP_VALUE_OR_NULL > 2. PTR_TO_SOCKET_OR_NULL > 3. PTR_TO_SOCK_COMMON_OR_NULL > 4. PTR_TO_TCP_SOCK_OR_NULL > 5. PTR_TO_BTF_ID_OR_NULL > 6. PTR_TO_MEM_OR_NULL > 7. PTR_TO_RDONLY_BUF_OR_NULL > 8. PTR_TO_RDWR_BUF_OR_NULL > > Signed-off-by: Hao Luo <haoluo@xxxxxxxxxx> > --- > drivers/net/ethernet/netronome/nfp/bpf/fw.h | 4 +- > include/linux/bpf.h | 16 +- > kernel/bpf/btf.c | 7 +- > kernel/bpf/map_iter.c | 4 +- > kernel/bpf/verifier.c | 278 ++++++++------------ > net/core/bpf_sk_storage.c | 2 +- > net/core/sock_map.c | 2 +- > 7 files changed, 126 insertions(+), 187 deletions(-) > [...] > @@ -535,38 +520,35 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn) > } > > /* string representation of 'enum bpf_reg_type' */ > -static const char * const reg_type_str[] = { > - [NOT_INIT] = "?", > - [SCALAR_VALUE] = "inv", > - [PTR_TO_CTX] = "ctx", > - [CONST_PTR_TO_MAP] = "map_ptr", > - [PTR_TO_MAP_VALUE] = "map_value", > - [PTR_TO_MAP_VALUE_OR_NULL] = "map_value_or_null", > - [PTR_TO_STACK] = "fp", > - [PTR_TO_PACKET] = "pkt", > - [PTR_TO_PACKET_META] = "pkt_meta", > - [PTR_TO_PACKET_END] = "pkt_end", > - [PTR_TO_FLOW_KEYS] = "flow_keys", > - [PTR_TO_SOCKET] = "sock", > - [PTR_TO_SOCKET_OR_NULL] = "sock_or_null", > - [PTR_TO_SOCK_COMMON] = "sock_common", > - [PTR_TO_SOCK_COMMON_OR_NULL] = "sock_common_or_null", > - [PTR_TO_TCP_SOCK] = "tcp_sock", > - [PTR_TO_TCP_SOCK_OR_NULL] = "tcp_sock_or_null", > - [PTR_TO_TP_BUFFER] = "tp_buffer", > - [PTR_TO_XDP_SOCK] = "xdp_sock", > - [PTR_TO_BTF_ID] = "ptr_", > - [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_", > - [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", > - [PTR_TO_MEM] = "mem", > - [PTR_TO_MEM_OR_NULL] = "mem_or_null", > - [PTR_TO_RDONLY_BUF] = "rdonly_buf", > - [PTR_TO_RDONLY_BUF_OR_NULL] = "rdonly_buf_or_null", > - [PTR_TO_RDWR_BUF] = "rdwr_buf", > - [PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null", > - [PTR_TO_FUNC] = "func", > - [PTR_TO_MAP_KEY] = "map_key", > -}; > +static const char *reg_type_str(enum bpf_reg_type type) > +{ > + static const char * const str[] = { > + [NOT_INIT] = "?", > + [SCALAR_VALUE] = "inv", > + [PTR_TO_CTX] = "ctx", > + [CONST_PTR_TO_MAP] = "map_ptr", > + [PTR_TO_MAP_VALUE] = "map_value", > + [PTR_TO_STACK] = "fp", > + [PTR_TO_PACKET] = "pkt", > + [PTR_TO_PACKET_META] = "pkt_meta", > + [PTR_TO_PACKET_END] = "pkt_end", > + [PTR_TO_FLOW_KEYS] = "flow_keys", > + [PTR_TO_SOCKET] = "sock", > + [PTR_TO_SOCK_COMMON] = "sock_common", > + [PTR_TO_TCP_SOCK] = "tcp_sock", > + [PTR_TO_TP_BUFFER] = "tp_buffer", > + [PTR_TO_XDP_SOCK] = "xdp_sock", > + [PTR_TO_BTF_ID] = "ptr_", > + [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", > + [PTR_TO_MEM] = "mem", > + [PTR_TO_RDONLY_BUF] = "rdonly_buf", > + [PTR_TO_RDWR_BUF] = "rdwr_buf", > + [PTR_TO_FUNC] = "func", > + [PTR_TO_MAP_KEY] = "map_key", > + }; > + > + return str[base_type(type)]; well... now we lose the "_or_null" part, that can be pretty important. Same will happen with RDONLY flag, right? What can we do about that? > +} > > static char slot_type_char[] = { > [STACK_INVALID] = '?', > @@ -631,7 +613,7 @@ static void print_verifier_state(struct bpf_verifier_env *env, > continue; > verbose(env, " R%d", i); > print_liveness(env, reg->live); > - verbose(env, "=%s", reg_type_str[t]); > + verbose(env, "=%s", reg_type_str(t)); > if (t == SCALAR_VALUE && reg->precise) > verbose(env, "P"); > if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && [...] > if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) { > verbose(env, "value %lld makes %s pointer be out of bounds\n", > - smin, reg_type_str[type]); > + smin, reg_type_str(type)); > return false; > } > > @@ -7209,11 +7151,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, > return -EACCES; > } > > - switch (ptr_reg->type) { > - case PTR_TO_MAP_VALUE_OR_NULL: > + if (ptr_reg->type == PTR_TO_MAP_VALUE_OR_NULL) { > verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n", the same message can be output for other pointer types, so instead of special-casing, let's just combine them with more helpful message > - dst, reg_type_str[ptr_reg->type]); > + dst, reg_type_str(ptr_reg->type)); > return -EACCES; > + } > + > + switch (base_type(ptr_reg->type)) { > case CONST_PTR_TO_MAP: > /* smin_val represents the known value */ > if (known && smin_val == 0 && opcode == BPF_ADD) > @@ -7221,14 +7165,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, > fallthrough; > case PTR_TO_PACKET_END: > case PTR_TO_SOCKET: > - case PTR_TO_SOCKET_OR_NULL: > case PTR_TO_SOCK_COMMON: > - case PTR_TO_SOCK_COMMON_OR_NULL: > case PTR_TO_TCP_SOCK: > - case PTR_TO_TCP_SOCK_OR_NULL: > case PTR_TO_XDP_SOCK: > verbose(env, "R%d pointer arithmetic on %s prohibited\n", > - dst, reg_type_str[ptr_reg->type]); > + dst, reg_type_str(ptr_reg->type)); > return -EACCES; > default: > break; [...]