diff mbox series

[bpf-next,v9,02/10] bpf: Return false for bpf_prog_check_recur() default case

Message ID 20241104193505.3242662-1-yonghong.song@linux.dev (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series bpf: Support private stack for bpf progs | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 5 this patch: 5
netdev/build_tools success Errors and warnings before: 0 (+0) this patch: 0 (+0)
netdev/cc_maintainers warning 8 maintainers not CCed: kpsingh@kernel.org martin.lau@linux.dev eddyz87@gmail.com sdf@fomichev.me john.fastabend@gmail.com song@kernel.org jolsa@kernel.org haoluo@google.com
netdev/build_clang success Errors and warnings before: 3 this patch: 3
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 68 this patch: 68
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 10 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Yonghong Song Nov. 4, 2024, 7:35 p.m. UTC
The bpf_prog_check_recur() funciton is currently used by trampoline
and tracing programs (also using trampoline) to check whether a
particular prog supports recursion checking or not. The default case
(non-trampoline progs) return true in the current implementation.

Let us make the non-trampoline prog recursion check return false
instead. It does not impact any existing use cases and allows the
function to be used outside the trampoline context in the next patch.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
 include/linux/bpf_verifier.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Comments

Alexei Starovoitov Nov. 5, 2024, 1:21 a.m. UTC | #1
On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>
> The bpf_prog_check_recur() funciton is currently used by trampoline
> and tracing programs (also using trampoline) to check whether a
> particular prog supports recursion checking or not. The default case
> (non-trampoline progs) return true in the current implementation.
>
> Let us make the non-trampoline prog recursion check return false
> instead. It does not impact any existing use cases and allows the
> function to be used outside the trampoline context in the next patch.

Does not impact ?! But it does.
This patch removes recursion check from fentry progs.
This cannot be right.

pw-bot: cr

> Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
> ---
>  include/linux/bpf_verifier.h | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 4513372c5bc8..ad887c68d3e1 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -889,9 +889,8 @@ static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
>                 return prog->expected_attach_type != BPF_TRACE_ITER;
>         case BPF_PROG_TYPE_STRUCT_OPS:
>         case BPF_PROG_TYPE_LSM:
> -               return false;
>         default:
> -               return true;
> +               return false;
>         }
>  }
>
> --
> 2.43.5
>
Yonghong Song Nov. 5, 2024, 1:35 a.m. UTC | #2
On 11/4/24 5:21 PM, Alexei Starovoitov wrote:
> On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>> The bpf_prog_check_recur() funciton is currently used by trampoline
>> and tracing programs (also using trampoline) to check whether a
>> particular prog supports recursion checking or not. The default case
>> (non-trampoline progs) return true in the current implementation.
>>
>> Let us make the non-trampoline prog recursion check return false
>> instead. It does not impact any existing use cases and allows the
>> function to be used outside the trampoline context in the next patch.
> Does not impact ?! But it does.
> This patch removes recursion check from fentry progs.
> This cannot be right.

The original bpf_prog_check_recur() implementation:

static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
{
         switch (resolve_prog_type(prog)) {
         case BPF_PROG_TYPE_TRACING:
                 return prog->expected_attach_type != BPF_TRACE_ITER;
         case BPF_PROG_TYPE_STRUCT_OPS:
         case BPF_PROG_TYPE_LSM:
                 return false;
         default:
                 return true;
         }
}

fentry prog is a TRACING prog, so it is covered. Did I miss anything?

>
> pw-bot: cr
>
>> Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
>> ---
>>   include/linux/bpf_verifier.h | 3 +--
>>   1 file changed, 1 insertion(+), 2 deletions(-)
>>
>> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
>> index 4513372c5bc8..ad887c68d3e1 100644
>> --- a/include/linux/bpf_verifier.h
>> +++ b/include/linux/bpf_verifier.h
>> @@ -889,9 +889,8 @@ static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
>>                  return prog->expected_attach_type != BPF_TRACE_ITER;
>>          case BPF_PROG_TYPE_STRUCT_OPS:
>>          case BPF_PROG_TYPE_LSM:
>> -               return false;
>>          default:
>> -               return true;
>> +               return false;
>>          }
>>   }
>>
>> --
>> 2.43.5
>>
Alexei Starovoitov Nov. 5, 2024, 1:55 a.m. UTC | #3
On Mon, Nov 4, 2024 at 5:35 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>
>
> On 11/4/24 5:21 PM, Alexei Starovoitov wrote:
> > On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song <yonghong.song@linux.dev> wrote:
> >> The bpf_prog_check_recur() funciton is currently used by trampoline
> >> and tracing programs (also using trampoline) to check whether a
> >> particular prog supports recursion checking or not. The default case
> >> (non-trampoline progs) return true in the current implementation.
> >>
> >> Let us make the non-trampoline prog recursion check return false
> >> instead. It does not impact any existing use cases and allows the
> >> function to be used outside the trampoline context in the next patch.
> > Does not impact ?! But it does.
> > This patch removes recursion check from fentry progs.
> > This cannot be right.
>
> The original bpf_prog_check_recur() implementation:
>
> static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
> {
>          switch (resolve_prog_type(prog)) {
>          case BPF_PROG_TYPE_TRACING:
>                  return prog->expected_attach_type != BPF_TRACE_ITER;
>          case BPF_PROG_TYPE_STRUCT_OPS:
>          case BPF_PROG_TYPE_LSM:
>                  return false;
>          default:
>                  return true;
>          }
> }
>
> fentry prog is a TRACING prog, so it is covered. Did I miss anything?

I see. This is way too subtle.
You're correct that fentry is TYPE_TRACING,
so it could have "worked" if it was used to build trampolines only.

But this helper is called for other prog types:

        case BPF_FUNC_task_storage_get:
                if (bpf_prog_check_recur(prog))
                        return &bpf_task_storage_get_recur_proto;
                return &bpf_task_storage_get_proto;

so it's still not correct, but for a different reason.
Yonghong Song Nov. 5, 2024, 2:53 a.m. UTC | #4
On 11/4/24 5:55 PM, Alexei Starovoitov wrote:
> On Mon, Nov 4, 2024 at 5:35 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>>
>> On 11/4/24 5:21 PM, Alexei Starovoitov wrote:
>>> On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>>>> The bpf_prog_check_recur() funciton is currently used by trampoline
>>>> and tracing programs (also using trampoline) to check whether a
>>>> particular prog supports recursion checking or not. The default case
>>>> (non-trampoline progs) return true in the current implementation.
>>>>
>>>> Let us make the non-trampoline prog recursion check return false
>>>> instead. It does not impact any existing use cases and allows the
>>>> function to be used outside the trampoline context in the next patch.
>>> Does not impact ?! But it does.
>>> This patch removes recursion check from fentry progs.
>>> This cannot be right.
>> The original bpf_prog_check_recur() implementation:
>>
>> static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
>> {
>>           switch (resolve_prog_type(prog)) {
>>           case BPF_PROG_TYPE_TRACING:
>>                   return prog->expected_attach_type != BPF_TRACE_ITER;
>>           case BPF_PROG_TYPE_STRUCT_OPS:
>>           case BPF_PROG_TYPE_LSM:
>>                   return false;
>>           default:
>>                   return true;
>>           }
>> }
>>
>> fentry prog is a TRACING prog, so it is covered. Did I miss anything?
> I see. This is way too subtle.
> You're correct that fentry is TYPE_TRACING,
> so it could have "worked" if it was used to build trampolines only.
>
> But this helper is called for other prog types:
>
>          case BPF_FUNC_task_storage_get:
>                  if (bpf_prog_check_recur(prog))
>                          return &bpf_task_storage_get_recur_proto;
>                  return &bpf_task_storage_get_proto;
>
> so it's still not correct, but for a different reason.

There are four uses for func bpf_prog_check_recur() in kernel based on 
cscope: 0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if 
(bpf_prog_check_recur(prog)) 1 kernel/bpf/trampoline.c 
bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog)) 2 
kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if 
(bpf_prog_check_recur(prog)) 3 kernel/trace/bpf_trace.c 
bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog)) The 2nd and 
3rd ones are in bpf_trace.c. 1444 static const struct bpf_func_proto * 
1445 bpf_tracing_func_proto(enum bpf_func_id func_id, const struct 
bpf_prog *prog) 1446 { 1447 switch (func_id) { ... 1548 case 
BPF_FUNC_task_storage_get: 1549 if (bpf_prog_check_recur(prog)) 1550 
return &bpf_task_storage_get_recur_proto; 1551 return 
&bpf_task_storage_get_proto; 1552 case BPF_FUNC_task_storage_delete: 
1553 if (bpf_prog_check_recur(prog)) 1554 return 
&bpf_task_storage_delete_recur_proto; 1555 return 
&bpf_task_storage_delete_proto; ... 1568 default: 1569 return 
bpf_base_func_proto(func_id, prog); 1570 } 1571 } They are used for 
tracing programs. So we should be safe here. But if you think that 
changing bpf_proc_check_recur() and calling function 
bpf_prog_check_recur() in bpf_enable_priv_stack() is too subtle, I can 
go back to my original approach which makes all supported prog types 
explicit in bpf_enable_priv_stack().
Yonghong Song Nov. 5, 2024, 3:50 a.m. UTC | #5
On 11/4/24 6:53 PM, Yonghong Song wrote:
>
> On 11/4/24 5:55 PM, Alexei Starovoitov wrote:
>> On Mon, Nov 4, 2024 at 5:35 PM Yonghong Song 
>> <yonghong.song@linux.dev> wrote:
>>>
>>> On 11/4/24 5:21 PM, Alexei Starovoitov wrote:
>>>> On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song 
>>>> <yonghong.song@linux.dev> wrote:
>>>>> The bpf_prog_check_recur() funciton is currently used by trampoline
>>>>> and tracing programs (also using trampoline) to check whether a
>>>>> particular prog supports recursion checking or not. The default case
>>>>> (non-trampoline progs) return true in the current implementation.
>>>>>
>>>>> Let us make the non-trampoline prog recursion check return false
>>>>> instead. It does not impact any existing use cases and allows the
>>>>> function to be used outside the trampoline context in the next patch.
>>>> Does not impact ?! But it does.
>>>> This patch removes recursion check from fentry progs.
>>>> This cannot be right.
>>> The original bpf_prog_check_recur() implementation:
>>>
>>> static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
>>> {
>>>           switch (resolve_prog_type(prog)) {
>>>           case BPF_PROG_TYPE_TRACING:
>>>                   return prog->expected_attach_type != BPF_TRACE_ITER;
>>>           case BPF_PROG_TYPE_STRUCT_OPS:
>>>           case BPF_PROG_TYPE_LSM:
>>>                   return false;
>>>           default:
>>>                   return true;
>>>           }
>>> }
>>>
>>> fentry prog is a TRACING prog, so it is covered. Did I miss anything?
>> I see. This is way too subtle.
>> You're correct that fentry is TYPE_TRACING,
>> so it could have "worked" if it was used to build trampolines only.
>>
>> But this helper is called for other prog types:
>>
>>          case BPF_FUNC_task_storage_get:
>>                  if (bpf_prog_check_recur(prog))
>>                          return &bpf_task_storage_get_recur_proto;
>>                  return &bpf_task_storage_get_proto;
>>
>> so it's still not correct, but for a different reason.
>
> There are four uses for func bpf_prog_check_recur() in kernel based on 
> cscope: 0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if 
> (bpf_prog_check_recur(prog)) 1 kernel/bpf/trampoline.c 
> bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog)) 2 
> kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if 
> (bpf_prog_check_recur(prog)) 3 kernel/trace/bpf_trace.c 
> bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog)) The 2nd 
> and 3rd ones are in bpf_trace.c. 1444 static const struct 
> bpf_func_proto * 1445 bpf_tracing_func_proto(enum bpf_func_id func_id, 
> const struct bpf_prog *prog) 1446 { 1447 switch (func_id) { ... 1548 
> case BPF_FUNC_task_storage_get: 1549 if (bpf_prog_check_recur(prog)) 
> 1550 return &bpf_task_storage_get_recur_proto; 1551 return 
> &bpf_task_storage_get_proto; 1552 case BPF_FUNC_task_storage_delete: 
> 1553 if (bpf_prog_check_recur(prog)) 1554 return 
> &bpf_task_storage_delete_recur_proto; 1555 return 
> &bpf_task_storage_delete_proto; ... 1568 default: 1569 return 
> bpf_base_func_proto(func_id, prog); 1570 } 1571 } They are used for 
> tracing programs. So we should be safe here. But if you think that 
> changing bpf_proc_check_recur() and calling function 
> bpf_prog_check_recur() in bpf_enable_priv_stack() is too subtle, I can 
> go back to my original approach which makes all supported prog types 
> explicit in bpf_enable_priv_stack().

Sorry. Format issue again. The below is a better format:

There are four uses for func bpf_prog_check_recur() in kernel based on cscope:

0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if (bpf_prog_check_recur(prog))
1 kernel/bpf/trampoline.c bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog))
2 kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if (bpf_prog_check_recur(prog))
3 kernel/trace/bpf_trace.c bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog))

The 2nd and 3rd ones are in bpf_trace.c.

1444 static const struct bpf_func_proto *
1445 bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
1446 {
1447     switch (func_id) {
...
1548     case BPF_FUNC_task_storage_get:
1549         if (bpf_prog_check_recur(prog))
1550             return &bpf_task_storage_get_recur_proto;
1551         return &bpf_task_storage_get_proto;
1552     case BPF_FUNC_task_storage_delete:
1553         if (bpf_prog_check_recur(prog))
1554             return &bpf_task_storage_delete_recur_proto;
1555         return &bpf_task_storage_delete_proto;
...
1568     default:
1569         return bpf_base_func_proto(func_id, prog);
1570     }
1571 }
  
They are used for tracing programs. So we should be safe here. But if you think that
changing bpf_proc_check_recur() and calling function bpf_prog_check_recur()
in bpf_enable_priv_stack() is too subtle, I can go back to my original approach
which makes all supported prog types explicit in bpf_enable_priv_stack().
Alexei Starovoitov Nov. 5, 2024, 4:28 a.m. UTC | #6
On Mon, Nov 4, 2024 at 7:50 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>
>
> On 11/4/24 6:53 PM, Yonghong Song wrote:
> >
> > On 11/4/24 5:55 PM, Alexei Starovoitov wrote:
> >> On Mon, Nov 4, 2024 at 5:35 PM Yonghong Song
> >> <yonghong.song@linux.dev> wrote:
> >>>
> >>> On 11/4/24 5:21 PM, Alexei Starovoitov wrote:
> >>>> On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song
> >>>> <yonghong.song@linux.dev> wrote:
> >>>>> The bpf_prog_check_recur() funciton is currently used by trampoline
> >>>>> and tracing programs (also using trampoline) to check whether a
> >>>>> particular prog supports recursion checking or not. The default case
> >>>>> (non-trampoline progs) return true in the current implementation.
> >>>>>
> >>>>> Let us make the non-trampoline prog recursion check return false
> >>>>> instead. It does not impact any existing use cases and allows the
> >>>>> function to be used outside the trampoline context in the next patch.
> >>>> Does not impact ?! But it does.
> >>>> This patch removes recursion check from fentry progs.
> >>>> This cannot be right.
> >>> The original bpf_prog_check_recur() implementation:
> >>>
> >>> static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
> >>> {
> >>>           switch (resolve_prog_type(prog)) {
> >>>           case BPF_PROG_TYPE_TRACING:
> >>>                   return prog->expected_attach_type != BPF_TRACE_ITER;
> >>>           case BPF_PROG_TYPE_STRUCT_OPS:
> >>>           case BPF_PROG_TYPE_LSM:
> >>>                   return false;
> >>>           default:
> >>>                   return true;
> >>>           }
> >>> }
> >>>
> >>> fentry prog is a TRACING prog, so it is covered. Did I miss anything?
> >> I see. This is way too subtle.
> >> You're correct that fentry is TYPE_TRACING,
> >> so it could have "worked" if it was used to build trampolines only.
> >>
> >> But this helper is called for other prog types:
> >>
> >>          case BPF_FUNC_task_storage_get:
> >>                  if (bpf_prog_check_recur(prog))
> >>                          return &bpf_task_storage_get_recur_proto;
> >>                  return &bpf_task_storage_get_proto;
> >>
> >> so it's still not correct, but for a different reason.
> >
> > There are four uses for func bpf_prog_check_recur() in kernel based on
> > cscope: 0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if
> > (bpf_prog_check_recur(prog)) 1 kernel/bpf/trampoline.c
> > bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog)) 2
> > kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if
> > (bpf_prog_check_recur(prog)) 3 kernel/trace/bpf_trace.c
> > bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog)) The 2nd
> > and 3rd ones are in bpf_trace.c. 1444 static const struct
> > bpf_func_proto * 1445 bpf_tracing_func_proto(enum bpf_func_id func_id,
> > const struct bpf_prog *prog) 1446 { 1447 switch (func_id) { ... 1548
> > case BPF_FUNC_task_storage_get: 1549 if (bpf_prog_check_recur(prog))
> > 1550 return &bpf_task_storage_get_recur_proto; 1551 return
> > &bpf_task_storage_get_proto; 1552 case BPF_FUNC_task_storage_delete:
> > 1553 if (bpf_prog_check_recur(prog)) 1554 return
> > &bpf_task_storage_delete_recur_proto; 1555 return
> > &bpf_task_storage_delete_proto; ... 1568 default: 1569 return
> > bpf_base_func_proto(func_id, prog); 1570 } 1571 } They are used for
> > tracing programs. So we should be safe here. But if you think that
> > changing bpf_proc_check_recur() and calling function
> > bpf_prog_check_recur() in bpf_enable_priv_stack() is too subtle, I can
> > go back to my original approach which makes all supported prog types
> > explicit in bpf_enable_priv_stack().
>
> Sorry. Format issue again. The below is a better format:
>
> There are four uses for func bpf_prog_check_recur() in kernel based on cscope:
>
> 0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if (bpf_prog_check_recur(prog))
> 1 kernel/bpf/trampoline.c bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog))
> 2 kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if (bpf_prog_check_recur(prog))
> 3 kernel/trace/bpf_trace.c bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog))
>
> The 2nd and 3rd ones are in bpf_trace.c.
>
> 1444 static const struct bpf_func_proto *
> 1445 bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
> 1446 {
> 1447     switch (func_id) {
> ...
> 1548     case BPF_FUNC_task_storage_get:
> 1549         if (bpf_prog_check_recur(prog))
> 1550             return &bpf_task_storage_get_recur_proto;
> 1551         return &bpf_task_storage_get_proto;
> 1552     case BPF_FUNC_task_storage_delete:
> 1553         if (bpf_prog_check_recur(prog))
> 1554             return &bpf_task_storage_delete_recur_proto;
> 1555         return &bpf_task_storage_delete_proto;
> ...
> 1568     default:
> 1569         return bpf_base_func_proto(func_id, prog);
> 1570     }
> 1571 }
>
> They are used for tracing programs. So we should be safe here. But if you think that
> changing bpf_proc_check_recur() and calling function bpf_prog_check_recur()
> in bpf_enable_priv_stack() is too subtle, I can go back to my original approach
> which makes all supported prog types explicit in bpf_enable_priv_stack().

What do you mean 'it's safe' ?
If you change bpf_prog_check_recur() to return false like this patch does
then kprobe progs will not have recursion protection
calling task_storage_get() helper.
In the context of this helper it means that kprobe progs have to use:
nobusy = bpf_task_storage_trylock();
With this patch as-is there will be a deadlock in bpf_task_storage_lock()
when kprobe is using task storage.
So it looks broken to me.

I also don't understand the point of this patch 2.
The patch 3 can still do:

+ switch (prog->type) {
+ case BPF_PROG_TYPE_KPROBE:
+ case BPF_PROG_TYPE_TRACEPOINT:
+ case BPF_PROG_TYPE_PERF_EVENT:
+ case BPF_PROG_TYPE_RAW_TRACEPOINT:
+   return PRIV_STACK_ADAPTIVE;
+ default:
+   break;
+ }
+
+ if (!bpf_prog_check_recur(prog))
+   return NO_PRIV_STACK;

which would mean that iter, lsm, struct_ops will not be allowed
to use priv stack.

Unless struct_ops will explicit request priv stack via bool flag.
Then we will also add recursion protection in trampoline.
Yonghong Song Nov. 5, 2024, 6:02 a.m. UTC | #7
On 11/4/24 8:28 PM, Alexei Starovoitov wrote:
> On Mon, Nov 4, 2024 at 7:50 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>>
>> On 11/4/24 6:53 PM, Yonghong Song wrote:
>>> On 11/4/24 5:55 PM, Alexei Starovoitov wrote:
>>>> On Mon, Nov 4, 2024 at 5:35 PM Yonghong Song
>>>> <yonghong.song@linux.dev> wrote:
>>>>> On 11/4/24 5:21 PM, Alexei Starovoitov wrote:
>>>>>> On Mon, Nov 4, 2024 at 11:35 AM Yonghong Song
>>>>>> <yonghong.song@linux.dev> wrote:
>>>>>>> The bpf_prog_check_recur() funciton is currently used by trampoline
>>>>>>> and tracing programs (also using trampoline) to check whether a
>>>>>>> particular prog supports recursion checking or not. The default case
>>>>>>> (non-trampoline progs) return true in the current implementation.
>>>>>>>
>>>>>>> Let us make the non-trampoline prog recursion check return false
>>>>>>> instead. It does not impact any existing use cases and allows the
>>>>>>> function to be used outside the trampoline context in the next patch.
>>>>>> Does not impact ?! But it does.
>>>>>> This patch removes recursion check from fentry progs.
>>>>>> This cannot be right.
>>>>> The original bpf_prog_check_recur() implementation:
>>>>>
>>>>> static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
>>>>> {
>>>>>            switch (resolve_prog_type(prog)) {
>>>>>            case BPF_PROG_TYPE_TRACING:
>>>>>                    return prog->expected_attach_type != BPF_TRACE_ITER;
>>>>>            case BPF_PROG_TYPE_STRUCT_OPS:
>>>>>            case BPF_PROG_TYPE_LSM:
>>>>>                    return false;
>>>>>            default:
>>>>>                    return true;
>>>>>            }
>>>>> }
>>>>>
>>>>> fentry prog is a TRACING prog, so it is covered. Did I miss anything?
>>>> I see. This is way too subtle.
>>>> You're correct that fentry is TYPE_TRACING,
>>>> so it could have "worked" if it was used to build trampolines only.
>>>>
>>>> But this helper is called for other prog types:
>>>>
>>>>           case BPF_FUNC_task_storage_get:
>>>>                   if (bpf_prog_check_recur(prog))
>>>>                           return &bpf_task_storage_get_recur_proto;
>>>>                   return &bpf_task_storage_get_proto;
>>>>
>>>> so it's still not correct, but for a different reason.
>>> There are four uses for func bpf_prog_check_recur() in kernel based on
>>> cscope: 0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if
>>> (bpf_prog_check_recur(prog)) 1 kernel/bpf/trampoline.c
>>> bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog)) 2
>>> kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if
>>> (bpf_prog_check_recur(prog)) 3 kernel/trace/bpf_trace.c
>>> bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog)) The 2nd
>>> and 3rd ones are in bpf_trace.c. 1444 static const struct
>>> bpf_func_proto * 1445 bpf_tracing_func_proto(enum bpf_func_id func_id,
>>> const struct bpf_prog *prog) 1446 { 1447 switch (func_id) { ... 1548
>>> case BPF_FUNC_task_storage_get: 1549 if (bpf_prog_check_recur(prog))
>>> 1550 return &bpf_task_storage_get_recur_proto; 1551 return
>>> &bpf_task_storage_get_proto; 1552 case BPF_FUNC_task_storage_delete:
>>> 1553 if (bpf_prog_check_recur(prog)) 1554 return
>>> &bpf_task_storage_delete_recur_proto; 1555 return
>>> &bpf_task_storage_delete_proto; ... 1568 default: 1569 return
>>> bpf_base_func_proto(func_id, prog); 1570 } 1571 } They are used for
>>> tracing programs. So we should be safe here. But if you think that
>>> changing bpf_proc_check_recur() and calling function
>>> bpf_prog_check_recur() in bpf_enable_priv_stack() is too subtle, I can
>>> go back to my original approach which makes all supported prog types
>>> explicit in bpf_enable_priv_stack().
>> Sorry. Format issue again. The below is a better format:
>>
>> There are four uses for func bpf_prog_check_recur() in kernel based on cscope:
>>
>> 0 kernel/bpf/trampoline.c bpf_trampoline_enter 1053 if (bpf_prog_check_recur(prog))
>> 1 kernel/bpf/trampoline.c bpf_trampoline_exit 1068 if (bpf_prog_check_recur(prog))
>> 2 kernel/trace/bpf_trace.c bpf_tracing_func_proto 1549 if (bpf_prog_check_recur(prog))
>> 3 kernel/trace/bpf_trace.c bpf_tracing_func_proto 1553 if (bpf_prog_check_recur(prog))
>>
>> The 2nd and 3rd ones are in bpf_trace.c.
>>
>> 1444 static const struct bpf_func_proto *
>> 1445 bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
>> 1446 {
>> 1447     switch (func_id) {
>> ...
>> 1548     case BPF_FUNC_task_storage_get:
>> 1549         if (bpf_prog_check_recur(prog))
>> 1550             return &bpf_task_storage_get_recur_proto;
>> 1551         return &bpf_task_storage_get_proto;
>> 1552     case BPF_FUNC_task_storage_delete:
>> 1553         if (bpf_prog_check_recur(prog))
>> 1554             return &bpf_task_storage_delete_recur_proto;
>> 1555         return &bpf_task_storage_delete_proto;
>> ...
>> 1568     default:
>> 1569         return bpf_base_func_proto(func_id, prog);
>> 1570     }
>> 1571 }
>>
>> They are used for tracing programs. So we should be safe here. But if you think that
>> changing bpf_proc_check_recur() and calling function bpf_prog_check_recur()
>> in bpf_enable_priv_stack() is too subtle, I can go back to my original approach
>> which makes all supported prog types explicit in bpf_enable_priv_stack().
> What do you mean 'it's safe' ?
> If you change bpf_prog_check_recur() to return false like this patch does
> then kprobe progs will not have recursion protection
> calling task_storage_get() helper.
> In the context of this helper it means that kprobe progs have to use:
> nobusy = bpf_task_storage_trylock();
> With this patch as-is there will be a deadlock in bpf_task_storage_lock()
> when kprobe is using task storage.
> So it looks broken to me.
>
> I also don't understand the point of this patch 2.
> The patch 3 can still do:
>
> + switch (prog->type) {
> + case BPF_PROG_TYPE_KPROBE:
> + case BPF_PROG_TYPE_TRACEPOINT:
> + case BPF_PROG_TYPE_PERF_EVENT:
> + case BPF_PROG_TYPE_RAW_TRACEPOINT:
> +   return PRIV_STACK_ADAPTIVE;
> + default:
> +   break;
> + }
> +
> + if (!bpf_prog_check_recur(prog))
> +   return NO_PRIV_STACK;
>
> which would mean that iter, lsm, struct_ops will not be allowed
> to use priv stack.

One example is e.g. a TC prog. Since bpf_prog_check_recur(prog)
will return true (means supporting recursion), and private stack
does not really support TC prog, the logic will become more
complicated.

I am totally okay with removing patch 2 and go back to my
previous approach to explicitly list prog types supporting
private stack.

>
> Unless struct_ops will explicit request priv stack via bool flag.
> Then we will also add recursion protection in trampoline.
Alexei Starovoitov Nov. 5, 2024, 3:50 p.m. UTC | #8
On Mon, Nov 4, 2024 at 10:02 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>
> >
> > I also don't understand the point of this patch 2.
> > The patch 3 can still do:
> >
> > + switch (prog->type) {
> > + case BPF_PROG_TYPE_KPROBE:
> > + case BPF_PROG_TYPE_TRACEPOINT:
> > + case BPF_PROG_TYPE_PERF_EVENT:
> > + case BPF_PROG_TYPE_RAW_TRACEPOINT:
> > +   return PRIV_STACK_ADAPTIVE;
> > + default:
> > +   break;
> > + }
> > +
> > + if (!bpf_prog_check_recur(prog))
> > +   return NO_PRIV_STACK;
> >
> > which would mean that iter, lsm, struct_ops will not be allowed
> > to use priv stack.
>
> One example is e.g. a TC prog. Since bpf_prog_check_recur(prog)
> will return true (means supporting recursion), and private stack
> does not really support TC prog, the logic will become more
> complicated.
>
> I am totally okay with removing patch 2 and go back to my
> previous approach to explicitly list prog types supporting
> private stack.

The point of reusing bpf_prog_check_recur() is that we don't
need to duplicate the logic.
We can still do something like:
switch (prog->type) {
 case BPF_PROG_TYPE_KPROBE:
 case BPF_PROG_TYPE_TRACEPOINT:
 case BPF_PROG_TYPE_PERF_EVENT:
 case BPF_PROG_TYPE_RAW_TRACEPOINT:
    return PRIV_STACK_ADAPTIVE;
 case BPF_PROG_TYPE_TRACING:
 case BPF_PROG_TYPE_LSM:
 case BPF_PROG_TYPE_STRUCT_OPS:
    if (bpf_prog_check_recur())
      return PRIV_STACK_ADAPTIVE;
    /* fallthrough */
  default:
    return NO_PRIV_STACK;
}
Yonghong Song Nov. 5, 2024, 4:33 p.m. UTC | #9
On 11/5/24 7:50 AM, Alexei Starovoitov wrote:
> On Mon, Nov 4, 2024 at 10:02 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>>> I also don't understand the point of this patch 2.
>>> The patch 3 can still do:
>>>
>>> + switch (prog->type) {
>>> + case BPF_PROG_TYPE_KPROBE:
>>> + case BPF_PROG_TYPE_TRACEPOINT:
>>> + case BPF_PROG_TYPE_PERF_EVENT:
>>> + case BPF_PROG_TYPE_RAW_TRACEPOINT:
>>> +   return PRIV_STACK_ADAPTIVE;
>>> + default:
>>> +   break;
>>> + }
>>> +
>>> + if (!bpf_prog_check_recur(prog))
>>> +   return NO_PRIV_STACK;
>>>
>>> which would mean that iter, lsm, struct_ops will not be allowed
>>> to use priv stack.
>> One example is e.g. a TC prog. Since bpf_prog_check_recur(prog)
>> will return true (means supporting recursion), and private stack
>> does not really support TC prog, the logic will become more
>> complicated.
>>
>> I am totally okay with removing patch 2 and go back to my
>> previous approach to explicitly list prog types supporting
>> private stack.
> The point of reusing bpf_prog_check_recur() is that we don't
> need to duplicate the logic.
> We can still do something like:
> switch (prog->type) {
>   case BPF_PROG_TYPE_KPROBE:
>   case BPF_PROG_TYPE_TRACEPOINT:
>   case BPF_PROG_TYPE_PERF_EVENT:
>   case BPF_PROG_TYPE_RAW_TRACEPOINT:
>      return PRIV_STACK_ADAPTIVE;
>   case BPF_PROG_TYPE_TRACING:
>   case BPF_PROG_TYPE_LSM:
>   case BPF_PROG_TYPE_STRUCT_OPS:
>      if (bpf_prog_check_recur())
>        return PRIV_STACK_ADAPTIVE;
>      /* fallthrough */
>    default:
>      return NO_PRIV_STACK;
> }

Right. Listing trampoline related prog types explicitly
and using bpf_prog_check_recur() will be safe.

One thing is for BPF_PROG_TYPE_STRUCT_OPS, PRIV_STACK_ALWAYS
will be returned. I will make adjustment like

switch (prog->type) {
  case BPF_PROG_TYPE_KPROBE:
  case BPF_PROG_TYPE_TRACEPOINT:
  case BPF_PROG_TYPE_PERF_EVENT:
  case BPF_PROG_TYPE_RAW_TRACEPOINT:
     return PRIV_STACK_ADAPTIVE;
  case BPF_PROG_TYPE_TRACING:
  case BPF_PROG_TYPE_LSM:
  case BPF_PROG_TYPE_STRUCT_OPS:
     if (bpf_prog_check_recur()) {
       if (prog->type == BPF_PROG_TYPE_STRUCT_OPS)
           return PRIV_STACK_ALWAYS;
       else
           return PRIV_STACK_ADAPTIVE;
     }
     /* fallthrough */
   default:
     return NO_PRIV_STACK;
}
Alexei Starovoitov Nov. 5, 2024, 4:38 p.m. UTC | #10
On Tue, Nov 5, 2024 at 8:33 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>
>
>
>
> On 11/5/24 7:50 AM, Alexei Starovoitov wrote:
> > On Mon, Nov 4, 2024 at 10:02 PM Yonghong Song <yonghong.song@linux.dev> wrote:
> >>> I also don't understand the point of this patch 2.
> >>> The patch 3 can still do:
> >>>
> >>> + switch (prog->type) {
> >>> + case BPF_PROG_TYPE_KPROBE:
> >>> + case BPF_PROG_TYPE_TRACEPOINT:
> >>> + case BPF_PROG_TYPE_PERF_EVENT:
> >>> + case BPF_PROG_TYPE_RAW_TRACEPOINT:
> >>> +   return PRIV_STACK_ADAPTIVE;
> >>> + default:
> >>> +   break;
> >>> + }
> >>> +
> >>> + if (!bpf_prog_check_recur(prog))
> >>> +   return NO_PRIV_STACK;
> >>>
> >>> which would mean that iter, lsm, struct_ops will not be allowed
> >>> to use priv stack.
> >> One example is e.g. a TC prog. Since bpf_prog_check_recur(prog)
> >> will return true (means supporting recursion), and private stack
> >> does not really support TC prog, the logic will become more
> >> complicated.
> >>
> >> I am totally okay with removing patch 2 and go back to my
> >> previous approach to explicitly list prog types supporting
> >> private stack.
> > The point of reusing bpf_prog_check_recur() is that we don't
> > need to duplicate the logic.
> > We can still do something like:
> > switch (prog->type) {
> >   case BPF_PROG_TYPE_KPROBE:
> >   case BPF_PROG_TYPE_TRACEPOINT:
> >   case BPF_PROG_TYPE_PERF_EVENT:
> >   case BPF_PROG_TYPE_RAW_TRACEPOINT:
> >      return PRIV_STACK_ADAPTIVE;
> >   case BPF_PROG_TYPE_TRACING:
> >   case BPF_PROG_TYPE_LSM:
> >   case BPF_PROG_TYPE_STRUCT_OPS:
> >      if (bpf_prog_check_recur())
> >        return PRIV_STACK_ADAPTIVE;
> >      /* fallthrough */
> >    default:
> >      return NO_PRIV_STACK;
> > }
>
> Right. Listing trampoline related prog types explicitly
> and using bpf_prog_check_recur() will be safe.
>
> One thing is for BPF_PROG_TYPE_STRUCT_OPS, PRIV_STACK_ALWAYS
> will be returned. I will make adjustment like
>
> switch (prog->type) {
>   case BPF_PROG_TYPE_KPROBE:
>   case BPF_PROG_TYPE_TRACEPOINT:
>   case BPF_PROG_TYPE_PERF_EVENT:
>   case BPF_PROG_TYPE_RAW_TRACEPOINT:
>      return PRIV_STACK_ADAPTIVE;
>   case BPF_PROG_TYPE_TRACING:
>   case BPF_PROG_TYPE_LSM:
>   case BPF_PROG_TYPE_STRUCT_OPS:
>      if (bpf_prog_check_recur()) {
>        if (prog->type == BPF_PROG_TYPE_STRUCT_OPS)
>            return PRIV_STACK_ALWAYS;

hmm. definitely not unconditionally.
Only when explicitly requested in callback.

Something like this:
   case BPF_PROG_TYPE_TRACING:
   case BPF_PROG_TYPE_LSM:
      if (bpf_prog_check_recur())
         return PRIV_STACK_ADAPTIVE;
   case BPF_PROG_TYPE_STRUCT_OPS:
      if (prog->aux->priv_stack_requested)
         return PRIV_STACK_ALWAYS;
   default:
      return NO_PRIV_STACK;

and then we also change bpf_prog_check_recur()
 to return true when prog->aux->priv_stack_requested
Yonghong Song Nov. 5, 2024, 4:48 p.m. UTC | #11
On 11/5/24 8:38 AM, Alexei Starovoitov wrote:
> On Tue, Nov 5, 2024 at 8:33 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>>
>>
>>
>> On 11/5/24 7:50 AM, Alexei Starovoitov wrote:
>>> On Mon, Nov 4, 2024 at 10:02 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>>>>> I also don't understand the point of this patch 2.
>>>>> The patch 3 can still do:
>>>>>
>>>>> + switch (prog->type) {
>>>>> + case BPF_PROG_TYPE_KPROBE:
>>>>> + case BPF_PROG_TYPE_TRACEPOINT:
>>>>> + case BPF_PROG_TYPE_PERF_EVENT:
>>>>> + case BPF_PROG_TYPE_RAW_TRACEPOINT:
>>>>> +   return PRIV_STACK_ADAPTIVE;
>>>>> + default:
>>>>> +   break;
>>>>> + }
>>>>> +
>>>>> + if (!bpf_prog_check_recur(prog))
>>>>> +   return NO_PRIV_STACK;
>>>>>
>>>>> which would mean that iter, lsm, struct_ops will not be allowed
>>>>> to use priv stack.
>>>> One example is e.g. a TC prog. Since bpf_prog_check_recur(prog)
>>>> will return true (means supporting recursion), and private stack
>>>> does not really support TC prog, the logic will become more
>>>> complicated.
>>>>
>>>> I am totally okay with removing patch 2 and go back to my
>>>> previous approach to explicitly list prog types supporting
>>>> private stack.
>>> The point of reusing bpf_prog_check_recur() is that we don't
>>> need to duplicate the logic.
>>> We can still do something like:
>>> switch (prog->type) {
>>>    case BPF_PROG_TYPE_KPROBE:
>>>    case BPF_PROG_TYPE_TRACEPOINT:
>>>    case BPF_PROG_TYPE_PERF_EVENT:
>>>    case BPF_PROG_TYPE_RAW_TRACEPOINT:
>>>       return PRIV_STACK_ADAPTIVE;
>>>    case BPF_PROG_TYPE_TRACING:
>>>    case BPF_PROG_TYPE_LSM:
>>>    case BPF_PROG_TYPE_STRUCT_OPS:
>>>       if (bpf_prog_check_recur())
>>>         return PRIV_STACK_ADAPTIVE;
>>>       /* fallthrough */
>>>     default:
>>>       return NO_PRIV_STACK;
>>> }
>> Right. Listing trampoline related prog types explicitly
>> and using bpf_prog_check_recur() will be safe.
>>
>> One thing is for BPF_PROG_TYPE_STRUCT_OPS, PRIV_STACK_ALWAYS
>> will be returned. I will make adjustment like
>>
>> switch (prog->type) {
>>    case BPF_PROG_TYPE_KPROBE:
>>    case BPF_PROG_TYPE_TRACEPOINT:
>>    case BPF_PROG_TYPE_PERF_EVENT:
>>    case BPF_PROG_TYPE_RAW_TRACEPOINT:
>>       return PRIV_STACK_ADAPTIVE;
>>    case BPF_PROG_TYPE_TRACING:
>>    case BPF_PROG_TYPE_LSM:
>>    case BPF_PROG_TYPE_STRUCT_OPS:
>>       if (bpf_prog_check_recur()) {
>>         if (prog->type == BPF_PROG_TYPE_STRUCT_OPS)
>>             return PRIV_STACK_ALWAYS;
> hmm. definitely not unconditionally.
> Only when explicitly requested in callback.
>
> Something like this:
>     case BPF_PROG_TYPE_TRACING:
>     case BPF_PROG_TYPE_LSM:
>        if (bpf_prog_check_recur())
>           return PRIV_STACK_ADAPTIVE;
>     case BPF_PROG_TYPE_STRUCT_OPS:
>        if (prog->aux->priv_stack_requested)
>           return PRIV_STACK_ALWAYS;
>     default:
>        return NO_PRIV_STACK;
>
> and then we also change bpf_prog_check_recur()
>   to return true when prog->aux->priv_stack_requested

This works too. I had another thinking about
    case BPF_PROG_TYPE_LSM:
       if (bpf_prog_check_recur())
          return PRIV_STACK_ADAPTIVE;
    case BPF_PROG_TYPE_STRUCT_OPS:
       if (bpf_prog_check_recur())
          return PRIV_STACK_ALWAYS;

Note that in bpf_prog_check_recur(), for struct_ops,
will return prog->aux->priv_stack_request.
But think it is too verbose so didn't propose.

So explicitly using prog->aux->priv_stack_requested
is more visible. Maybe we can even do

    case BPF_PROG_TYPE_TRACING:
    case BPF_PROG_TYPE_LSM:
    case BPF_PROG_TYPE_STRUCT_OPS:
       if (prog->aux->priv_stack_requested)
          return PRIV_STACK_ALWYAS;
       else if (bpf_prog_check_recur())
          return PRIV_STACK_ADAPTIVE;
       /* fallthrough */
    default:
       return NO_PRIV_STACK;
Alexei Starovoitov Nov. 5, 2024, 5:47 p.m. UTC | #12
On Tue, Nov 5, 2024 at 8:48 AM Yonghong Song <yonghong.song@linux.dev> wrote:
>
>
>
>
> On 11/5/24 8:38 AM, Alexei Starovoitov wrote:
> > On Tue, Nov 5, 2024 at 8:33 AM Yonghong Song <yonghong.song@linux.dev> wrote:
> >>
> >>
> >>
> >> On 11/5/24 7:50 AM, Alexei Starovoitov wrote:
> >>> On Mon, Nov 4, 2024 at 10:02 PM Yonghong Song <yonghong.song@linux.dev> wrote:
> >>>>> I also don't understand the point of this patch 2.
> >>>>> The patch 3 can still do:
> >>>>>
> >>>>> + switch (prog->type) {
> >>>>> + case BPF_PROG_TYPE_KPROBE:
> >>>>> + case BPF_PROG_TYPE_TRACEPOINT:
> >>>>> + case BPF_PROG_TYPE_PERF_EVENT:
> >>>>> + case BPF_PROG_TYPE_RAW_TRACEPOINT:
> >>>>> +   return PRIV_STACK_ADAPTIVE;
> >>>>> + default:
> >>>>> +   break;
> >>>>> + }
> >>>>> +
> >>>>> + if (!bpf_prog_check_recur(prog))
> >>>>> +   return NO_PRIV_STACK;
> >>>>>
> >>>>> which would mean that iter, lsm, struct_ops will not be allowed
> >>>>> to use priv stack.
> >>>> One example is e.g. a TC prog. Since bpf_prog_check_recur(prog)
> >>>> will return true (means supporting recursion), and private stack
> >>>> does not really support TC prog, the logic will become more
> >>>> complicated.
> >>>>
> >>>> I am totally okay with removing patch 2 and go back to my
> >>>> previous approach to explicitly list prog types supporting
> >>>> private stack.
> >>> The point of reusing bpf_prog_check_recur() is that we don't
> >>> need to duplicate the logic.
> >>> We can still do something like:
> >>> switch (prog->type) {
> >>>    case BPF_PROG_TYPE_KPROBE:
> >>>    case BPF_PROG_TYPE_TRACEPOINT:
> >>>    case BPF_PROG_TYPE_PERF_EVENT:
> >>>    case BPF_PROG_TYPE_RAW_TRACEPOINT:
> >>>       return PRIV_STACK_ADAPTIVE;
> >>>    case BPF_PROG_TYPE_TRACING:
> >>>    case BPF_PROG_TYPE_LSM:
> >>>    case BPF_PROG_TYPE_STRUCT_OPS:
> >>>       if (bpf_prog_check_recur())
> >>>         return PRIV_STACK_ADAPTIVE;
> >>>       /* fallthrough */
> >>>     default:
> >>>       return NO_PRIV_STACK;
> >>> }
> >> Right. Listing trampoline related prog types explicitly
> >> and using bpf_prog_check_recur() will be safe.
> >>
> >> One thing is for BPF_PROG_TYPE_STRUCT_OPS, PRIV_STACK_ALWAYS
> >> will be returned. I will make adjustment like
> >>
> >> switch (prog->type) {
> >>    case BPF_PROG_TYPE_KPROBE:
> >>    case BPF_PROG_TYPE_TRACEPOINT:
> >>    case BPF_PROG_TYPE_PERF_EVENT:
> >>    case BPF_PROG_TYPE_RAW_TRACEPOINT:
> >>       return PRIV_STACK_ADAPTIVE;
> >>    case BPF_PROG_TYPE_TRACING:
> >>    case BPF_PROG_TYPE_LSM:
> >>    case BPF_PROG_TYPE_STRUCT_OPS:
> >>       if (bpf_prog_check_recur()) {
> >>         if (prog->type == BPF_PROG_TYPE_STRUCT_OPS)
> >>             return PRIV_STACK_ALWAYS;
> > hmm. definitely not unconditionally.
> > Only when explicitly requested in callback.
> >
> > Something like this:
> >     case BPF_PROG_TYPE_TRACING:
> >     case BPF_PROG_TYPE_LSM:
> >        if (bpf_prog_check_recur())
> >           return PRIV_STACK_ADAPTIVE;
> >     case BPF_PROG_TYPE_STRUCT_OPS:
> >        if (prog->aux->priv_stack_requested)
> >           return PRIV_STACK_ALWAYS;
> >     default:
> >        return NO_PRIV_STACK;
> >
> > and then we also change bpf_prog_check_recur()
> >   to return true when prog->aux->priv_stack_requested
>
> This works too. I had another thinking about
>     case BPF_PROG_TYPE_LSM:
>        if (bpf_prog_check_recur())
>           return PRIV_STACK_ADAPTIVE;
>     case BPF_PROG_TYPE_STRUCT_OPS:
>        if (bpf_prog_check_recur())
>           return PRIV_STACK_ALWAYS;
>
> Note that in bpf_prog_check_recur(), for struct_ops,
> will return prog->aux->priv_stack_request.
> But think it is too verbose so didn't propose.
>
> So explicitly using prog->aux->priv_stack_requested
> is more visible. Maybe we can even do
>
>     case BPF_PROG_TYPE_TRACING:
>     case BPF_PROG_TYPE_LSM:
>     case BPF_PROG_TYPE_STRUCT_OPS:
>        if (prog->aux->priv_stack_requested)
>           return PRIV_STACK_ALWYAS;
>        else if (bpf_prog_check_recur())
>           return PRIV_STACK_ADAPTIVE;
>        /* fallthrough */
>     default:
>        return NO_PRIV_STACK;

The last version makes sense to me.
bpf_prog_check_recur() should also return true when
prog->aux->priv_stack_requested to make sure trampoline adds a
run-time check.
diff mbox series

Patch

diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 4513372c5bc8..ad887c68d3e1 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -889,9 +889,8 @@  static inline bool bpf_prog_check_recur(const struct bpf_prog *prog)
 		return prog->expected_attach_type != BPF_TRACE_ITER;
 	case BPF_PROG_TYPE_STRUCT_OPS:
 	case BPF_PROG_TYPE_LSM:
-		return false;
 	default:
-		return true;
+		return false;
 	}
 }