[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200912045924.2992997-1-kafai@fb.com>
Date: Fri, 11 Sep 2020 21:59:24 -0700
From: Martin KaFai Lau <kafai@...com>
To: <bpf@...r.kernel.org>
CC: Alexei Starovoitov <ast@...nel.org>,
Daniel Borkmann <daniel@...earbox.net>, <kernel-team@...com>,
Lorenz Bauer <lmb@...udflare.com>, <netdev@...r.kernel.org>
Subject: [PATCH RFC bpf-next 1/2] bpf: Move the PTR_TO_BTF_ID check to check_reg_type()
check_reg_type() checks whether a reg can be used as an arg of a
func_proto. For PTR_TO_BTF_ID, the check is actually not
completely done until the reg->btf_id is pointing to a
kernel struct that is acceptable by the func_proto.
Thus, this patch moves the btf_id check into check_reg_type().
The compatible_reg_types[] usage is localized in check_reg_type()
now which I found it easier to reason in the next patch.
The "if (!btf_id) verbose(...); " is removed for now since it won't
happen. It will be added back in the next patch with new error log
specific to mis-configured compatible_reg_types[].
Signed-off-by: Martin KaFai Lau <kafai@...com>
---
kernel/bpf/verifier.c | 65 +++++++++++++++++++++++--------------------
1 file changed, 35 insertions(+), 30 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8fdef5656e7f..3a5932bd7c22 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3981,20 +3981,29 @@ static const struct bpf_reg_types *compatible_reg_types[] = {
[__BPF_ARG_TYPE_MAX] = NULL,
};
-static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
- const struct bpf_reg_types *compatible)
+static int check_reg_type(struct bpf_verifier_env *env, u32 arg,
+ enum bpf_arg_type arg_type,
+ const struct bpf_func_proto *fn)
{
+ u32 regno = BPF_REG_1 + arg;
struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
enum bpf_reg_type expected, type = reg->type;
+ const struct bpf_reg_types *compatible;
int i, j;
+ compatible = compatible_reg_types[arg_type];
+ if (!compatible) {
+ verbose(env, "verifier internal error: unsupported arg type %d\n", arg_type);
+ return -EFAULT;
+ }
+
for (i = 0; i < ARRAY_SIZE(compatible->types); i++) {
expected = compatible->types[i];
if (expected == NOT_INIT)
break;
if (type == expected)
- return 0;
+ goto found;
}
verbose(env, "R%d type=%s expected=", regno, reg_type_str[type]);
@@ -4002,6 +4011,27 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
verbose(env, "%s, ", reg_type_str[compatible->types[j]]);
verbose(env, "%s\n", reg_type_str[compatible->types[j]]);
return -EACCES;
+
+found:
+ if (type == PTR_TO_BTF_ID) {
+ u32 *expected_btf_id = fn->arg_btf_id[arg];
+
+ if (!btf_struct_ids_match(&env->log, reg->off, reg->btf_id,
+ *expected_btf_id)) {
+ verbose(env, "R%d is a pointer to in-kernel struct %s but %s is expected instead\n",
+ regno, kernel_type_name(reg->btf_id),
+ kernel_type_name(*expected_btf_id));
+ return -EACCES;
+ }
+
+ if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
+ verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
+ regno);
+ return -EACCES;
+ }
+ }
+
+ return 0;
}
static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
@@ -4011,7 +4041,6 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
u32 regno = BPF_REG_1 + arg;
struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
enum bpf_arg_type arg_type = fn->arg_type[arg];
- const struct bpf_reg_types *compatible;
enum bpf_reg_type type = reg->type;
int err = 0;
@@ -4051,35 +4080,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
*/
goto skip_type_check;
- compatible = compatible_reg_types[arg_type];
- if (!compatible) {
- verbose(env, "verifier internal error: unsupported arg type %d\n", arg_type);
- return -EFAULT;
- }
-
- err = check_reg_type(env, regno, compatible);
+ err = check_reg_type(env, arg, arg_type, fn);
if (err)
return err;
- if (type == PTR_TO_BTF_ID) {
- const u32 *btf_id = fn->arg_btf_id[arg];
-
- if (!btf_id) {
- verbose(env, "verifier internal error: missing BTF ID\n");
- return -EFAULT;
- }
-
- if (!btf_struct_ids_match(&env->log, reg->off, reg->btf_id, *btf_id)) {
- verbose(env, "R%d has incompatible type %s\n", regno,
- kernel_type_name(reg->btf_id));
- return -EACCES;
- }
- if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
- verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
- regno);
- return -EACCES;
- }
- } else if (type == PTR_TO_CTX) {
+ if (type == PTR_TO_CTX) {
err = check_ctx_reg(env, reg, regno);
if (err < 0)
return err;
--
2.24.1
Powered by blists - more mailing lists