Re: [PATCH bpf-next v1 1/7] bpf: Add MEM_UNINIT as a bpf_type_flag

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Apr 1, 2022 at 7:00 PM Joanne Koong <joannekoong@xxxxxx> wrote:
>
> From: Joanne Koong <joannelkoong@xxxxxxxxx>
>
> Instead of having uninitialized versions of arguments as separate
> bpf_arg_types (eg ARG_PTR_TO_UNINIT_MEM as the uninitialized version
> of ARG_PTR_TO_MEM), we can instead use MEM_UNINIT as a bpf_type_flag
> modifier to denote that the argument is uninitialized.
>
> Doing so cleans up some of the logic in the verifier. We no longer
> need to do two checks against an argument type (eg "if
> (base_type(arg_type) == ARG_PTR_TO_MEM || base_type(arg_type) ==
> ARG_PTR_TO_UNINIT_MEM)"), since uninitialized and initialized
> versions of the same argument type will now share the same base type.
>
> In the near future, MEM_UNINIT will be used by dynptr helper functions
> as well.
>
> Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx>
> ---
>  include/linux/bpf.h      | 19 +++++++++++--------
>  kernel/bpf/bpf_lsm.c     |  4 ++--
>  kernel/bpf/cgroup.c      |  4 ++--
>  kernel/bpf/helpers.c     | 12 ++++++------
>  kernel/bpf/stackmap.c    |  6 +++---
>  kernel/bpf/verifier.c    | 25 ++++++++++---------------
>  kernel/trace/bpf_trace.c | 20 ++++++++++----------
>  net/core/filter.c        | 26 +++++++++++++-------------
>  8 files changed, 57 insertions(+), 59 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index bdb5298735ce..6f2558da9d4a 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -342,7 +342,9 @@ enum bpf_type_flag {
>          */
>         MEM_PERCPU              = BIT(4 + BPF_BASE_TYPE_BITS),
>
> -       __BPF_TYPE_LAST_FLAG    = MEM_PERCPU,
> +       MEM_UNINIT              = BIT(5 + BPF_BASE_TYPE_BITS),
> +
> +       __BPF_TYPE_LAST_FLAG    = MEM_UNINIT,
>  };
>
>  /* Max number of base types. */
> @@ -361,16 +363,11 @@ enum bpf_arg_type {
>         ARG_CONST_MAP_PTR,      /* const argument used as pointer to bpf_map */
>         ARG_PTR_TO_MAP_KEY,     /* pointer to stack used as map key */
>         ARG_PTR_TO_MAP_VALUE,   /* pointer to stack used as map value */
> -       ARG_PTR_TO_UNINIT_MAP_VALUE,    /* pointer to valid memory used to store a map value */
>
> -       /* the following constraints used to prototype bpf_memcmp() and other
> -        * functions that access data on eBPF program stack
> +       /* Used to prototype bpf_memcmp() and other functions that access data
> +        * on eBPF program stack
>          */
>         ARG_PTR_TO_MEM,         /* pointer to valid memory (stack, packet, map value) */
> -       ARG_PTR_TO_UNINIT_MEM,  /* pointer to memory does not need to be initialized,
> -                                * helper function must fill all bytes or clear
> -                                * them in error case.
> -                                */
>
>         ARG_CONST_SIZE,         /* number of bytes accessed from memory */
>         ARG_CONST_SIZE_OR_ZERO, /* number of bytes accessed from memory or 0 */
> @@ -400,6 +397,12 @@ enum bpf_arg_type {
>         ARG_PTR_TO_SOCKET_OR_NULL       = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
>         ARG_PTR_TO_ALLOC_MEM_OR_NULL    = PTR_MAYBE_NULL | ARG_PTR_TO_ALLOC_MEM,
>         ARG_PTR_TO_STACK_OR_NULL        = PTR_MAYBE_NULL | ARG_PTR_TO_STACK,
> +       /* pointer to valid memory used to store a map value */
> +       ARG_PTR_TO_MAP_VALUE_UNINIT     = MEM_UNINIT | ARG_PTR_TO_MAP_VALUE,

seeing how this "alias" is used only in few places, I'd just use
`ARG_PTR_TO_MAP_VALUE | MEM_UNINIT` directly in prototype declaration
and the MEM_UNINIT flag directly in verifier logic.

> +       /* pointer to memory does not need to be initialized, helper function must fill
> +        * all bytes or clear them in error case.
> +        */
> +       ARG_PTR_TO_MEM_UNINIT           = MEM_UNINIT | ARG_PTR_TO_MEM,
>
>         /* This must be the last entry. Its purpose is to ensure the enum is
>          * wide enough to hold the higher bits reserved for bpf_type_flag.

[...]

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index d175b70067b3..90280d5666be 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5136,8 +5136,7 @@ static int process_timer_func(struct bpf_verifier_env *env, int regno,
>
>  static bool arg_type_is_mem_ptr(enum bpf_arg_type type)
>  {
> -       return base_type(type) == ARG_PTR_TO_MEM ||
> -              base_type(type) == ARG_PTR_TO_UNINIT_MEM;
> +       return base_type(type) == ARG_PTR_TO_MEM;
>  }

Is this helper function even useful anymore? I'd just drop this
function altogether.

>
>  static bool arg_type_is_mem_size(enum bpf_arg_type type)
> @@ -5273,7 +5272,6 @@ static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE }
>  static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
>         [ARG_PTR_TO_MAP_KEY]            = &map_key_value_types,
>         [ARG_PTR_TO_MAP_VALUE]          = &map_key_value_types,
> -       [ARG_PTR_TO_UNINIT_MAP_VALUE]   = &map_key_value_types,
>         [ARG_CONST_SIZE]                = &scalar_types,
>         [ARG_CONST_SIZE_OR_ZERO]        = &scalar_types,
>         [ARG_CONST_ALLOC_SIZE_OR_ZERO]  = &scalar_types,
> @@ -5287,7 +5285,6 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
>         [ARG_PTR_TO_BTF_ID]             = &btf_ptr_types,
>         [ARG_PTR_TO_SPIN_LOCK]          = &spin_lock_types,
>         [ARG_PTR_TO_MEM]                = &mem_types,
> -       [ARG_PTR_TO_UNINIT_MEM]         = &mem_types,
>         [ARG_PTR_TO_ALLOC_MEM]          = &alloc_mem_types,
>         [ARG_PTR_TO_INT]                = &int_ptr_types,
>         [ARG_PTR_TO_LONG]               = &int_ptr_types,
> @@ -5451,8 +5448,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
>                 return -EACCES;
>         }
>
> -       if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE ||
> -           base_type(arg_type) == ARG_PTR_TO_UNINIT_MAP_VALUE) {
> +       if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {
>                 err = resolve_map_arg_type(env, meta, &arg_type);
>                 if (err)
>                         return err;
> @@ -5528,8 +5524,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
>                 err = check_helper_mem_access(env, regno,
>                                               meta->map_ptr->key_size, false,
>                                               NULL);
> -       } else if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE ||
> -                  base_type(arg_type) == ARG_PTR_TO_UNINIT_MAP_VALUE) {
> +       } else if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {
>                 if (type_may_be_null(arg_type) && register_is_null(reg))
>                         return 0;
>
> @@ -5541,7 +5536,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
>                         verbose(env, "invalid map_ptr to access map->value\n");
>                         return -EACCES;
>                 }
> -               meta->raw_mode = (arg_type == ARG_PTR_TO_UNINIT_MAP_VALUE);
> +               meta->raw_mode = (arg_type == ARG_PTR_TO_MAP_VALUE_UNINIT);
>                 err = check_helper_mem_access(env, regno,
>                                               meta->map_ptr->value_size, false,
>                                               meta);
> @@ -5572,7 +5567,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
>                 /* The access to this pointer is only checked when we hit the
>                  * next is_mem_size argument below.
>                  */
> -               meta->raw_mode = (arg_type == ARG_PTR_TO_UNINIT_MEM);
> +               meta->raw_mode = (arg_type == ARG_PTR_TO_MEM_UNINIT);

aside: raw_mode is a horrible name that communicates literally nothing
towards its semantics (IMO), would be nice to fix that, I'm always
confused by it

>         } else if (arg_type_is_mem_size(arg_type)) {
>                 bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);
>

[...]

> @@ -1406,7 +1406,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {
>         .gpl_only       = true,
>         .ret_type       = RET_INTEGER,
>         .arg1_type      = ARG_PTR_TO_CTX,
> -       .arg2_type      = ARG_PTR_TO_UNINIT_MEM,
> +       .arg2_type      = ARG_PTR_TO_MEM_UNINIT,
>         .arg3_type      = ARG_CONST_SIZE_OR_ZERO,
>         .arg4_type      = ARG_ANYTHING,
>  };
> @@ -1473,7 +1473,7 @@ static const struct bpf_func_proto bpf_perf_prog_read_value_proto = {
>           .gpl_only       = true,
>           .ret_type       = RET_INTEGER,
>           .arg1_type      = ARG_PTR_TO_CTX,
> -         .arg2_type      = ARG_PTR_TO_UNINIT_MEM,
> +        .arg2_type      = ARG_PTR_TO_MEM_UNINIT,

indentation is off

>           .arg3_type      = ARG_CONST_SIZE,
>  };
>

[...]



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux