diff options
author | Alexei Starovoitov <ast@kernel.org> | 2020-03-10 20:00:42 +0300 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2020-03-10 20:00:47 +0300 |
commit | f7861a55b1ce35d0cacfd1f0435f46533dbc9b67 (patch) | |
tree | 524f44a063aa249f4b93668b0149564311175cc7 | |
parent | 1d8006abaab4cb90f81add86e8d1bf9411add05a (diff) | |
parent | 6ffe559a77d1c963a3567f7a39a5419bdcdc4f1c (diff) | |
download | linux-f7861a55b1ce35d0cacfd1f0435f46533dbc9b67.tar.xz |
Merge branch 'fix-BTF-enum'
Yoshiki Komachi says:
====================
btf_enum_check_member() checked if the size of "enum" as a struct
member exceeded struct_size or not. Then, the function compared it
with the size of "int". Although the size of "enum" is 4-byte by
default (i.e., equivalent to "int"), the packing feature enables
us to reduce it, as illustrated by the following example:
struct A {
char m;
enum { E0, E1 } __attribute__((packed)) n;
};
With such a setup above, the bpf loader gave an error attempting
to load it:
------------------------------------------------------------------
...
[3] ENUM (anon) size=1 vlen=2
E0 val=0
E1 val=1
[4] STRUCT A size=2 vlen=2
m type_id=2 bits_offset=0
n type_id=3 bits_offset=8
[4] STRUCT A size=2 vlen=2
n type_id=3 bits_offset=8 Member exceeds struct_size
libbpf: Error loading .BTF into kernel: -22.
------------------------------------------------------------------
The related issue was previously fixed by the commit 9eea98497951 ("bpf:
fix BTF verification of enums"). On the other hand, this series fixes
this issue as well, and adds a selftest program for it.
Changes in v2:
- change an example in commit message based on Andrii's review
- add a selftest program for packed "enum" type members in struct/union
====================
Acked-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r-- | kernel/bpf/btf.c | 2 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_btf.c | 42 |
2 files changed, 43 insertions, 1 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 787140095e58..32ab9225026e 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -2418,7 +2418,7 @@ static int btf_enum_check_member(struct btf_verifier_env *env, struct_size = struct_type->size; bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off); - if (struct_size - bytes_offset < sizeof(int)) { + if (struct_size - bytes_offset < member_type->size) { btf_verifier_log_member(env, struct_type, member, "Member exceeds struct_size"); return -EINVAL; diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index 93040ca83e60..8da77cda5f4a 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -1062,6 +1062,48 @@ static struct btf_raw_test raw_tests[] = { .err_str = "Member exceeds struct_size", }, +/* Test member unexceeds the size of struct + * + * enum E { + * E0, + * E1, + * }; + * + * struct A { + * char m; + * enum E __attribute__((packed)) n; + * }; + */ +{ + .descr = "size check test #5", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, sizeof(int)), + /* char */ /* [2] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), + /* enum E { */ /* [3] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 2), 1), + BTF_ENUM_ENC(NAME_TBD, 0), + BTF_ENUM_ENC(NAME_TBD, 1), + /* } */ + /* struct A { */ /* [4] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 2), + BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* char m; */ + BTF_MEMBER_ENC(NAME_TBD, 3, 8),/* enum E __attribute__((packed)) n; */ + /* } */ + BTF_END_RAW, + }, + .str_sec = "\0E\0E0\0E1\0A\0m\0n", + .str_sec_size = sizeof("\0E\0E0\0E1\0A\0m\0n"), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "size_check5_map", + .key_size = sizeof(int), + .value_size = 2, + .key_type_id = 1, + .value_type_id = 4, + .max_entries = 4, +}, + /* typedef const void * const_void_ptr; * struct A { * const_void_ptr m; |