Re: [PATCH bpf-next v8 3/9] bpf: Check potential private stack recursion for progs with async callback

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

 



On Thu, Oct 31, 2024 at 8:12 PM Yonghong Song <yonghong.song@xxxxxxxxx> wrote:
>
> In previous patch, tracing progs are enabled for private stack since
> recursion checking ensures there exists no nested same bpf prog run on
> the same cpu.
>
> But it is still possible for nested bpf subprog run on the same cpu
> if the same subprog is called in both main prog and async callback,
> or in different async callbacks. For example,
>   main_prog
>    bpf_timer_set_callback(timer, timer_cb);
>    call sub1
>   sub1
>    ...
>   time_cb
>    call sub1
>
> In the above case, nested subprog run for sub1 is possible with one in
> process context and the other in softirq context. If this is the case,
> the verifier will disable private stack for this bpf prog.
>
> Signed-off-by: Yonghong Song <yonghong.song@xxxxxxxxx>
> ---
>  kernel/bpf/verifier.c | 46 ++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 41 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index d3f4cbab97bc..596afd29f088 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -6070,7 +6070,8 @@ static int round_up_stack_depth(struct bpf_verifier_env *env, int stack_depth)
>   */
>  static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
>                                          int *subtree_depth, int *depth_frame,
> -                                        int priv_stack_supported)
> +                                        int priv_stack_supported,
> +                                        char *subprog_visited)
>  {
>         struct bpf_subprog_info *subprog = env->subprog_info;
>         struct bpf_insn *insn = env->prog->insnsi;
> @@ -6120,8 +6121,12 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
>                                         idx, subprog_depth);
>                                 return -EACCES;
>                         }
> -                       if (subprog_depth >= BPF_PRIV_STACK_MIN_SIZE)
> +                       if (subprog_depth >= BPF_PRIV_STACK_MIN_SIZE) {
>                                 subprog[idx].use_priv_stack = true;
> +                               subprog_visited[idx] = 1;
> +                       }
> +               } else {
> +                       subprog_visited[idx] = 1;
>                 }
>         }
>  continue_func:
> @@ -6222,19 +6227,42 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
>  static int check_max_stack_depth(struct bpf_verifier_env *env)
>  {
>         struct bpf_subprog_info *si = env->subprog_info;
> +       char *subprogs1 = NULL, *subprogs2 = NULL;
>         int ret, subtree_depth = 0, depth_frame;
> +       int orig_priv_stack_supported;
>         int priv_stack_supported;
>
>         priv_stack_supported = bpf_enable_priv_stack(env);
>         if (priv_stack_supported < 0)
>                 return priv_stack_supported;
>
> +       orig_priv_stack_supported = priv_stack_supported;
> +       if (orig_priv_stack_supported != NO_PRIV_STACK) {
> +               subprogs1 = kvmalloc(env->subprog_cnt * 2, __GFP_ZERO);

Just __GFP_ZERO ?!

Overall the algo is messy. Pls think of a cleaner way of checking.
Add two bool flags to bpf_subprog_info:
visited_with_priv_stack
visited_without_priv_stack
and after walking all subrpogs add another loop over subprogs
that checks for exclusivity of these flags?

Probably other algos are possible.

> +               if (!subprogs1)
> +                       priv_stack_supported = NO_PRIV_STACK;
> +               else
> +                       subprogs2 = subprogs1 + env->subprog_cnt;
> +       }
> +
>         for (int i = 0; i < env->subprog_cnt; i++) {
>                 if (!i || si[i].is_async_cb) {
>                         ret = check_max_stack_depth_subprog(env, i, &subtree_depth, &depth_frame,
> -                                                           priv_stack_supported);
> +                                                           priv_stack_supported, subprogs2);
>                         if (ret < 0)
> -                               return ret;
> +                               goto out;
> +
> +                       if (priv_stack_supported != NO_PRIV_STACK) {
> +                               for (int j = 0; j < env->subprog_cnt; j++) {
> +                                       if (subprogs1[j] && subprogs2[j]) {
> +                                               priv_stack_supported = NO_PRIV_STACK;
> +                                               break;
> +                                       }
> +                                       subprogs1[j] |= subprogs2[j];
> +                               }
> +                       }
> +                       if (priv_stack_supported != NO_PRIV_STACK)
> +                               memset(subprogs2, 0, env->subprog_cnt);
>                 }
>         }
>         if (priv_stack_supported == NO_PRIV_STACK) {
> @@ -6243,10 +6271,18 @@ static int check_max_stack_depth(struct bpf_verifier_env *env)
>                                 depth_frame, subtree_depth);
>                         return -EACCES;
>                 }
> +               if (orig_priv_stack_supported == PRIV_STACK_ADAPTIVE) {
> +                       for (int i = 0; i < env->subprog_cnt; i++)
> +                               si[i].use_priv_stack = false;
> +               }
>         }
>         if (si[0].use_priv_stack)
>                 env->prog->aux->use_priv_stack = true;
> -       return 0;
> +       ret = 0;
> +
> +out:
> +       kvfree(subprogs1);
> +       return ret;
>  }
>
>  #ifndef CONFIG_BPF_JIT_ALWAYS_ON
> --
> 2.43.5
>





[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