Commit 0db63c0b authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Martin KaFai Lau

bpf: Fix verifier assumptions about socket->sk

The verifier assumes that 'sk' field in 'struct socket' is valid
and non-NULL when 'socket' pointer itself is trusted and non-NULL.
That may not be the case when socket was just created and
passed to LSM socket_accept hook.
Fix this verifier assumption and adjust tests.
Reported-by: default avatarLiam Wisehart <liamwisehart@meta.com>
Acked-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Fixes: 6fcd486b ("bpf: Refactor RCU enforcement in the verifier.")
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/r/20240427002544.68803-1-alexei.starovoitov@gmail.comSigned-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parent 89de2db1
...@@ -2368,6 +2368,8 @@ static void mark_btf_ld_reg(struct bpf_verifier_env *env, ...@@ -2368,6 +2368,8 @@ static void mark_btf_ld_reg(struct bpf_verifier_env *env,
regs[regno].type = PTR_TO_BTF_ID | flag; regs[regno].type = PTR_TO_BTF_ID | flag;
regs[regno].btf = btf; regs[regno].btf = btf;
regs[regno].btf_id = btf_id; regs[regno].btf_id = btf_id;
if (type_may_be_null(flag))
regs[regno].id = ++env->id_gen;
} }
#define DEF_NOT_SUBREG (0) #define DEF_NOT_SUBREG (0)
...@@ -5400,8 +5402,6 @@ static int check_map_kptr_access(struct bpf_verifier_env *env, u32 regno, ...@@ -5400,8 +5402,6 @@ static int check_map_kptr_access(struct bpf_verifier_env *env, u32 regno,
*/ */
mark_btf_ld_reg(env, cur_regs(env), value_regno, PTR_TO_BTF_ID, kptr_field->kptr.btf, mark_btf_ld_reg(env, cur_regs(env), value_regno, PTR_TO_BTF_ID, kptr_field->kptr.btf,
kptr_field->kptr.btf_id, btf_ld_kptr_type(env, kptr_field)); kptr_field->kptr.btf_id, btf_ld_kptr_type(env, kptr_field));
/* For mark_ptr_or_null_reg */
val_reg->id = ++env->id_gen;
} else if (class == BPF_STX) { } else if (class == BPF_STX) {
val_reg = reg_state(env, value_regno); val_reg = reg_state(env, value_regno);
if (!register_is_null(val_reg) && if (!register_is_null(val_reg) &&
...@@ -5719,7 +5719,8 @@ static bool is_trusted_reg(const struct bpf_reg_state *reg) ...@@ -5719,7 +5719,8 @@ static bool is_trusted_reg(const struct bpf_reg_state *reg)
return true; return true;
/* Types listed in the reg2btf_ids are always trusted */ /* Types listed in the reg2btf_ids are always trusted */
if (reg2btf_ids[base_type(reg->type)]) if (reg2btf_ids[base_type(reg->type)] &&
!bpf_type_has_unsafe_modifiers(reg->type))
return true; return true;
/* If a register is not referenced, it is trusted if it has the /* If a register is not referenced, it is trusted if it has the
...@@ -6339,6 +6340,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val, ...@@ -6339,6 +6340,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val,
#define BTF_TYPE_SAFE_RCU(__type) __PASTE(__type, __safe_rcu) #define BTF_TYPE_SAFE_RCU(__type) __PASTE(__type, __safe_rcu)
#define BTF_TYPE_SAFE_RCU_OR_NULL(__type) __PASTE(__type, __safe_rcu_or_null) #define BTF_TYPE_SAFE_RCU_OR_NULL(__type) __PASTE(__type, __safe_rcu_or_null)
#define BTF_TYPE_SAFE_TRUSTED(__type) __PASTE(__type, __safe_trusted) #define BTF_TYPE_SAFE_TRUSTED(__type) __PASTE(__type, __safe_trusted)
#define BTF_TYPE_SAFE_TRUSTED_OR_NULL(__type) __PASTE(__type, __safe_trusted_or_null)
/* /*
* Allow list few fields as RCU trusted or full trusted. * Allow list few fields as RCU trusted or full trusted.
...@@ -6402,7 +6404,7 @@ BTF_TYPE_SAFE_TRUSTED(struct dentry) { ...@@ -6402,7 +6404,7 @@ BTF_TYPE_SAFE_TRUSTED(struct dentry) {
struct inode *d_inode; struct inode *d_inode;
}; };
BTF_TYPE_SAFE_TRUSTED(struct socket) { BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket) {
struct sock *sk; struct sock *sk;
}; };
...@@ -6437,11 +6439,20 @@ static bool type_is_trusted(struct bpf_verifier_env *env, ...@@ -6437,11 +6439,20 @@ static bool type_is_trusted(struct bpf_verifier_env *env,
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct linux_binprm)); BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct linux_binprm));
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct file)); BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct file));
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct dentry)); BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct dentry));
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct socket));
return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, "__safe_trusted"); return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, "__safe_trusted");
} }
static bool type_is_trusted_or_null(struct bpf_verifier_env *env,
struct bpf_reg_state *reg,
const char *field_name, u32 btf_id)
{
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket));
return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id,
"__safe_trusted_or_null");
}
static int check_ptr_to_btf_access(struct bpf_verifier_env *env, static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
struct bpf_reg_state *regs, struct bpf_reg_state *regs,
int regno, int off, int size, int regno, int off, int size,
...@@ -6550,6 +6561,8 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, ...@@ -6550,6 +6561,8 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
*/ */
if (type_is_trusted(env, reg, field_name, btf_id)) { if (type_is_trusted(env, reg, field_name, btf_id)) {
flag |= PTR_TRUSTED; flag |= PTR_TRUSTED;
} else if (type_is_trusted_or_null(env, reg, field_name, btf_id)) {
flag |= PTR_TRUSTED | PTR_MAYBE_NULL;
} else if (in_rcu_cs(env) && !type_may_be_null(reg->type)) { } else if (in_rcu_cs(env) && !type_may_be_null(reg->type)) {
if (type_is_rcu(env, reg, field_name, btf_id)) { if (type_is_rcu(env, reg, field_name, btf_id)) {
/* ignore __rcu tag and mark it MEM_RCU */ /* ignore __rcu tag and mark it MEM_RCU */
......
...@@ -61,14 +61,15 @@ SEC("lsm.s/socket_post_create") ...@@ -61,14 +61,15 @@ SEC("lsm.s/socket_post_create")
int BPF_PROG(socket_post_create, struct socket *sock, int family, int type, int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
int protocol, int kern) int protocol, int kern)
{ {
struct sock *sk = sock->sk;
struct storage *stg; struct storage *stg;
__u32 pid; __u32 pid;
pid = bpf_get_current_pid_tgid() >> 32; pid = bpf_get_current_pid_tgid() >> 32;
if (pid != bench_pid) if (pid != bench_pid || !sk)
return 0; return 0;
stg = bpf_sk_storage_get(&sk_storage_map, sock->sk, NULL, stg = bpf_sk_storage_get(&sk_storage_map, sk, NULL,
BPF_LOCAL_STORAGE_GET_F_CREATE); BPF_LOCAL_STORAGE_GET_F_CREATE);
if (stg) if (stg)
......
...@@ -140,11 +140,12 @@ int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address, ...@@ -140,11 +140,12 @@ int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
{ {
__u32 pid = bpf_get_current_pid_tgid() >> 32; __u32 pid = bpf_get_current_pid_tgid() >> 32;
struct local_storage *storage; struct local_storage *storage;
struct sock *sk = sock->sk;
if (pid != monitored_pid) if (pid != monitored_pid || !sk)
return 0; return 0;
storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0, 0); storage = bpf_sk_storage_get(&sk_storage_map, sk, 0, 0);
if (!storage) if (!storage)
return 0; return 0;
...@@ -155,24 +156,24 @@ int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address, ...@@ -155,24 +156,24 @@ int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
/* This tests that we can associate multiple elements /* This tests that we can associate multiple elements
* with the local storage. * with the local storage.
*/ */
storage = bpf_sk_storage_get(&sk_storage_map2, sock->sk, 0, storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE); BPF_LOCAL_STORAGE_GET_F_CREATE);
if (!storage) if (!storage)
return 0; return 0;
if (bpf_sk_storage_delete(&sk_storage_map2, sock->sk)) if (bpf_sk_storage_delete(&sk_storage_map2, sk))
return 0; return 0;
storage = bpf_sk_storage_get(&sk_storage_map2, sock->sk, 0, storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE); BPF_LOCAL_STORAGE_GET_F_CREATE);
if (!storage) if (!storage)
return 0; return 0;
if (bpf_sk_storage_delete(&sk_storage_map, sock->sk)) if (bpf_sk_storage_delete(&sk_storage_map, sk))
return 0; return 0;
/* Ensure that the sk_storage_map is disconnected from the storage. */ /* Ensure that the sk_storage_map is disconnected from the storage. */
if (!sock->sk->sk_bpf_storage || sock->sk->sk_bpf_storage->smap) if (!sk->sk_bpf_storage || sk->sk_bpf_storage->smap)
return 0; return 0;
sk_storage_result = 0; sk_storage_result = 0;
...@@ -185,11 +186,12 @@ int BPF_PROG(socket_post_create, struct socket *sock, int family, int type, ...@@ -185,11 +186,12 @@ int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
{ {
__u32 pid = bpf_get_current_pid_tgid() >> 32; __u32 pid = bpf_get_current_pid_tgid() >> 32;
struct local_storage *storage; struct local_storage *storage;
struct sock *sk = sock->sk;
if (pid != monitored_pid) if (pid != monitored_pid || !sk)
return 0; return 0;
storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0, storage = bpf_sk_storage_get(&sk_storage_map, sk, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE); BPF_LOCAL_STORAGE_GET_F_CREATE);
if (!storage) if (!storage)
return 0; return 0;
......
...@@ -103,11 +103,15 @@ static __always_inline int real_bind(struct socket *sock, ...@@ -103,11 +103,15 @@ static __always_inline int real_bind(struct socket *sock,
int addrlen) int addrlen)
{ {
struct sockaddr_ll sa = {}; struct sockaddr_ll sa = {};
struct sock *sk = sock->sk;
if (sock->sk->__sk_common.skc_family != AF_PACKET) if (!sk)
return 1;
if (sk->__sk_common.skc_family != AF_PACKET)
return 1; return 1;
if (sock->sk->sk_kern_sock) if (sk->sk_kern_sock)
return 1; return 1;
bpf_probe_read_kernel(&sa, sizeof(sa), address); bpf_probe_read_kernel(&sa, sizeof(sa), address);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment