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: <CAEf4BzapTMSfv4afg8QnV-mX2nL8cKboXCTBwp-_cRk8ybKnQQ@mail.gmail.com>
Date: Tue, 14 Jan 2025 14:37:32 -0800
From: Andrii Nakryiko <andrii.nakryiko@...il.com>
To: Song Liu <song@...nel.org>
Cc: bpf@...r.kernel.org, linux-kernel@...r.kernel.org, 
	linux-security-module@...r.kernel.org, kernel-team@...a.com, 
	andrii@...nel.org, ast@...nel.org, daniel@...earbox.net, martin.lau@...ux.dev, 
	kpsingh@...nel.org, mattbobrowski@...gle.com, paul@...l-moore.com, 
	jmorris@...ei.org, serge@...lyn.com, memxor@...il.com
Subject: Re: [PATCH v8 bpf-next 5/7] bpf: Use btf_kfunc_id_set.remap logic for bpf_dynptr_from_skb

On Wed, Jan 8, 2025 at 2:52 PM Song Liu <song@...nel.org> wrote:
>
> btf_kfunc_id_set.remap can pick proper version of a kfunc for the calling
> context. Use this logic to select bpf_dynptr_from_skb or
> bpf_dynptr_from_skb_rdonly. This will make the verifier simpler.
>
> Unfortunately, btf_kfunc_id_set.remap cannot cover the DYNPTR_TYPE_SKB
> logic in check_kfunc_args(). This can be addressed later.
>
> Signed-off-by: Song Liu <song@...nel.org>
> ---
>  kernel/bpf/verifier.c | 25 ++++++----------------
>  net/core/filter.c     | 49 +++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 51 insertions(+), 23 deletions(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index c321fd25fca3..95b0847191fe 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11677,6 +11677,7 @@ enum special_kfunc_type {
>         KF_bpf_rbtree_add_impl,
>         KF_bpf_rbtree_first,
>         KF_bpf_dynptr_from_skb,
> +       KF_bpf_dynptr_from_skb_rdonly,
>         KF_bpf_dynptr_from_xdp,
>         KF_bpf_dynptr_slice,
>         KF_bpf_dynptr_slice_rdwr,
> @@ -11712,6 +11713,7 @@ BTF_ID(func, bpf_rbtree_add_impl)
>  BTF_ID(func, bpf_rbtree_first)
>  #ifdef CONFIG_NET
>  BTF_ID(func, bpf_dynptr_from_skb)
> +BTF_ID(func, bpf_dynptr_from_skb_rdonly)
>  BTF_ID(func, bpf_dynptr_from_xdp)
>  #endif
>  BTF_ID(func, bpf_dynptr_slice)
> @@ -11743,10 +11745,12 @@ BTF_ID(func, bpf_rbtree_add_impl)
>  BTF_ID(func, bpf_rbtree_first)
>  #ifdef CONFIG_NET
>  BTF_ID(func, bpf_dynptr_from_skb)
> +BTF_ID(func, bpf_dynptr_from_skb_rdonly)
>  BTF_ID(func, bpf_dynptr_from_xdp)
>  #else
>  BTF_ID_UNUSED
>  BTF_ID_UNUSED
> +BTF_ID_UNUSED
>  #endif
>  BTF_ID(func, bpf_dynptr_slice)
>  BTF_ID(func, bpf_dynptr_slice_rdwr)
> @@ -12668,7 +12672,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
>                         if (is_kfunc_arg_uninit(btf, &args[i]))
>                                 dynptr_arg_type |= MEM_UNINIT;
>
> -                       if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
> +                       if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb] ||
> +                           meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb_rdonly]) {
>                                 dynptr_arg_type |= DYNPTR_TYPE_SKB;
>                         } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) {
>                                 dynptr_arg_type |= DYNPTR_TYPE_XDP;
> @@ -20821,9 +20826,7 @@ static void specialize_kfunc(struct bpf_verifier_env *env,
>                              u32 func_id, u16 offset, unsigned long *addr)
>  {
>         struct bpf_prog *prog = env->prog;
> -       bool seen_direct_write;
>         void *xdp_kfunc;
> -       bool is_rdonly;
>
>         if (bpf_dev_bound_kfunc_id(func_id)) {
>                 xdp_kfunc = bpf_dev_bound_resolve_kfunc(prog, func_id);
> @@ -20833,22 +20836,6 @@ static void specialize_kfunc(struct bpf_verifier_env *env,
>                 }
>                 /* fallback to default kfunc when not supported by netdev */
>         }
> -
> -       if (offset)
> -               return;
> -
> -       if (func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
> -               seen_direct_write = env->seen_direct_write;
> -               is_rdonly = !may_access_direct_pkt_data(env, NULL, BPF_WRITE);
> -
> -               if (is_rdonly)
> -                       *addr = (unsigned long)bpf_dynptr_from_skb_rdonly;
> -
> -               /* restore env->seen_direct_write to its original value, since
> -                * may_access_direct_pkt_data mutates it
> -                */
> -               env->seen_direct_write = seen_direct_write;

is it safe to remove this special seen_direct_write part of logic?

> -       }
>  }
>
>  static void __fixup_collection_insert_kfunc(struct bpf_insn_aux_data *insn_aux,
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 21131ec25f24..f12bcc1b21d1 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -12047,10 +12047,8 @@ __bpf_kfunc int bpf_sk_assign_tcp_reqsk(struct __sk_buff *s, struct sock *sk,
>  #endif
>  }
>
> -__bpf_kfunc_end_defs();
> -
> -int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
> -                              struct bpf_dynptr *ptr__uninit)
> +__bpf_kfunc int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
> +                                          struct bpf_dynptr *ptr__uninit)
>  {
>         struct bpf_dynptr_kern *ptr = (struct bpf_dynptr_kern *)ptr__uninit;
>         int err;
> @@ -12064,10 +12062,16 @@ int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
>         return 0;
>  }
>
> +__bpf_kfunc_end_defs();
> +
>  BTF_KFUNCS_START(bpf_kfunc_check_set_skb)
>  BTF_ID_FLAGS(func, bpf_dynptr_from_skb, KF_TRUSTED_ARGS)
>  BTF_KFUNCS_END(bpf_kfunc_check_set_skb)
>
> +BTF_HIDDEN_KFUNCS_START(bpf_kfunc_check_hidden_set_skb)
> +BTF_ID_FLAGS(func, bpf_dynptr_from_skb_rdonly, KF_TRUSTED_ARGS)
> +BTF_KFUNCS_END(bpf_kfunc_check_hidden_set_skb)
> +
>  BTF_KFUNCS_START(bpf_kfunc_check_set_xdp)
>  BTF_ID_FLAGS(func, bpf_dynptr_from_xdp)
>  BTF_KFUNCS_END(bpf_kfunc_check_set_xdp)
> @@ -12080,9 +12084,46 @@ BTF_KFUNCS_START(bpf_kfunc_check_set_tcp_reqsk)
>  BTF_ID_FLAGS(func, bpf_sk_assign_tcp_reqsk, KF_TRUSTED_ARGS)
>  BTF_KFUNCS_END(bpf_kfunc_check_set_tcp_reqsk)
>
> +BTF_ID_LIST(bpf_dynptr_from_skb_list)
> +BTF_ID(func, bpf_dynptr_from_skb)
> +BTF_ID(func, bpf_dynptr_from_skb_rdonly)
> +
> +static u32 bpf_kfunc_set_skb_remap(const struct bpf_prog *prog, u32 kfunc_id)
> +{
> +       if (kfunc_id != bpf_dynptr_from_skb_list[0])
> +               return 0;
> +
> +       switch (resolve_prog_type(prog)) {
> +       /* Program types only with direct read access go here! */
> +       case BPF_PROG_TYPE_LWT_IN:
> +       case BPF_PROG_TYPE_LWT_OUT:
> +       case BPF_PROG_TYPE_LWT_SEG6LOCAL:
> +       case BPF_PROG_TYPE_SK_REUSEPORT:
> +       case BPF_PROG_TYPE_FLOW_DISSECTOR:
> +       case BPF_PROG_TYPE_CGROUP_SKB:
> +               return bpf_dynptr_from_skb_list[1];
> +
> +       /* Program types with direct read + write access go here! */
> +       case BPF_PROG_TYPE_SCHED_CLS:
> +       case BPF_PROG_TYPE_SCHED_ACT:
> +       case BPF_PROG_TYPE_XDP:
> +       case BPF_PROG_TYPE_LWT_XMIT:
> +       case BPF_PROG_TYPE_SK_SKB:
> +       case BPF_PROG_TYPE_SK_MSG:
> +       case BPF_PROG_TYPE_CGROUP_SOCKOPT:
> +               return kfunc_id;
> +
> +       default:
> +               break;
> +       }
> +       return bpf_dynptr_from_skb_list[1];
> +}

I'd personally prefer the approach we have with BPF helpers, where
each program type has a function that handles all helpers (identified
by its ID), and then we can use C code sharing to minimize duplication
of code.

With this approach it seems like we'll have more duplication and we'll
need to repeat these program type-based large switches for various
small sets of kfuncs, no?

> +
>  static const struct btf_kfunc_id_set bpf_kfunc_set_skb = {
>         .owner = THIS_MODULE,
>         .set = &bpf_kfunc_check_set_skb,
> +       .hidden_set = &bpf_kfunc_check_hidden_set_skb,
> +       .remap = &bpf_kfunc_set_skb_remap,
>  };
>
>  static const struct btf_kfunc_id_set bpf_kfunc_set_xdp = {
> --
> 2.43.5
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ