Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Liam Wisehart <liamwisehart@meta.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Fixes: 6fcd486b3a0a ("bpf: Refactor RCU enforcement in the verifier.")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/r/20240427002544.68803-1-alexei.starovoitov@gmail.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

authored by

Alexei Starovoitov and committed by
Martin KaFai Lau
0db63c0b 89de2db1

+38 -18
+18 -5
kernel/bpf/verifier.c
··· 2368 2368 regs[regno].type = PTR_TO_BTF_ID | flag; 2369 2369 regs[regno].btf = btf; 2370 2370 regs[regno].btf_id = btf_id; 2371 + if (type_may_be_null(flag)) 2372 + regs[regno].id = ++env->id_gen; 2371 2373 } 2372 2374 2373 2375 #define DEF_NOT_SUBREG (0) ··· 5402 5400 */ 5403 5401 mark_btf_ld_reg(env, cur_regs(env), value_regno, PTR_TO_BTF_ID, kptr_field->kptr.btf, 5404 5402 kptr_field->kptr.btf_id, btf_ld_kptr_type(env, kptr_field)); 5405 - /* For mark_ptr_or_null_reg */ 5406 - val_reg->id = ++env->id_gen; 5407 5403 } else if (class == BPF_STX) { 5408 5404 val_reg = reg_state(env, value_regno); 5409 5405 if (!register_is_null(val_reg) && ··· 5719 5719 return true; 5720 5720 5721 5721 /* Types listed in the reg2btf_ids are always trusted */ 5722 - if (reg2btf_ids[base_type(reg->type)]) 5722 + if (reg2btf_ids[base_type(reg->type)] && 5723 + !bpf_type_has_unsafe_modifiers(reg->type)) 5723 5724 return true; 5724 5725 5725 5726 /* If a register is not referenced, it is trusted if it has the ··· 6340 6339 #define BTF_TYPE_SAFE_RCU(__type) __PASTE(__type, __safe_rcu) 6341 6340 #define BTF_TYPE_SAFE_RCU_OR_NULL(__type) __PASTE(__type, __safe_rcu_or_null) 6342 6341 #define BTF_TYPE_SAFE_TRUSTED(__type) __PASTE(__type, __safe_trusted) 6342 + #define BTF_TYPE_SAFE_TRUSTED_OR_NULL(__type) __PASTE(__type, __safe_trusted_or_null) 6343 6343 6344 6344 /* 6345 6345 * Allow list few fields as RCU trusted or full trusted. ··· 6404 6402 struct inode *d_inode; 6405 6403 }; 6406 6404 6407 - BTF_TYPE_SAFE_TRUSTED(struct socket) { 6405 + BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket) { 6408 6406 struct sock *sk; 6409 6407 }; 6410 6408 ··· 6439 6437 BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct linux_binprm)); 6440 6438 BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct file)); 6441 6439 BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct dentry)); 6442 - BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct socket)); 6443 6440 6444 6441 return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, "__safe_trusted"); 6442 + } 6443 + 6444 + static bool type_is_trusted_or_null(struct bpf_verifier_env *env, 6445 + struct bpf_reg_state *reg, 6446 + const char *field_name, u32 btf_id) 6447 + { 6448 + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket)); 6449 + 6450 + return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, 6451 + "__safe_trusted_or_null"); 6445 6452 } 6446 6453 6447 6454 static int check_ptr_to_btf_access(struct bpf_verifier_env *env, ··· 6561 6550 */ 6562 6551 if (type_is_trusted(env, reg, field_name, btf_id)) { 6563 6552 flag |= PTR_TRUSTED; 6553 + } else if (type_is_trusted_or_null(env, reg, field_name, btf_id)) { 6554 + flag |= PTR_TRUSTED | PTR_MAYBE_NULL; 6564 6555 } else if (in_rcu_cs(env) && !type_may_be_null(reg->type)) { 6565 6556 if (type_is_rcu(env, reg, field_name, btf_id)) { 6566 6557 /* ignore __rcu tag and mark it MEM_RCU */
+3 -2
tools/testing/selftests/bpf/progs/bench_local_storage_create.c
··· 61 61 int BPF_PROG(socket_post_create, struct socket *sock, int family, int type, 62 62 int protocol, int kern) 63 63 { 64 + struct sock *sk = sock->sk; 64 65 struct storage *stg; 65 66 __u32 pid; 66 67 67 68 pid = bpf_get_current_pid_tgid() >> 32; 68 - if (pid != bench_pid) 69 + if (pid != bench_pid || !sk) 69 70 return 0; 70 71 71 - stg = bpf_sk_storage_get(&sk_storage_map, sock->sk, NULL, 72 + stg = bpf_sk_storage_get(&sk_storage_map, sk, NULL, 72 73 BPF_LOCAL_STORAGE_GET_F_CREATE); 73 74 74 75 if (stg)
+11 -9
tools/testing/selftests/bpf/progs/local_storage.c
··· 140 140 { 141 141 __u32 pid = bpf_get_current_pid_tgid() >> 32; 142 142 struct local_storage *storage; 143 + struct sock *sk = sock->sk; 143 144 144 - if (pid != monitored_pid) 145 + if (pid != monitored_pid || !sk) 145 146 return 0; 146 147 147 - storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0, 0); 148 + storage = bpf_sk_storage_get(&sk_storage_map, sk, 0, 0); 148 149 if (!storage) 149 150 return 0; 150 151 ··· 156 155 /* This tests that we can associate multiple elements 157 156 * with the local storage. 158 157 */ 159 - storage = bpf_sk_storage_get(&sk_storage_map2, sock->sk, 0, 158 + storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0, 160 159 BPF_LOCAL_STORAGE_GET_F_CREATE); 161 160 if (!storage) 162 161 return 0; 163 162 164 - if (bpf_sk_storage_delete(&sk_storage_map2, sock->sk)) 163 + if (bpf_sk_storage_delete(&sk_storage_map2, sk)) 165 164 return 0; 166 165 167 - storage = bpf_sk_storage_get(&sk_storage_map2, sock->sk, 0, 166 + storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0, 168 167 BPF_LOCAL_STORAGE_GET_F_CREATE); 169 168 if (!storage) 170 169 return 0; 171 170 172 - if (bpf_sk_storage_delete(&sk_storage_map, sock->sk)) 171 + if (bpf_sk_storage_delete(&sk_storage_map, sk)) 173 172 return 0; 174 173 175 174 /* Ensure that the sk_storage_map is disconnected from the storage. */ 176 - if (!sock->sk->sk_bpf_storage || sock->sk->sk_bpf_storage->smap) 175 + if (!sk->sk_bpf_storage || sk->sk_bpf_storage->smap) 177 176 return 0; 178 177 179 178 sk_storage_result = 0; ··· 186 185 { 187 186 __u32 pid = bpf_get_current_pid_tgid() >> 32; 188 187 struct local_storage *storage; 188 + struct sock *sk = sock->sk; 189 189 190 - if (pid != monitored_pid) 190 + if (pid != monitored_pid || !sk) 191 191 return 0; 192 192 193 - storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0, 193 + storage = bpf_sk_storage_get(&sk_storage_map, sk, 0, 194 194 BPF_LOCAL_STORAGE_GET_F_CREATE); 195 195 if (!storage) 196 196 return 0;
+6 -2
tools/testing/selftests/bpf/progs/lsm_cgroup.c
··· 103 103 int addrlen) 104 104 { 105 105 struct sockaddr_ll sa = {}; 106 + struct sock *sk = sock->sk; 106 107 107 - if (sock->sk->__sk_common.skc_family != AF_PACKET) 108 + if (!sk) 108 109 return 1; 109 110 110 - if (sock->sk->sk_kern_sock) 111 + if (sk->__sk_common.skc_family != AF_PACKET) 112 + return 1; 113 + 114 + if (sk->sk_kern_sock) 111 115 return 1; 112 116 113 117 bpf_probe_read_kernel(&sa, sizeof(sa), address);