Vulnerability: kernel/bpf/verifier.c in the Linux kernel through 4.14.8 allows local users to cause a denial of service (memory corruption) or possibly have unspecified other impact by leveraging improper use of pointers in place of scalars.
Vulnerability ID: CVE-2017-17855
CWE: CWE-119
Severity score: 10
Project: https://github.com/torvalds/linux
Published: 2017-12-27
File: kernel/bpf/verifier.c
Commit message: bpf: don't prune branches when a scalar is replaced with a pointer

This could be made safe by passing through a reference to env and checking
for env->allow_ptr_leaks, but it would only work one way and is probably
not worth the hassle - not doing it will not directly lead to program
rejection.

Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Commit author: Jann Horn

Vulnerable version (before fix):
 static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, 			return range_within(rold, rcur) && 			       tnum_in(rold->var_off, rcur->var_off); 		} else { 			/* if we knew anything about the old value, we're not 			 * equal, because we can't know anything about the 			 * scalar value of the pointer in the new value. 			 */ 			return rold->umin_value == 0 && 			       rold->umax_value == U64_MAX && 			       rold->smin_value == S64_MIN && 			       rold->smax_value == S64_MAX && 			       tnum_is_unknown(rold->var_off); 		} 	case PTR_TO_MAP_VALUE: 		/* If the new min/max/var_off satisfy the old ones and

Fixed version (after fix):
 static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, 			return range_within(rold, rcur) && 			       tnum_in(rold->var_off, rcur->var_off); 		} else { 			/* We're trying to use a pointer in place of a scalar. 			 * Even if the scalar was unbounded, this could lead to 			 * pointer leaks because scalars are allowed to leak 			 * while pointers are not. We could make this safe in 			 * special cases if root is calling us, but it's 			 * probably not worth the hassle. 			 */ 			return false; 		} 	case PTR_TO_MAP_VALUE: 		/* If the new min/max/var_off satisfy the old ones and

Patch:
patch: @@ -3467,15 +3467,14 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
 			return range_within(rold, rcur) &&
 			       tnum_in(rold->var_off, rcur->var_off);
 		} else {
-			/* if we knew anything about the old value, we're not
-			 * equal, because we can't know anything about the
-			 * scalar value of the pointer in the new value.
+			/* We're trying to use a pointer in place of a scalar.
+			 * Even if the scalar was unbounded, this could lead to
+			 * pointer leaks because scalars are allowed to leak
+			 * while pointers are not. We could make this safe in
+			 * special cases if root is calling us, but it's
+			 * probably not worth the hassle.
 			 */
-			return rold->umin_value == 0 &&
-			       rold->umax_value == U64_MAX &&
-			       rold->smin_value == S64_MIN &&
-			       rold->smax_value == S64_MAX &&
-			       tnum_is_unknown(rold->var_off);
+			return false;
 		}
 	case PTR_TO_MAP_VALUE:
 		/* If the new min/max/var_off satisfy the old ones and
path: kernel/bpf/verifier.c