Skip to content

Commit 55a1c95

Browse files
lmbkernel-patches-bot
authored andcommitted
The mapping between bpf_arg_type and bpf_reg_type is encoded in a big
hairy if statement that is hard to follow. The debug output also leaves to be desired: if a reg_type doesn't match we only print one of the options, instead printing all the valid ones. Convert the if statement into a table which is then used to drive type checking. If none of the reg_types match we print all options, e.g.: R2 type=rdonly_buf expected=fp, pkt, pkt_meta, map_value Signed-off-by: Lorenz Bauer <[email protected]> --- include/linux/bpf.h | 1 + kernel/bpf/verifier.c | 189 +++++++++++++++++++++++++----------------- 2 files changed, 116 insertions(+), 74 deletions(-)
1 parent 664cb93 commit 55a1c95

File tree

2 files changed

+116
-74
lines changed

2 files changed

+116
-74
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ enum bpf_arg_type {
292292
ARG_PTR_TO_ALLOC_MEM, /* pointer to dynamically allocated memory */
293293
ARG_PTR_TO_ALLOC_MEM_OR_NULL, /* pointer to dynamically allocated memory or NULL */
294294
ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */
295+
__BPF_ARG_TYPE_MAX,
295296
};
296297

297298
/* type of values returned from helper functions */

kernel/bpf/verifier.c

Lines changed: 115 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,12 +3856,6 @@ static bool arg_type_is_mem_size(enum bpf_arg_type type)
38563856
type == ARG_CONST_SIZE_OR_ZERO;
38573857
}
38583858

3859-
static bool arg_type_is_alloc_mem_ptr(enum bpf_arg_type type)
3860-
{
3861-
return type == ARG_PTR_TO_ALLOC_MEM ||
3862-
type == ARG_PTR_TO_ALLOC_MEM_OR_NULL;
3863-
}
3864-
38653859
static bool arg_type_is_alloc_size(enum bpf_arg_type type)
38663860
{
38673861
return type == ARG_CONST_ALLOC_SIZE_OR_ZERO;
@@ -3910,14 +3904,121 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
39103904
return 0;
39113905
}
39123906

3907+
struct bpf_reg_types {
3908+
const enum bpf_reg_type types[10];
3909+
};
3910+
3911+
static const struct bpf_reg_types map_key_value_types = {
3912+
.types = {
3913+
PTR_TO_STACK,
3914+
PTR_TO_PACKET,
3915+
PTR_TO_PACKET_META,
3916+
PTR_TO_MAP_VALUE,
3917+
},
3918+
};
3919+
3920+
static const struct bpf_reg_types sock_types = {
3921+
.types = {
3922+
PTR_TO_SOCK_COMMON,
3923+
PTR_TO_SOCKET,
3924+
PTR_TO_TCP_SOCK,
3925+
PTR_TO_XDP_SOCK,
3926+
},
3927+
};
3928+
3929+
static const struct bpf_reg_types mem_types = {
3930+
.types = {
3931+
PTR_TO_STACK,
3932+
PTR_TO_PACKET,
3933+
PTR_TO_PACKET_META,
3934+
PTR_TO_MAP_VALUE,
3935+
PTR_TO_MEM,
3936+
PTR_TO_RDONLY_BUF,
3937+
PTR_TO_RDWR_BUF,
3938+
},
3939+
};
3940+
3941+
static const struct bpf_reg_types int_ptr_types = {
3942+
.types = {
3943+
PTR_TO_STACK,
3944+
PTR_TO_PACKET,
3945+
PTR_TO_PACKET_META,
3946+
PTR_TO_MAP_VALUE,
3947+
},
3948+
};
3949+
3950+
static const struct bpf_reg_types fullsock_types = {
3951+
.types = {
3952+
PTR_TO_SOCKET,
3953+
PTR_TO_BTF_ID,
3954+
},
3955+
};
3956+
3957+
static const struct bpf_reg_types scalar_types = { .types = { SCALAR_VALUE } };
3958+
static const struct bpf_reg_types context_types = { .types = { PTR_TO_CTX } };
3959+
static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } };
3960+
static const struct bpf_reg_types const_map_ptr_types = { .types = {CONST_PTR_TO_MAP } };
3961+
static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } };
3962+
static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } };
3963+
3964+
static const struct bpf_reg_types *compatible_reg_types[] = {
3965+
[ARG_PTR_TO_MAP_KEY] = &map_key_value_types,
3966+
[ARG_PTR_TO_MAP_VALUE] = &map_key_value_types,
3967+
[ARG_PTR_TO_UNINIT_MAP_VALUE] = &map_key_value_types,
3968+
[ARG_PTR_TO_MAP_VALUE_OR_NULL] = &map_key_value_types,
3969+
[ARG_CONST_SIZE] = &scalar_types,
3970+
[ARG_CONST_SIZE_OR_ZERO] = &scalar_types,
3971+
[ARG_CONST_ALLOC_SIZE_OR_ZERO] = &scalar_types,
3972+
[ARG_CONST_MAP_PTR] = &const_map_ptr_types,
3973+
[ARG_PTR_TO_CTX] = &context_types,
3974+
[ARG_PTR_TO_CTX_OR_NULL] = &context_types,
3975+
[ARG_PTR_TO_SOCK_COMMON] = &sock_types,
3976+
[ARG_PTR_TO_SOCKET] = &fullsock_types,
3977+
[ARG_PTR_TO_SOCKET_OR_NULL] = &fullsock_types,
3978+
[ARG_PTR_TO_BTF_ID] = &btf_ptr_types,
3979+
[ARG_PTR_TO_SPIN_LOCK] = &spin_lock_types,
3980+
[ARG_PTR_TO_MEM] = &mem_types,
3981+
[ARG_PTR_TO_MEM_OR_NULL] = &mem_types,
3982+
[ARG_PTR_TO_UNINIT_MEM] = &mem_types,
3983+
[ARG_PTR_TO_ALLOC_MEM] = &alloc_mem_types,
3984+
[ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types,
3985+
[ARG_PTR_TO_INT] = &int_ptr_types,
3986+
[ARG_PTR_TO_LONG] = &int_ptr_types,
3987+
[__BPF_ARG_TYPE_MAX] = NULL,
3988+
};
3989+
3990+
static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
3991+
const struct bpf_reg_types *compatible)
3992+
{
3993+
struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
3994+
enum bpf_reg_type expected, type = reg->type;
3995+
int i, j;
3996+
3997+
for (i = 0; i < ARRAY_SIZE(compatible->types); i++) {
3998+
expected = compatible->types[i];
3999+
if (expected == NOT_INIT)
4000+
break;
4001+
4002+
if (type == expected)
4003+
return 0;
4004+
}
4005+
4006+
verbose(env, "R%d type=%s expected=", regno, reg_type_str[type]);
4007+
for (j = 0; j + 1 < i; j++)
4008+
verbose(env, "%s, ", reg_type_str[compatible->types[j]]);
4009+
verbose(env, "%s\n", reg_type_str[compatible->types[j]]);
4010+
return -EACCES;
4011+
}
4012+
39134013
static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
39144014
struct bpf_call_arg_meta *meta,
39154015
const struct bpf_func_proto *fn)
39164016
{
39174017
u32 regno = BPF_REG_1 + arg;
39184018
struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
3919-
enum bpf_reg_type expected_type, type = reg->type;
39204019
enum bpf_arg_type arg_type = fn->arg_type[arg];
4020+
const struct bpf_reg_types *compatible;
4021+
enum bpf_reg_type type = reg->type;
39214022
int err = 0;
39224023

39234024
if (arg_type == ARG_DONTCARE)
@@ -3956,72 +4057,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
39564057
*/
39574058
goto skip_type_check;
39584059

3959-
if (arg_type == ARG_PTR_TO_MAP_KEY ||
3960-
arg_type == ARG_PTR_TO_MAP_VALUE ||
3961-
arg_type == ARG_PTR_TO_UNINIT_MAP_VALUE ||
3962-
arg_type == ARG_PTR_TO_MAP_VALUE_OR_NULL) {
3963-
expected_type = PTR_TO_STACK;
3964-
if (!type_is_pkt_pointer(type) &&
3965-
type != PTR_TO_MAP_VALUE &&
3966-
type != expected_type)
3967-
goto err_type;
3968-
} else if (arg_type == ARG_CONST_SIZE ||
3969-
arg_type == ARG_CONST_SIZE_OR_ZERO ||
3970-
arg_type == ARG_CONST_ALLOC_SIZE_OR_ZERO) {
3971-
expected_type = SCALAR_VALUE;
3972-
if (type != expected_type)
3973-
goto err_type;
3974-
} else if (arg_type == ARG_CONST_MAP_PTR) {
3975-
expected_type = CONST_PTR_TO_MAP;
3976-
if (type != expected_type)
3977-
goto err_type;
3978-
} else if (arg_type == ARG_PTR_TO_CTX ||
3979-
arg_type == ARG_PTR_TO_CTX_OR_NULL) {
3980-
expected_type = PTR_TO_CTX;
3981-
if (type != expected_type)
3982-
goto err_type;
3983-
} else if (arg_type == ARG_PTR_TO_SOCK_COMMON) {
3984-
expected_type = PTR_TO_SOCK_COMMON;
3985-
/* Any sk pointer can be ARG_PTR_TO_SOCK_COMMON */
3986-
if (!type_is_sk_pointer(type))
3987-
goto err_type;
3988-
} else if (arg_type == ARG_PTR_TO_SOCKET ||
3989-
arg_type == ARG_PTR_TO_SOCKET_OR_NULL) {
3990-
expected_type = PTR_TO_SOCKET;
3991-
if (type != expected_type)
3992-
goto err_type;
3993-
} else if (arg_type == ARG_PTR_TO_BTF_ID) {
3994-
expected_type = PTR_TO_BTF_ID;
3995-
if (type != expected_type)
3996-
goto err_type;
3997-
} else if (arg_type == ARG_PTR_TO_SPIN_LOCK) {
3998-
expected_type = PTR_TO_MAP_VALUE;
3999-
if (type != expected_type)
4000-
goto err_type;
4001-
} else if (arg_type_is_mem_ptr(arg_type)) {
4002-
expected_type = PTR_TO_STACK;
4003-
if (!type_is_pkt_pointer(type) &&
4004-
type != PTR_TO_MAP_VALUE &&
4005-
type != PTR_TO_MEM &&
4006-
type != PTR_TO_RDONLY_BUF &&
4007-
type != PTR_TO_RDWR_BUF &&
4008-
type != expected_type)
4009-
goto err_type;
4010-
} else if (arg_type_is_alloc_mem_ptr(arg_type)) {
4011-
expected_type = PTR_TO_MEM;
4012-
if (type != expected_type)
4013-
goto err_type;
4014-
} else if (arg_type_is_int_ptr(arg_type)) {
4015-
expected_type = PTR_TO_STACK;
4016-
if (!type_is_pkt_pointer(type) &&
4017-
type != PTR_TO_MAP_VALUE &&
4018-
type != expected_type)
4019-
goto err_type;
4020-
} else {
4021-
verbose(env, "unsupported arg_type %d\n", arg_type);
4060+
compatible = compatible_reg_types[arg_type];
4061+
if (!compatible) {
4062+
verbose(env, "verifier internal error: unsupported arg type %d\n", arg_type);
40224063
return -EFAULT;
40234064
}
40244065

4066+
err = check_reg_type(env, regno, compatible);
4067+
if (err)
4068+
return err;
4069+
40254070
if (type == PTR_TO_BTF_ID) {
40264071
const u32 *btf_id = fn->arg_btf_id[arg];
40274072

@@ -4174,10 +4219,6 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
41744219
}
41754220

41764221
return err;
4177-
err_type:
4178-
verbose(env, "R%d type=%s expected=%s\n", regno,
4179-
reg_type_str[type], reg_type_str[expected_type]);
4180-
return -EACCES;
41814222
}
41824223

41834224
static bool may_update_sockmap(struct bpf_verifier_env *env, int func_id)

0 commit comments

Comments
 (0)