scalar += rdonly_untrusted_mem reaches adjust_ptr_min_max_vals() with the
pointer as the source register. The untrusted PTR_TO_MEM case returns there
without updating the scalar destination, leaving stale verifier state.

Handle the untrusted PTR_TO_MEM case before the early return. Addition and
pointer-minus-scalar subtraction preserve the pointer type and keep the
existing "do not track offsets" rule for untrusted memory.
Scalar-minus-pointer and unsupported pointer ALU operations are still
rejected instead of being accepted by the early return.

Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
Signed-off-by: Nuoqi Gui <[email protected]>
---
 kernel/bpf/verifier.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c8d980fdd709..26c67c53166b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -13729,8 +13729,32 @@ static int adjust_ptr_min_max_vals(struct 
bpf_verifier_env *env,
         * Accesses to untrusted PTR_TO_MEM are done through probe
         * instructions, hence no need to track offsets.
         */
-       if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & 
PTR_UNTRUSTED))
-               return 0;
+       if (base_type(ptr_reg->type) == PTR_TO_MEM &&
+           (ptr_reg->type & PTR_UNTRUSTED)) {
+               switch (opcode) {
+               case BPF_ADD:
+                       *dst_reg = *ptr_reg;
+                       return 0;
+               case BPF_SUB:
+                       if (dst_reg == off_reg) {
+                               verbose(env, "R%d tried to subtract pointer 
from scalar\n",
+                                       dst);
+                               return -EACCES;
+                       }
+                       *dst_reg = *ptr_reg;
+                       return 0;
+               case BPF_AND:
+               case BPF_OR:
+               case BPF_XOR:
+                       verbose(env, "R%d bitwise operator %s on pointer 
prohibited\n",
+                               dst, bpf_alu_string[opcode >> 4]);
+                       return -EACCES;
+               default:
+                       verbose(env, "R%d pointer arithmetic with %s operator 
prohibited\n",
+                               dst, bpf_alu_string[opcode >> 4]);
+                       return -EACCES;
+               }
+       }
 
        switch (base_type(ptr_reg->type)) {
        case PTR_TO_CTX:

-- 
2.34.1


Reply via email to