diff mbox series

[bpf-next] bpf: bpf_core_calc_relo_insn() should verify relocation type id

Message ID 20240821164620.1056362-1-eddyz87@gmail.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series [bpf-next] bpf: bpf_core_calc_relo_insn() should verify relocation type id | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
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: 42 this patch: 42
netdev/build_tools success Errors and warnings before: 2 this patch: 2
netdev/cc_maintainers warning 6 maintainers not CCed: song@kernel.org sdf@fomichev.me haoluo@google.com jolsa@kernel.org kpsingh@kernel.org john.fastabend@gmail.com
netdev/build_clang success Errors and warnings before: 43 this patch: 43
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: 43 this patch: 43
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 11 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
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 fail Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 fail Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat

Commit Message

Eduard Zingerman Aug. 21, 2024, 4:46 p.m. UTC
In case of malformed relocation record of kind BPF_CORE_TYPE_ID_LOCAL
referencing a non-existing BTF type, function bpf_core_calc_relo_insn
would cause a null pointer deference.

Fix this by adding a proper check, as malformed relocation records
could be passed from user space.

Simplest reproducer is a program:

    r0 = 0
    exit

With a single relocation record:

    .insn_off = 0,          /* patch first instruction */
    .type_id = 100500,      /* this type id does not exist */
    .access_str_off = 6,    /* offset of string "0" */
    .kind = BPF_CORE_TYPE_ID_LOCAL,

See the link for original reproducer.

Fixes: 74753e1462e7 ("libbpf: Replace btf__type_by_id() with btf_type_by_id().")
Reported-by: Liu RuiTong <cnitlrt@gmail.com>
Closes: https://lore.kernel.org/bpf/CAK55_s6do7C+DVwbwY_7nKfUz0YLDoiA1v6X3Y9+p0sWzipFSA@mail.gmail.com/
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 tools/lib/bpf/relo_core.c | 5 +++++
 1 file changed, 5 insertions(+)

Comments

Andrii Nakryiko Aug. 21, 2024, 4:59 p.m. UTC | #1
On Wed, Aug 21, 2024 at 9:46 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> In case of malformed relocation record of kind BPF_CORE_TYPE_ID_LOCAL
> referencing a non-existing BTF type, function bpf_core_calc_relo_insn
> would cause a null pointer deference.
>
> Fix this by adding a proper check, as malformed relocation records
> could be passed from user space.
>
> Simplest reproducer is a program:
>
>     r0 = 0
>     exit
>
> With a single relocation record:
>
>     .insn_off = 0,          /* patch first instruction */
>     .type_id = 100500,      /* this type id does not exist */
>     .access_str_off = 6,    /* offset of string "0" */
>     .kind = BPF_CORE_TYPE_ID_LOCAL,
>
> See the link for original reproducer.
>
> Fixes: 74753e1462e7 ("libbpf: Replace btf__type_by_id() with btf_type_by_id().")
> Reported-by: Liu RuiTong <cnitlrt@gmail.com>
> Closes: https://lore.kernel.org/bpf/CAK55_s6do7C+DVwbwY_7nKfUz0YLDoiA1v6X3Y9+p0sWzipFSA@mail.gmail.com/
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
>  tools/lib/bpf/relo_core.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
> index 63a4d5ad12d1..a04724831ebc 100644
> --- a/tools/lib/bpf/relo_core.c
> +++ b/tools/lib/bpf/relo_core.c
> @@ -1297,6 +1297,11 @@ int bpf_core_calc_relo_insn(const char *prog_name,
>
>         local_id = relo->type_id;
>         local_type = btf_type_by_id(local_btf, local_id);
> +       if (!local_type) {

This is a meaningless check at least for libbpf's implementation of
btf_type_by_id(), it never returns NULL. Commit you point to in Fixes
tag clearly states the differences.

So you'd need to validate local_id directly against number of types in
local_btf.

pw-bot: cr


> +               pr_warn("prog '%s': relo #%d: bad type id %u\n",

nit: this part of CO-RE-related code normally uses [%u] "syntax" to
point to BTF type IDs, please adjust for consistency

> +                       prog_name, relo_idx, local_id);
> +               return -EINVAL;
> +       }
>         local_name = btf__name_by_offset(local_btf, local_type->name_off);
>         if (!local_name)
>                 return -EINVAL;
> --
> 2.45.2
>
Eduard Zingerman Aug. 21, 2024, 5:46 p.m. UTC | #2
On Wed, 2024-08-21 at 09:59 -0700, Andrii Nakryiko wrote:

[...]

> > Fixes: 74753e1462e7 ("libbpf: Replace btf__type_by_id() with btf_type_by_id().")
> > Reported-by: Liu RuiTong <cnitlrt@gmail.com>
> > Closes: https://lore.kernel.org/bpf/CAK55_s6do7C+DVwbwY_7nKfUz0YLDoiA1v6X3Y9+p0sWzipFSA@mail.gmail.com/
> > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > ---
> >  tools/lib/bpf/relo_core.c | 5 +++++
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
> > index 63a4d5ad12d1..a04724831ebc 100644
> > --- a/tools/lib/bpf/relo_core.c
> > +++ b/tools/lib/bpf/relo_core.c
> > @@ -1297,6 +1297,11 @@ int bpf_core_calc_relo_insn(const char *prog_name,
> > 
> >         local_id = relo->type_id;
> >         local_type = btf_type_by_id(local_btf, local_id);
> > +       if (!local_type) {
> 
> This is a meaningless check at least for libbpf's implementation of
> btf_type_by_id(), it never returns NULL. Commit you point to in Fixes
> tag clearly states the differences.

That is not true on kernel side.
bpf_core_calc_relo_insn() is called from bpf_core_apply():

int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
                   int relo_idx, void *insn)
{
        bool need_cands = relo->kind != BPF_CORE_TYPE_ID_LOCAL;
        ...
        if (need_cands) {
                ...
                // code below would report an error if relo->type_id is bogus
                cc = bpf_core_find_cands(ctx, relo->type_id);
                if (IS_ERR(cc)) {
                        bpf_log(ctx->log, "target candidate search failed for %d\n",
                                relo->type_id);
                        err = PTR_ERR(cc);
                        goto out;
                }
                ...
        }

        err = bpf_core_calc_relo_insn((void *)ctx->log, relo, relo_idx, ctx->btf, &cands, specs,
                                      &targ_res);
        ...
}

If `need_cands` is false the bogus type_id could reach into bpf_core_calc_relo_insn().
Which is exactly the case with repro submitted by Liu.
There is also a simplified repro here:
https://github.com/kernel-patches/bpf/commit/017a9dcf17e572f9b7c32aa62a81df8ef41cef17
But I can't submit it as a test yet.

> 
> So you'd need to validate local_id directly against number of types in
> local_btf.

How is this better than a null check?

> 
> pw-bot: cr
> 
> 
> > +               pr_warn("prog '%s': relo #%d: bad type id %u\n",
> 
> nit: this part of CO-RE-related code normally uses [%u] "syntax" to
> point to BTF type IDs, please adjust for consistency

Ok
Andrii Nakryiko Aug. 21, 2024, 7:10 p.m. UTC | #3
On Wed, Aug 21, 2024 at 10:46 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Wed, 2024-08-21 at 09:59 -0700, Andrii Nakryiko wrote:
>
> [...]
>
> > > Fixes: 74753e1462e7 ("libbpf: Replace btf__type_by_id() with btf_type_by_id().")
> > > Reported-by: Liu RuiTong <cnitlrt@gmail.com>
> > > Closes: https://lore.kernel.org/bpf/CAK55_s6do7C+DVwbwY_7nKfUz0YLDoiA1v6X3Y9+p0sWzipFSA@mail.gmail.com/
> > > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > > ---
> > >  tools/lib/bpf/relo_core.c | 5 +++++
> > >  1 file changed, 5 insertions(+)
> > >
> > > diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
> > > index 63a4d5ad12d1..a04724831ebc 100644
> > > --- a/tools/lib/bpf/relo_core.c
> > > +++ b/tools/lib/bpf/relo_core.c
> > > @@ -1297,6 +1297,11 @@ int bpf_core_calc_relo_insn(const char *prog_name,
> > >
> > >         local_id = relo->type_id;
> > >         local_type = btf_type_by_id(local_btf, local_id);
> > > +       if (!local_type) {
> >
> > This is a meaningless check at least for libbpf's implementation of
> > btf_type_by_id(), it never returns NULL. Commit you point to in Fixes
> > tag clearly states the differences.
>
> That is not true on kernel side.
> bpf_core_calc_relo_insn() is called from bpf_core_apply():
>
> int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
>                    int relo_idx, void *insn)
> {
>         bool need_cands = relo->kind != BPF_CORE_TYPE_ID_LOCAL;
>         ...
>         if (need_cands) {
>                 ...
>                 // code below would report an error if relo->type_id is bogus
>                 cc = bpf_core_find_cands(ctx, relo->type_id);
>                 if (IS_ERR(cc)) {
>                         bpf_log(ctx->log, "target candidate search failed for %d\n",
>                                 relo->type_id);
>                         err = PTR_ERR(cc);
>                         goto out;
>                 }
>                 ...
>         }
>
>         err = bpf_core_calc_relo_insn((void *)ctx->log, relo, relo_idx, ctx->btf, &cands, specs,
>                                       &targ_res);
>         ...
> }
>
> If `need_cands` is false the bogus type_id could reach into bpf_core_calc_relo_insn().
> Which is exactly the case with repro submitted by Liu.
> There is also a simplified repro here:
> https://github.com/kernel-patches/bpf/commit/017a9dcf17e572f9b7c32aa62a81df8ef41cef17
> But I can't submit it as a test yet.
>
> >
> > So you'd need to validate local_id directly against number of types in
> > local_btf.
>
> How is this better than a null check?
>

because id check will be useful for both kernel and libbpf sides?..

> >
> > pw-bot: cr
> >
> >
> > > +               pr_warn("prog '%s': relo #%d: bad type id %u\n",
> >
> > nit: this part of CO-RE-related code normally uses [%u] "syntax" to
> > point to BTF type IDs, please adjust for consistency
>
> Ok
>
Eduard Zingerman Aug. 21, 2024, 7:28 p.m. UTC | #4
On Wed, 2024-08-21 at 12:10 -0700, Andrii Nakryiko wrote:
> On Wed, Aug 21, 2024 at 10:46 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> > 
> > On Wed, 2024-08-21 at 09:59 -0700, Andrii Nakryiko wrote:
> > 
> > [...]
> > 
> > > > Fixes: 74753e1462e7 ("libbpf: Replace btf__type_by_id() with btf_type_by_id().")
> > > > Reported-by: Liu RuiTong <cnitlrt@gmail.com>
> > > > Closes: https://lore.kernel.org/bpf/CAK55_s6do7C+DVwbwY_7nKfUz0YLDoiA1v6X3Y9+p0sWzipFSA@mail.gmail.com/
> > > > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > > > ---
> > > >  tools/lib/bpf/relo_core.c | 5 +++++
> > > >  1 file changed, 5 insertions(+)
> > > > 
> > > > diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
> > > > index 63a4d5ad12d1..a04724831ebc 100644
> > > > --- a/tools/lib/bpf/relo_core.c
> > > > +++ b/tools/lib/bpf/relo_core.c
> > > > @@ -1297,6 +1297,11 @@ int bpf_core_calc_relo_insn(const char *prog_name,
> > > > 
> > > >         local_id = relo->type_id;
> > > >         local_type = btf_type_by_id(local_btf, local_id);
> > > > +       if (!local_type) {
> > > 
> > > This is a meaningless check at least for libbpf's implementation of
> > > btf_type_by_id(), it never returns NULL. Commit you point to in Fixes
> > > tag clearly states the differences.
> > 
> > That is not true on kernel side.
> > bpf_core_calc_relo_insn() is called from bpf_core_apply():
> > 
> > int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
> >                    int relo_idx, void *insn)
> > {
> >         bool need_cands = relo->kind != BPF_CORE_TYPE_ID_LOCAL;
> >         ...
> >         if (need_cands) {
> >                 ...
> >                 // code below would report an error if relo->type_id is bogus
> >                 cc = bpf_core_find_cands(ctx, relo->type_id);
> >                 if (IS_ERR(cc)) {
> >                         bpf_log(ctx->log, "target candidate search failed for %d\n",
> >                                 relo->type_id);
> >                         err = PTR_ERR(cc);
> >                         goto out;
> >                 }
> >                 ...
> >         }
> > 
> >         err = bpf_core_calc_relo_insn((void *)ctx->log, relo, relo_idx, ctx->btf, &cands, specs,
> >                                       &targ_res);
> >         ...
> > }
> > 
> > If `need_cands` is false the bogus type_id could reach into bpf_core_calc_relo_insn().
> > Which is exactly the case with repro submitted by Liu.
> > There is also a simplified repro here:
> > https://github.com/kernel-patches/bpf/commit/017a9dcf17e572f9b7c32aa62a81df8ef41cef17
> > But I can't submit it as a test yet.
> > 
> > > 
> > > So you'd need to validate local_id directly against number of types in
> > > local_btf.
> > 
> > How is this better than a null check?
> > 
> 
> because id check will be useful for both kernel and libbpf sides?..

This would require a special case for BPF_CORE_TYPE_ID_LOCAL in
bpf_core_calc_relo_insn(). If you don't like this null check I'll
modify bpf_core_apply() instead to always check relo->type_id and
report and error.

This would also be in the line with what bpf_core_resolve_relo()
does on libbpf side.

[...]
Andrii Nakryiko Aug. 21, 2024, 8:08 p.m. UTC | #5
On Wed, Aug 21, 2024 at 12:29 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Wed, 2024-08-21 at 12:10 -0700, Andrii Nakryiko wrote:
> > On Wed, Aug 21, 2024 at 10:46 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> > >
> > > On Wed, 2024-08-21 at 09:59 -0700, Andrii Nakryiko wrote:
> > >
> > > [...]
> > >
> > > > > Fixes: 74753e1462e7 ("libbpf: Replace btf__type_by_id() with btf_type_by_id().")
> > > > > Reported-by: Liu RuiTong <cnitlrt@gmail.com>
> > > > > Closes: https://lore.kernel.org/bpf/CAK55_s6do7C+DVwbwY_7nKfUz0YLDoiA1v6X3Y9+p0sWzipFSA@mail.gmail.com/
> > > > > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > > > > ---
> > > > >  tools/lib/bpf/relo_core.c | 5 +++++
> > > > >  1 file changed, 5 insertions(+)
> > > > >
> > > > > diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
> > > > > index 63a4d5ad12d1..a04724831ebc 100644
> > > > > --- a/tools/lib/bpf/relo_core.c
> > > > > +++ b/tools/lib/bpf/relo_core.c
> > > > > @@ -1297,6 +1297,11 @@ int bpf_core_calc_relo_insn(const char *prog_name,
> > > > >
> > > > >         local_id = relo->type_id;
> > > > >         local_type = btf_type_by_id(local_btf, local_id);
> > > > > +       if (!local_type) {
> > > >
> > > > This is a meaningless check at least for libbpf's implementation of
> > > > btf_type_by_id(), it never returns NULL. Commit you point to in Fixes
> > > > tag clearly states the differences.
> > >
> > > That is not true on kernel side.
> > > bpf_core_calc_relo_insn() is called from bpf_core_apply():
> > >
> > > int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
> > >                    int relo_idx, void *insn)
> > > {
> > >         bool need_cands = relo->kind != BPF_CORE_TYPE_ID_LOCAL;
> > >         ...
> > >         if (need_cands) {
> > >                 ...
> > >                 // code below would report an error if relo->type_id is bogus
> > >                 cc = bpf_core_find_cands(ctx, relo->type_id);
> > >                 if (IS_ERR(cc)) {
> > >                         bpf_log(ctx->log, "target candidate search failed for %d\n",
> > >                                 relo->type_id);
> > >                         err = PTR_ERR(cc);
> > >                         goto out;
> > >                 }
> > >                 ...
> > >         }
> > >
> > >         err = bpf_core_calc_relo_insn((void *)ctx->log, relo, relo_idx, ctx->btf, &cands, specs,
> > >                                       &targ_res);
> > >         ...
> > > }
> > >
> > > If `need_cands` is false the bogus type_id could reach into bpf_core_calc_relo_insn().
> > > Which is exactly the case with repro submitted by Liu.
> > > There is also a simplified repro here:
> > > https://github.com/kernel-patches/bpf/commit/017a9dcf17e572f9b7c32aa62a81df8ef41cef17
> > > But I can't submit it as a test yet.
> > >
> > > >
> > > > So you'd need to validate local_id directly against number of types in
> > > > local_btf.
> > >
> > > How is this better than a null check?
> > >
> >
> > because id check will be useful for both kernel and libbpf sides?..
>
> This would require a special case for BPF_CORE_TYPE_ID_LOCAL in
> bpf_core_calc_relo_insn(). If you don't like this null check I'll
> modify bpf_core_apply() instead to always check relo->type_id and
> report and error.
>
> This would also be in the line with what bpf_core_resolve_relo()
> does on libbpf side.

Ok, then let's do that. I don't want static analysers complaining
about this when checking libbpf code base.

>
> [...]
>
Eduard Zingerman Aug. 21, 2024, 10:32 p.m. UTC | #6
On Wed, 2024-08-21 at 13:08 -0700, Andrii Nakryiko wrote:

[...]

> Ok, then let's do that. I don't want static analysers complaining
> about this when checking libbpf code base.

Just want to rant a bit.
Here is a footgun in the relo_core.c:

    #ifdef __KERNEL__
    ...
    #undef pr_warn
    #undef pr_info
    #undef pr_debug
    #define pr_warn(fmt, log, ...)      bpf_log((void *)log, fmt, "", ##__VA_ARGS__)
    #define pr_info(fmt, log, ...)      bpf_log((void *)log, fmt, "", ##__VA_ARGS__)
    #define pr_debug(fmt, log, ...)     bpf_log((void *)log, fmt, "", ##__VA_ARGS__)
                          ^^^                   ^^^^^^^^^^^       ^^
                     first format param,        prog_name         replacement for
                     usually prog_name          cast to           first param
                                                verifier log
    ...
    #else
    ...
    #endif

    int bpf_core_calc_relo_insn(const char *prog_name, ...)
    {
        ...
        pr_warn("prog '%s': relo #%d: bad type id %u\n",
                prog_name, relo_idx, local_id);
        ...
    }

And in the verifier.c:

    err = bpf_core_calc_relo_insn((void *)ctx->log, relo, ...);
                                  ^^^^^^^^^^^^^^^^
                                  This is a prog_name parameter

Just spent more than an hour trying to figure out why passing real
program name (char *) does not work.
I'll think on a refactoring, but that is for another series.
Eduard Zingerman Aug. 21, 2024, 10:38 p.m. UTC | #7
On Wed, 2024-08-21 at 15:32 -0700, Eduard Zingerman wrote:

[...]

> Just spent more than an hour trying to figure out why passing real
> program name (char *) does not work.
> I'll think on a refactoring, but that is for another series.

I passed env->prog->aux->name there, and pr_warn caused corruption
of the aux structure. Sigh.
diff mbox series

Patch

diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
index 63a4d5ad12d1..a04724831ebc 100644
--- a/tools/lib/bpf/relo_core.c
+++ b/tools/lib/bpf/relo_core.c
@@ -1297,6 +1297,11 @@  int bpf_core_calc_relo_insn(const char *prog_name,
 
 	local_id = relo->type_id;
 	local_type = btf_type_by_id(local_btf, local_id);
+	if (!local_type) {
+		pr_warn("prog '%s': relo #%d: bad type id %u\n",
+			prog_name, relo_idx, local_id);
+		return -EINVAL;
+	}
 	local_name = btf__name_by_offset(local_btf, local_type->name_off);
 	if (!local_name)
 		return -EINVAL;