2022-01-08 02:22:35

by Yichun Zhang (agentzh)

[permalink] [raw]
Subject: [PATCH] bpf: btf: Fix a var size check in validator

The btf validator should croak when the variable size is larger than
its type size, not less. The LLVM optimizer may use smaller sizes for
the C type.

We ran into this issue with real-world BPF programs emitted by the
latest version of Clang/LLVM.

Fixes: 1dc92851849cc ("bpf: kernel side support for BTF Var and DataSec")
Signed-off-by: Yichun Zhang (agentzh) <[email protected]>
---
kernel/bpf/btf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 9bdb03767db5..2a6967b13ce1 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -3696,7 +3696,7 @@ static int btf_datasec_resolve(struct btf_verifier_env *env,
return -EINVAL;
}

- if (vsi->size < type_size) {
+ if (vsi->size > type_size) {
btf_verifier_log_vsi(env, v->t, vsi, "Invalid size");
return -EINVAL;
}
--
2.17.2



2022-01-08 18:54:21

by Yonghong Song

[permalink] [raw]
Subject: Re: [PATCH] bpf: btf: Fix a var size check in validator



On 1/7/22 6:22 PM, Yichun Zhang (agentzh) wrote:
> The btf validator should croak when the variable size is larger than
> its type size, not less. The LLVM optimizer may use smaller sizes for
> the C type.
>
> We ran into this issue with real-world BPF programs emitted by the
> latest version of Clang/LLVM.

Could you give an example to show we have variable size is less than
type_size?

>
> Fixes: 1dc92851849cc ("bpf: kernel side support for BTF Var and DataSec")
> Signed-off-by: Yichun Zhang (agentzh) <[email protected]>
> ---
> kernel/bpf/btf.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 9bdb03767db5..2a6967b13ce1 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -3696,7 +3696,7 @@ static int btf_datasec_resolve(struct btf_verifier_env *env,
> return -EINVAL;
> }
>
> - if (vsi->size < type_size) {
> + if (vsi->size > type_size) {
> btf_verifier_log_vsi(env, v->t, vsi, "Invalid size");
> return -EINVAL;
> }

The fix is incorrect. We do have cases where variable size greater than
type_size. For example,

$ cat t.c
struct t {
int g;
char a[];
} v = {1, {'a', 'b', 'c', 0}};

The type (struct t) size is 4, but the variable size is 8.