bpf: Introduce ARG_PTR_TO_{INT,LONG} arg types
Currently the way to pass result from BPF helper to BPF program is to provide memory area defined by pointer and size: func(void *, size_t). It works great for generic use-case, but for simple types, such as int, it's overkill and consumes two arguments when it could use just one. Introduce new argument types ARG_PTR_TO_INT and ARG_PTR_TO_LONG to be able to pass result from helper to program via pointer to int and long correspondingly: func(int *) or func(long *). New argument types are similar to ARG_PTR_TO_MEM with the following differences: * they don't require corresponding ARG_CONST_SIZE argument, predefined access sizes are used instead (32bit for int, 64bit for long); * it's possible to use more than one such an argument in a helper; * provided pointers have to be aligned. It's easy to introduce similar ARG_PTR_TO_CHAR and ARG_PTR_TO_SHORT argument types. It's not done due to lack of use-case though. Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
9a1027e525
commit
57c3bb725a
|
@ -202,6 +202,8 @@ enum bpf_arg_type {
|
|||
ARG_ANYTHING, /* any (initialized) argument is ok */
|
||||
ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */
|
||||
ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */
|
||||
ARG_PTR_TO_INT, /* pointer to int */
|
||||
ARG_PTR_TO_LONG, /* pointer to long */
|
||||
};
|
||||
|
||||
/* type of values returned from helper functions */
|
||||
|
|
|
@ -2462,6 +2462,22 @@ static bool arg_type_is_mem_size(enum bpf_arg_type type)
|
|||
type == ARG_CONST_SIZE_OR_ZERO;
|
||||
}
|
||||
|
||||
static bool arg_type_is_int_ptr(enum bpf_arg_type type)
|
||||
{
|
||||
return type == ARG_PTR_TO_INT ||
|
||||
type == ARG_PTR_TO_LONG;
|
||||
}
|
||||
|
||||
static int int_ptr_type_to_size(enum bpf_arg_type type)
|
||||
{
|
||||
if (type == ARG_PTR_TO_INT)
|
||||
return sizeof(u32);
|
||||
else if (type == ARG_PTR_TO_LONG)
|
||||
return sizeof(u64);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
||||
enum bpf_arg_type arg_type,
|
||||
struct bpf_call_arg_meta *meta)
|
||||
|
@ -2554,6 +2570,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
|||
type != expected_type)
|
||||
goto err_type;
|
||||
meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM;
|
||||
} else if (arg_type_is_int_ptr(arg_type)) {
|
||||
expected_type = PTR_TO_STACK;
|
||||
if (!type_is_pkt_pointer(type) &&
|
||||
type != PTR_TO_MAP_VALUE &&
|
||||
type != expected_type)
|
||||
goto err_type;
|
||||
} else {
|
||||
verbose(env, "unsupported arg_type %d\n", arg_type);
|
||||
return -EFAULT;
|
||||
|
@ -2635,6 +2657,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
|||
err = check_helper_mem_access(env, regno - 1,
|
||||
reg->umax_value,
|
||||
zero_size_allowed, meta);
|
||||
} else if (arg_type_is_int_ptr(arg_type)) {
|
||||
int size = int_ptr_type_to_size(arg_type);
|
||||
|
||||
err = check_helper_mem_access(env, regno, size, false, meta);
|
||||
if (err)
|
||||
return err;
|
||||
err = check_ptr_alignment(env, reg, 0, size, true);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
Loading…
Reference in New Issue