bpf: fix integer overflows
authorAlexei Starovoitov <ast@kernel.org>
Tue, 19 Dec 2017 04:12:00 +0000 (20:12 -0800)
committerPeter Michael Green <plugwash@raspbian.org>
Wed, 7 Feb 2018 23:32:32 +0000 (23:32 +0000)
There were various issues related to the limited size of integers used in
the verifier:
 - `off + size` overflow in __check_map_access()
 - `off + reg->off` overflow in check_mem_access()
 - `off + reg->var_off.value` overflow or 32-bit truncation of
   `reg->var_off.value` in check_mem_access()
 - 32-bit truncation in check_stack_boundary()

Make sure that any integer math cannot overflow by not allowing
pointer math with large values.

Also reduce the scope of "scalar op scalar" tracking.

Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
[carnil:
 - adjust context, we previously change verbose() signature
 - drop changes to include/linux/bpf_verifier.h already set
]

Gbp-Pq: Topic bugfix/all
Gbp-Pq: Name bpf-fix-integer-overflows.patch

kernel/bpf/verifier.c

index 31bdf181470e82a4d51e88d7f2bc47501c423444..8bd7d2e97e0def8b976d93616b486b9e7a968f92 100644 (file)
@@ -1821,25 +1821,25 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
        s64 smin = reg->smin_value;
 
        if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) {
-               verbose("math between %s pointer and %lld is not allowed\n",
+               verbose(env, "math between %s pointer and %lld is not allowed\n",
                        reg_type_str[type], val);
                return false;
        }
 
        if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
-               verbose("%s pointer offset %d is not allowed\n",
+               verbose(env, "%s pointer offset %d is not allowed\n",
                        reg_type_str[type], reg->off);
                return false;
        }
 
        if (smin == S64_MIN) {
-               verbose("math between %s pointer and register with unbounded min value is not allowed\n",
+               verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n",
                        reg_type_str[type]);
                return false;
        }
 
        if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) {
-               verbose("value %lld makes %s pointer be out of bounds\n",
+               verbose(env, "value %lld makes %s pointer be out of bounds\n",
                        smin, reg_type_str[type]);
                return false;
        }