diff options
author | Andrey Ignatov <rdna@fb.com> | 2019-03-18 19:57:10 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2019-04-12 16:54:59 -0400 |
commit | 57c3bb725a3dd97d960d7e1cd0845d88de53217f (patch) | |
tree | dfe95f1ef2311cd1426916df144922892135c9c1 | |
parent | 9a1027e52535db1a0adf7831afdfce745dc0a061 (diff) |
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>
-rw-r--r-- | include/linux/bpf.h | 2 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 29 |
2 files changed, 31 insertions, 0 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index e4d4c1771ab0..fd06ada941ad 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h | |||
@@ -202,6 +202,8 @@ enum bpf_arg_type { | |||
202 | ARG_ANYTHING, /* any (initialized) argument is ok */ | 202 | ARG_ANYTHING, /* any (initialized) argument is ok */ |
203 | ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */ | 203 | ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */ |
204 | ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */ | 204 | ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */ |
205 | ARG_PTR_TO_INT, /* pointer to int */ | ||
206 | ARG_PTR_TO_LONG, /* pointer to long */ | ||
205 | }; | 207 | }; |
206 | 208 | ||
207 | /* type of values returned from helper functions */ | 209 | /* type of values returned from helper functions */ |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 20808e3c95a8..15ab6fa817ce 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -2462,6 +2462,22 @@ static bool arg_type_is_mem_size(enum bpf_arg_type type) | |||
2462 | type == ARG_CONST_SIZE_OR_ZERO; | 2462 | type == ARG_CONST_SIZE_OR_ZERO; |
2463 | } | 2463 | } |
2464 | 2464 | ||
2465 | static bool arg_type_is_int_ptr(enum bpf_arg_type type) | ||
2466 | { | ||
2467 | return type == ARG_PTR_TO_INT || | ||
2468 | type == ARG_PTR_TO_LONG; | ||
2469 | } | ||
2470 | |||
2471 | static int int_ptr_type_to_size(enum bpf_arg_type type) | ||
2472 | { | ||
2473 | if (type == ARG_PTR_TO_INT) | ||
2474 | return sizeof(u32); | ||
2475 | else if (type == ARG_PTR_TO_LONG) | ||
2476 | return sizeof(u64); | ||
2477 | |||
2478 | return -EINVAL; | ||
2479 | } | ||
2480 | |||
2465 | static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | 2481 | static int check_func_arg(struct bpf_verifier_env *env, u32 regno, |
2466 | enum bpf_arg_type arg_type, | 2482 | enum bpf_arg_type arg_type, |
2467 | struct bpf_call_arg_meta *meta) | 2483 | struct bpf_call_arg_meta *meta) |
@@ -2554,6 +2570,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | |||
2554 | type != expected_type) | 2570 | type != expected_type) |
2555 | goto err_type; | 2571 | goto err_type; |
2556 | meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM; | 2572 | meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM; |
2573 | } else if (arg_type_is_int_ptr(arg_type)) { | ||
2574 | expected_type = PTR_TO_STACK; | ||
2575 | if (!type_is_pkt_pointer(type) && | ||
2576 | type != PTR_TO_MAP_VALUE && | ||
2577 | type != expected_type) | ||
2578 | goto err_type; | ||
2557 | } else { | 2579 | } else { |
2558 | verbose(env, "unsupported arg_type %d\n", arg_type); | 2580 | verbose(env, "unsupported arg_type %d\n", arg_type); |
2559 | return -EFAULT; | 2581 | return -EFAULT; |
@@ -2635,6 +2657,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | |||
2635 | err = check_helper_mem_access(env, regno - 1, | 2657 | err = check_helper_mem_access(env, regno - 1, |
2636 | reg->umax_value, | 2658 | reg->umax_value, |
2637 | zero_size_allowed, meta); | 2659 | zero_size_allowed, meta); |
2660 | } else if (arg_type_is_int_ptr(arg_type)) { | ||
2661 | int size = int_ptr_type_to_size(arg_type); | ||
2662 | |||
2663 | err = check_helper_mem_access(env, regno, size, false, meta); | ||
2664 | if (err) | ||
2665 | return err; | ||
2666 | err = check_ptr_alignment(env, reg, 0, size, true); | ||
2638 | } | 2667 | } |
2639 | 2668 | ||
2640 | return err; | 2669 | return err; |