From: Yonghong Song <yhs@fb.com>
To: <ast@fb.com>, <daniel@iogearbox.net>, <netdev@vger.kernel.org>
Cc: <kernel-team@fb.com>
Subject: [PATCH bpf-next v2 3/9] bpf/verifier: refine retval R0 state for bpf_get_stack helper
Date: Wed, 18 Apr 2018 09:54:38 -0700 [thread overview]
Message-ID: <20180418165444.2263237-4-yhs@fb.com> (raw)
In-Reply-To: <20180418165444.2263237-1-yhs@fb.com>
The special property of return values for helpers bpf_get_stack
and bpf_probe_read_str are captured in verifier.
Both helpers return a negative error code or
a length, which is equal to or smaller than the buffer
size argument. This additional information in the
verifier can avoid the condition such as "retval > bufsize"
in the bpf program. For example, for the code blow,
usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK);
if (usize < 0 || usize > max_len)
return 0;
The verifier may have the following errors:
52: (85) call bpf_get_stack#65
R0=map_value(id=0,off=0,ks=4,vs=1600,imm=0) R1_w=ctx(id=0,off=0,imm=0)
R2_w=map_value(id=0,off=0,ks=4,vs=1600,imm=0) R3_w=inv800 R4_w=inv256
R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=1600,imm=0)
R9_w=inv800 R10=fp0,call_-1
53: (bf) r8 = r0
54: (bf) r1 = r8
55: (67) r1 <<= 32
56: (bf) r2 = r1
57: (77) r2 >>= 32
58: (25) if r2 > 0x31f goto pc+33
R0=inv(id=0) R1=inv(id=0,smax_value=9223372032559808512,
umax_value=18446744069414584320,
var_off=(0x0; 0xffffffff00000000))
R2=inv(id=0,umax_value=799,var_off=(0x0; 0x3ff))
R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=1600,imm=0)
R8=inv(id=0) R9=inv800 R10=fp0,call_-1
59: (1f) r9 -= r8
60: (c7) r1 s>>= 32
61: (bf) r2 = r7
62: (0f) r2 += r1
math between map_value pointer and register with unbounded
min value is not allowed
The failure is due to llvm compiler optimization where register "r2",
which is a copy of "r1", is tested for condition while later on "r1"
is used for map_ptr operation. The verifier is not able to track such
inst sequence effectively.
Without the "usize > max_len" condition, there is no llvm optimization
and the below generated code passed verifier:
52: (85) call bpf_get_stack#65
R0=map_value(id=0,off=0,ks=4,vs=1600,imm=0) R1_w=ctx(id=0,off=0,imm=0)
R2_w=map_value(id=0,off=0,ks=4,vs=1600,imm=0) R3_w=inv800 R4_w=inv256
R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=1600,imm=0)
R9_w=inv800 R10=fp0,call_-1
53: (b7) r1 = 0
54: (bf) r8 = r0
55: (67) r8 <<= 32
56: (c7) r8 s>>= 32
57: (6d) if r1 s> r8 goto pc+24
R0=inv(id=0,umax_value=800) R1=inv0 R6=ctx(id=0,off=0,imm=0)
R7=map_value(id=0,off=0,ks=4,vs=1600,imm=0)
R8=inv(id=0,umax_value=800,var_off=(0x0; 0x3ff)) R9=inv800
R10=fp0,call_-1
58: (bf) r2 = r7
59: (0f) r2 += r8
60: (1f) r9 -= r8
61: (bf) r1 = r6
Signed-off-by: Yonghong Song <yhs@fb.com>
---
kernel/bpf/verifier.c | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index aba9425..a8302c3 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2333,10 +2333,32 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
return 0;
}
+static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type,
+ int func_id,
+ struct bpf_reg_state *retval_state,
+ bool is_check)
+{
+ struct bpf_reg_state *src_reg, *dst_reg;
+
+ if (ret_type != RET_INTEGER ||
+ (func_id != BPF_FUNC_get_stack &&
+ func_id != BPF_FUNC_probe_read_str))
+ return;
+
+ dst_reg = is_check ? retval_state : ®s[BPF_REG_0];
+ if (func_id == BPF_FUNC_get_stack)
+ src_reg = is_check ? ®s[BPF_REG_3] : retval_state;
+ else
+ src_reg = is_check ? ®s[BPF_REG_2] : retval_state;
+
+ dst_reg->smax_value = src_reg->smax_value;
+ dst_reg->umax_value = src_reg->umax_value;
+}
+
static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn_idx)
{
const struct bpf_func_proto *fn = NULL;
- struct bpf_reg_state *regs;
+ struct bpf_reg_state *regs, retval_state;
struct bpf_call_arg_meta meta;
bool changes_data;
int i, err;
@@ -2415,6 +2437,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
}
regs = cur_regs(env);
+
+ /* before reset caller saved regs, check special ret value */
+ do_refine_retval_range(regs, fn->ret_type, func_id, &retval_state, 1);
+
/* reset caller saved regs */
for (i = 0; i < CALLER_SAVED_REGS; i++) {
mark_reg_not_init(env, regs, caller_saved[i]);
@@ -2456,6 +2482,9 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
return -EINVAL;
}
+ /* apply additional constraints to ret value */
+ do_refine_retval_range(regs, fn->ret_type, func_id, &retval_state, 0);
+
err = check_map_func_compatibility(env, meta.map_ptr, func_id);
if (err)
return err;
--
2.9.5
next prev parent reply other threads:[~2018-04-18 16:54 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-18 16:54 [PATCH bpf-next v2 0/9] bpf: add bpf_get_stack helper Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 1/9] bpf: change prototype for stack_map_get_build_id_offset Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 2/9] bpf: add bpf_get_stack helper Yonghong Song
2018-04-19 4:26 ` Alexei Starovoitov
2018-04-18 16:54 ` Yonghong Song [this message]
2018-04-19 4:33 ` [PATCH bpf-next v2 3/9] bpf/verifier: refine retval R0 state for " Alexei Starovoitov
2018-04-19 23:37 ` Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 4/9] bpf/verifier: improve register value range tracking with ARSH Yonghong Song
2018-04-19 4:35 ` Alexei Starovoitov
2018-04-19 23:39 ` Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 5/9] tools/bpf: add bpf_get_stack helper to tools headers Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 6/9] samples/bpf: move common-purpose perf_event functions to bpf_load.c Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 7/9] samples/bpf: add a test for bpf_get_stack helper Yonghong Song
2018-04-19 4:37 ` Alexei Starovoitov
2018-04-19 23:42 ` Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 8/9] tools/bpf: add a verifier test case for bpf_get_stack helper and ARSH Yonghong Song
2018-04-18 16:54 ` [PATCH bpf-next v2 9/9] tools/bpf: add a test_progs test case for bpf_get_stack helper Yonghong Song
2018-04-19 4:39 ` Alexei Starovoitov
2018-04-19 23:42 ` Yonghong Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180418165444.2263237-4-yhs@fb.com \
--to=yhs@fb.com \
--cc=ast@fb.com \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.