ebpf: verifier: check that call reg with ARG_ANYTHING is initialized
authorDaniel Borkmann <daniel@iogearbox.net>
Thu, 12 Mar 2015 16:21:42 +0000 (17:21 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 12 Mar 2015 19:29:31 +0000 (15:29 -0400)
I noticed that a helper function with argument type ARG_ANYTHING does
not need to have an initialized value (register).

This can worst case lead to unintented stack memory leakage in future
helper functions if they are not carefully designed, or unintended
application behaviour in case the application developer was not careful
enough to match a correct helper function signature in the API.

The underlying issue is that ARG_ANYTHING should actually be split
into two different semantics:

  1) ARG_DONTCARE for function arguments that the helper function
     does not care about (in other words: the default for unused
     function arguments), and

  2) ARG_ANYTHING that is an argument actually being used by a
     helper function and *guaranteed* to be an initialized register.

The current risk is low: ARG_ANYTHING is only used for the 'flags'
argument (r4) in bpf_map_update_elem() that internally does strict
checking.

Fixes: 17a5267067f3 ("bpf: verifier (add verifier core)")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/bpf.h
kernel/bpf/verifier.c

index a884f5a2c5039d381016efc7b4830b8bd294cf0a..80f2e0fc3d02e7983c75019a4f1e8bfd132185d8 100644 (file)
@@ -44,7 +44,7 @@ struct bpf_map_type_list {
 
 /* function argument constraints */
 enum bpf_arg_type {
-       ARG_ANYTHING = 0,       /* any argument is ok */
+       ARG_DONTCARE = 0,       /* unused argument in helper function */
 
        /* the following constraints used to prototype
         * bpf_map_lookup/update/delete_elem() functions
@@ -58,6 +58,8 @@ enum bpf_arg_type {
         */
        ARG_PTR_TO_STACK,       /* any pointer to eBPF program stack */
        ARG_CONST_STACK_SIZE,   /* number of bytes accessed from stack */
+
+       ARG_ANYTHING,           /* any (initialized) argument is ok */
 };
 
 /* type of values returned from helper functions */
index bdf4192a889b1374610de457874877dd3f943c48..e6b522496250373ea1700ceaf8bf801fbff7b66a 100644 (file)
@@ -755,7 +755,7 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
        enum bpf_reg_type expected_type;
        int err = 0;
 
-       if (arg_type == ARG_ANYTHING)
+       if (arg_type == ARG_DONTCARE)
                return 0;
 
        if (reg->type == NOT_INIT) {
@@ -763,6 +763,9 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
                return -EACCES;
        }
 
+       if (arg_type == ARG_ANYTHING)
+               return 0;
+
        if (arg_type == ARG_PTR_TO_STACK || arg_type == ARG_PTR_TO_MAP_KEY ||
            arg_type == ARG_PTR_TO_MAP_VALUE) {
                expected_type = PTR_TO_STACK;