aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2019-03-18 19:57:10 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-04-12 16:54:59 -0400
commit57c3bb725a3dd97d960d7e1cd0845d88de53217f (patch)
treedfe95f1ef2311cd1426916df144922892135c9c1
parent9a1027e52535db1a0adf7831afdfce745dc0a061 (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.h2
-rw-r--r--kernel/bpf/verifier.c29
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
2465static 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
2471static 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
2465static int check_func_arg(struct bpf_verifier_env *env, u32 regno, 2481static 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;