[PATCH bpf-next 2/4] bpf: Merge pointer types also when both are PTR_TO_MEM
Daniel Borkmann <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
save_aux_ptr_type() only reaches the merge when reg_type_mismatch() says
the two types are incompatible, and that in turn requires at least one of
them to have a base type reg_type_mismatch_ok() rejects. PTR_TO_MEM is
not among those, so for two PTR_TO_MEM based types the merge never runs
and the recorded type stays the one of whichever path was verified first.
That is ok as long as all PTR_TO_MEM variants can be dereferenced with
a plain load, which stopped being true with commit f2362a57aeff ("bpf:
allow void* cast using bpf_rdonly_cast()") adding PTR_TO_MEM | MEM_RDONLY
| PTR_UNTRUSTED. If the other path saved e.g. a PTR_TO_MEM | MEM_RINGBUF
first, then bpf_convert_ctx_accesses() does not rewrite the load into a
BPF_PROBE_MEM one, and the untrusted path faults on a plain load.
Fix by merging the two whenever they differ and both are of PTR_TO_MEM or
PTR_TO_BTF_ID base instead of keying it off reg_type_mismatch(), so that
merge_ptr_types() gets to normalize the result in this case as well. The
rejection of genuinely incompatible types is left untouched.
Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
Signed-off-by: Daniel Borkmann <[email protected]>
---
kernel/bpf/verifier.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 0d3b76d7820e..8ef9418733ca 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -17050,6 +17050,17 @@ static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type typ
* save type to validate intersecting paths
*/
*prev_type = type;
+ } else if (*prev_type != type && allow_trust_mismatch &&
+ is_ptr_to_mem_or_btf_id(type) &&
+ is_ptr_to_mem_or_btf_id(*prev_type)) {
+ /*
+ * Have to support a use case when one path through the
+ * program yields a TRUSTED pointer while another is
+ * UNTRUSTED. Merge them into a type which keeps the
+ * BPF_PROBE_MEM/BPF_PROBE_MEMSX rewrite when either
+ * side needs it.
+ */
+ *prev_type = merge_ptr_types(type, *prev_type);
} else if (reg_type_mismatch(type, *prev_type)) {
/* Abuser program is trying to use the same insn
* dst_reg = *(u32*) (src_reg + off)
@@ -17058,21 +17069,8 @@ static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type typ
* src_reg == stack|map in some other branch.
* Reject it.
*/
- if (allow_trust_mismatch &&
- is_ptr_to_mem_or_btf_id(type) &&
- is_ptr_to_mem_or_btf_id(*prev_type)) {
- /*
- * Have to support a use case when one path through
- * the program yields a TRUSTED pointer while another
- * is UNTRUSTED. Merge them into a type which keeps
- * the BPF_PROBE_MEM/BPF_PROBE_MEMSX rewrite when
- * either side needs it.
- */
- *prev_type = merge_ptr_types(type, *prev_type);
- } else {
- verbose(env, "same insn cannot be used with different pointers\n");
- return -EINVAL;
- }
+ verbose(env, "same insn cannot be used with different pointers\n");
+ return -EINVAL;
}
return 0;
--
2.43.0