lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAEf4BzZ6Lfmn9pEJSLVhROjkPGJO_mT4nHot8AOjZ_9HTC1rEQ@mail.gmail.com>
Date:   Mon, 15 Mar 2021 18:03:11 -0700
From:   Andrii Nakryiko <andrii.nakryiko@...il.com>
To:     Florent Revest <revest@...omium.org>
Cc:     bpf <bpf@...r.kernel.org>, Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>,
        Andrii Nakryiko <andrii@...nel.org>,
        Yonghong Song <yhs@...com>, KP Singh <kpsingh@...nel.org>,
        Brendan Jackman <jackmanb@...omium.org>,
        open list <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH bpf-next 1/5] bpf: Add a ARG_PTR_TO_CONST_STR argument type

On Wed, Mar 10, 2021 at 2:02 PM Florent Revest <revest@...omium.org> wrote:
>
> This type provides the guarantee that an argument is going to be a const
> pointer to somewhere in a read-only map value. It also checks that this
> pointer is followed by a NULL character before the end of the map value.
>
> Signed-off-by: Florent Revest <revest@...omium.org>
> ---
>  include/linux/bpf.h   |  1 +
>  kernel/bpf/verifier.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 42 insertions(+)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index a25730eaa148..7b5319d75b3e 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -308,6 +308,7 @@ enum bpf_arg_type {
>         ARG_PTR_TO_PERCPU_BTF_ID,       /* pointer to in-kernel percpu type */
>         ARG_PTR_TO_FUNC,        /* pointer to a bpf program function */
>         ARG_PTR_TO_STACK_OR_NULL,       /* pointer to stack or NULL */
> +       ARG_PTR_TO_CONST_STR,   /* pointer to a null terminated read-only string */
>         __BPF_ARG_TYPE_MAX,
>  };
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index f9096b049cd6..c99b2b67dc8d 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -4601,6 +4601,7 @@ static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALU
>  static const struct bpf_reg_types percpu_btf_ptr_types = { .types = { PTR_TO_PERCPU_BTF_ID } };
>  static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } };
>  static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } };
> +static const struct bpf_reg_types const_str_ptr_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,
> @@ -4631,6 +4632,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
>         [ARG_PTR_TO_PERCPU_BTF_ID]      = &percpu_btf_ptr_types,
>         [ARG_PTR_TO_FUNC]               = &func_ptr_types,
>         [ARG_PTR_TO_STACK_OR_NULL]      = &stack_ptr_types,
> +       [ARG_PTR_TO_CONST_STR]          = &const_str_ptr_types,
>  };
>
>  static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
> @@ -4881,6 +4883,45 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
>                 if (err)
>                         return err;
>                 err = check_ptr_alignment(env, reg, 0, size, true);
> +       } else if (arg_type == ARG_PTR_TO_CONST_STR) {
> +               struct bpf_map *map = reg->map_ptr;
> +               int map_off, i;
> +               u64 map_addr;
> +               char *map_ptr;
> +
> +               if (!map || !bpf_map_is_rdonly(map)) {
> +                       verbose(env, "R%d does not point to a readonly map'\n", regno);
> +                       return -EACCES;
> +               }
> +
> +               if (!tnum_is_const(reg->var_off)) {
> +                       verbose(env, "R%d is not a constant address'\n", regno);
> +                       return -EACCES;
> +               }
> +
> +               if (!map->ops->map_direct_value_addr) {
> +                       verbose(env, "no direct value access support for this map type\n");
> +                       return -EACCES;
> +               }
> +
> +               err = check_helper_mem_access(env, regno,
> +                                             map->value_size - reg->off,
> +                                             false, meta);

you expect reg to be PTR_TO_MAP_VALUE, so probably better to directly
use check_map_access(). And double-check that register is of expected
type. just the presence of ref->map_ptr might not be sufficient?

> +               if (err)
> +                       return err;
> +
> +               map_off = reg->off + reg->var_off.value;
> +               err = map->ops->map_direct_value_addr(map, &map_addr, map_off);
> +               if (err)
> +                       return err;
> +
> +               map_ptr = (char *)(map_addr);

map_ptr is a very confusing name. str_ptr or value ptr?

> +               for (i = map_off; map_ptr[i] != '\0'; i++) {
> +                       if (i == map->value_size - 1) {

use strnchr()?

> +                               verbose(env, "map does not contain a NULL-terminated string\n");

map in the user-visible message is quite confusing, given that users
will probably use this through static variables, so maybe just "string
is not zero-terminated?" And it's not really a NULL, it's zero
character.

> +                               return -EACCES;
> +                       }
> +               }
>         }
>
>         return err;
> --
> 2.30.1.766.gb4fecdf3b7-goog
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ