summaryrefslogtreecommitdiffstats
path: root/kernel/bpf
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2019-04-04 02:22:39 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2019-04-05 10:50:07 -0400
commit088ec26d9c2da9d879ab73e3f4117f9df6c566ee (patch)
treec7965d3ac5707279af5d842e99d37e474a4e8d73 /kernel/bpf
parentf68a5b44647bce6c34b10d5560c5b2c0aff31afc (diff)
bpf: Reject indirect var_off stack access in unpriv mode
Proper support of indirect stack access with variable offset in unprivileged mode (!root) requires corresponding support in Spectre masking for stack ALU in retrieve_ptr_limit(). There are no use-case for variable offset in unprivileged mode though so make verifier reject such accesses for simplicity. Pointer arithmetics is one (and only?) way to cause variable offset and it's already rejected in unpriv mode so that verifier won't even get to helper function whose argument contains variable offset, e.g.: 0: (7a) *(u64 *)(r10 -16) = 0 1: (7a) *(u64 *)(r10 -8) = 0 2: (61) r2 = *(u32 *)(r1 +0) 3: (57) r2 &= 4 4: (17) r2 -= 16 5: (0f) r2 += r10 variable stack access var_off=(0xfffffffffffffff0; 0x4) off=-16 size=1R2 stack pointer arithmetic goes out of range, prohibited for !root Still it looks like a good idea to reject variable offset indirect stack access for unprivileged mode in check_stack_boundary() explicitly. Fixes: 2011fccfb61b ("bpf: Support variable offset stack access from helpers") Reported-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel/bpf')
-rw-r--r--kernel/bpf/verifier.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 0f12fda35626..8400c1f33cd4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2226,6 +2226,19 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
2226 if (err) 2226 if (err)
2227 return err; 2227 return err;
2228 } else { 2228 } else {
2229 /* Variable offset is prohibited for unprivileged mode for
2230 * simplicity since it requires corresponding support in
2231 * Spectre masking for stack ALU.
2232 * See also retrieve_ptr_limit().
2233 */
2234 if (!env->allow_ptr_leaks) {
2235 char tn_buf[48];
2236
2237 tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
2238 verbose(env, "R%d indirect variable offset stack access prohibited for !root, var_off=%s\n",
2239 regno, tn_buf);
2240 return -EACCES;
2241 }
2229 /* Only initialized buffer on stack is allowed to be accessed 2242 /* Only initialized buffer on stack is allowed to be accessed
2230 * with variable offset. With uninitialized buffer it's hard to 2243 * with variable offset. With uninitialized buffer it's hard to
2231 * guarantee that whole memory is marked as initialized on 2244 * guarantee that whole memory is marked as initialized on
@@ -3339,6 +3352,9 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
3339 3352
3340 switch (ptr_reg->type) { 3353 switch (ptr_reg->type) {
3341 case PTR_TO_STACK: 3354 case PTR_TO_STACK:
3355 /* Indirect variable offset stack access is prohibited in
3356 * unprivileged mode so it's not handled here.
3357 */
3342 off = ptr_reg->off + ptr_reg->var_off.value; 3358 off = ptr_reg->off + ptr_reg->var_off.value;
3343 if (mask_to_left) 3359 if (mask_to_left)
3344 *ptr_limit = MAX_BPF_STACK + off; 3360 *ptr_limit = MAX_BPF_STACK + off;