diff mbox series

[bpf,v2,2/2] bpf: ensure main program has an extable

Message ID de425e99876dc6c344e1a4254894a3c81e71a2ec.1686166633.git.kjlx@templeofstupid.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series bpf: fix NULL dereference during extable search | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 20 this patch: 20
netdev/cc_maintainers success CCed 12 of 12 maintainers
netdev/build_clang success Errors and warnings before: 8 this patch: 8
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 Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 20 this patch: 20
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 7 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-PR fail PR summary
bpf/vmtest-bpf-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-VM_Test-5 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-11 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-13 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-15 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-VM_Test-16 fail Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-VM_Test-8 success Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-VM_Test-12 success Logs for test_progs on s390x with gcc

Commit Message

Krister Johansen June 7, 2023, 9:04 p.m. UTC
When bpf subprograms are in use, the main program is not jit'd after the
subprograms because jit_subprogs sets a value for prog->bpf_func upon
success.  Subsequent calls to the JIT are bypassed when this value is
non-NULL.  This leads to a situation where the main program and its
func[0] counterpart are both in the bpf kallsyms tree, but only func[0]
has an extable.  Extables are only created during JIT.  Now there are
two nearly identical program ksym entries in the tree, but only one has
an extable.  Depending upon how the entries are placed, there's a chance
that a fault will call search_extable on the aux with the NULL entry.

Since jit_subprogs already copies state from func[0] to the main
program, include the extable pointer in this state duplication.  The
alternative is to skip adding the main program to the bpf_kallsyms
table, but that would mean adding a check for subprograms into the
middle of bpf_prog_load.

Cc: stable@vger.kernel.org
Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs")
Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
---
 kernel/bpf/verifier.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Yonghong Song June 8, 2023, 5:38 p.m. UTC | #1
On 6/7/23 2:04 PM, Krister Johansen wrote:
> When bpf subprograms are in use, the main program is not jit'd after the
> subprograms because jit_subprogs sets a value for prog->bpf_func upon
> success.  Subsequent calls to the JIT are bypassed when this value is
> non-NULL.  This leads to a situation where the main program and its
> func[0] counterpart are both in the bpf kallsyms tree, but only func[0]
> has an extable.  Extables are only created during JIT.  Now there are
> two nearly identical program ksym entries in the tree, but only one has
> an extable.  Depending upon how the entries are placed, there's a chance
> that a fault will call search_extable on the aux with the NULL entry.
> 
> Since jit_subprogs already copies state from func[0] to the main
> program, include the extable pointer in this state duplication.  The
> alternative is to skip adding the main program to the bpf_kallsyms
> table, but that would mean adding a check for subprograms into the
> middle of bpf_prog_load.

I think having two early identical program ksym entries is bad.
When people 'cat /proc/kallsyms | grep <their program name>',
they will find two programs with identical kernel address but different
hash value. This is just very confusing. I think removing the
duplicate in kallsyms is better from user's perspective.

> 
> Cc: stable@vger.kernel.org
> Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs")
> Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
> ---
>   kernel/bpf/verifier.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5871aa78d01a..d6939db9fbf9 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -17242,6 +17242,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>   	prog->jited = 1;
>   	prog->bpf_func = func[0]->bpf_func;
>   	prog->jited_len = func[0]->jited_len;
> +	prog->aux->extable = func[0]->aux->extable;
>   	prog->aux->func = func;
>   	prog->aux->func_cnt = env->subprog_cnt;
>   	bpf_prog_jit_attempt_done(prog);
Alexei Starovoitov June 8, 2023, 10:01 p.m. UTC | #2
On Wed, Jun 7, 2023 at 2:04 PM Krister Johansen <kjlx@templeofstupid.com> wrote:
>
> When bpf subprograms are in use, the main program is not jit'd after the
> subprograms because jit_subprogs sets a value for prog->bpf_func upon
> success.  Subsequent calls to the JIT are bypassed when this value is
> non-NULL.  This leads to a situation where the main program and its
> func[0] counterpart are both in the bpf kallsyms tree, but only func[0]
> has an extable.  Extables are only created during JIT.  Now there are
> two nearly identical program ksym entries in the tree, but only one has
> an extable.  Depending upon how the entries are placed, there's a chance
> that a fault will call search_extable on the aux with the NULL entry.
>
> Since jit_subprogs already copies state from func[0] to the main
> program, include the extable pointer in this state duplication.  The
> alternative is to skip adding the main program to the bpf_kallsyms
> table, but that would mean adding a check for subprograms into the
> middle of bpf_prog_load.

adding a check to bpf_prog_load() isn't great. that's true, but...

> Cc: stable@vger.kernel.org
> Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs")
> Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
> ---
>  kernel/bpf/verifier.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5871aa78d01a..d6939db9fbf9 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -17242,6 +17242,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>         prog->jited = 1;
>         prog->bpf_func = func[0]->bpf_func;
>         prog->jited_len = func[0]->jited_len;
> +       prog->aux->extable = func[0]->aux->extable;

Why not to do this hunk and what I suggested earlier: start from func=1 ?
That will address double ksym insertion that Yonghong mentioned.
Krister Johansen June 8, 2023, 10:05 p.m. UTC | #3
On Thu, Jun 08, 2023 at 10:38:12AM -0700, Yonghong Song wrote:
> 
> 
> On 6/7/23 2:04 PM, Krister Johansen wrote:
> > When bpf subprograms are in use, the main program is not jit'd after the
> > subprograms because jit_subprogs sets a value for prog->bpf_func upon
> > success.  Subsequent calls to the JIT are bypassed when this value is
> > non-NULL.  This leads to a situation where the main program and its
> > func[0] counterpart are both in the bpf kallsyms tree, but only func[0]
> > has an extable.  Extables are only created during JIT.  Now there are
> > two nearly identical program ksym entries in the tree, but only one has
> > an extable.  Depending upon how the entries are placed, there's a chance
> > that a fault will call search_extable on the aux with the NULL entry.
> > 
> > Since jit_subprogs already copies state from func[0] to the main
> > program, include the extable pointer in this state duplication.  The
> > alternative is to skip adding the main program to the bpf_kallsyms
> > table, but that would mean adding a check for subprograms into the
> > middle of bpf_prog_load.
> 
> I think having two early identical program ksym entries is bad.
> When people 'cat /proc/kallsyms | grep <their program name>',
> they will find two programs with identical kernel address but different
> hash value. This is just very confusing. I think removing the
> duplicate in kallsyms is better from user's perspective.

Thanks for all the feedback.

In terms of resolving this confusion my inclination is to use the main
program. That way users see in kallsyms the same tag that is reported by
bpftool.  On the other hand, the tag in kallsyms won't match the sha1 of
that actual chunk of code.  Is anything relying on the hash in the tag
and the digest of the code agreeing?

-K
Krister Johansen June 9, 2023, 12:09 a.m. UTC | #4
On Thu, Jun 08, 2023 at 03:01:36PM -0700, Alexei Starovoitov wrote:
> On Wed, Jun 7, 2023 at 2:04 PM Krister Johansen <kjlx@templeofstupid.com> wrote:
> > Cc: stable@vger.kernel.org
> > Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs")
> > Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
> > ---
> >  kernel/bpf/verifier.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 5871aa78d01a..d6939db9fbf9 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -17242,6 +17242,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> >         prog->jited = 1;
> >         prog->bpf_func = func[0]->bpf_func;
> >         prog->jited_len = func[0]->jited_len;
> > +       prog->aux->extable = func[0]->aux->extable;
> 
> Why not to do this hunk and what I suggested earlier: start from func=1 ?
> That will address double ksym insertion that Yonghong mentioned.

Sure thing.  Yonghong and you have convinced me.

I'll send out a v3 with all changes requested so far.

-K
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5871aa78d01a..d6939db9fbf9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -17242,6 +17242,7 @@  static int jit_subprogs(struct bpf_verifier_env *env)
 	prog->jited = 1;
 	prog->bpf_func = func[0]->bpf_func;
 	prog->jited_len = func[0]->jited_len;
+	prog->aux->extable = func[0]->aux->extable;
 	prog->aux->func = func;
 	prog->aux->func_cnt = env->subprog_cnt;
 	bpf_prog_jit_attempt_done(prog);