diff options
| author | Martin KaFai Lau <kafai@fb.com> | 2018-07-20 20:38:37 -0400 |
|---|---|---|
| committer | Daniel Borkmann <daniel@iogearbox.net> | 2018-07-23 19:20:44 -0400 |
| commit | 6283fa38dc8744dc7c2bd2a03bb0478fe42f79fa (patch) | |
| tree | 5c196acf3b4827da8059920bc97148106e8739d9 /kernel/bpf | |
| parent | 1a4f14bab1868b443f0dd3c55b689a478f82e72e (diff) | |
bpf: btf: Ensure the member->offset is in the right order
This patch ensures the member->offset of a struct
is in the correct order (i.e the later member's offset cannot
go backward).
The current "pahole -J" BTF encoder does not generate something
like this. However, checking this can ensure future encoder
will not violate this.
Fixes: 69b693f0aefa ("bpf: btf: Introduce BPF Type Format (BTF)")
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/btf.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 9704934252b3..2590700237c1 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c | |||
| @@ -1519,9 +1519,9 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env, | |||
| 1519 | { | 1519 | { |
| 1520 | bool is_union = BTF_INFO_KIND(t->info) == BTF_KIND_UNION; | 1520 | bool is_union = BTF_INFO_KIND(t->info) == BTF_KIND_UNION; |
| 1521 | const struct btf_member *member; | 1521 | const struct btf_member *member; |
| 1522 | u32 meta_needed, last_offset; | ||
| 1522 | struct btf *btf = env->btf; | 1523 | struct btf *btf = env->btf; |
| 1523 | u32 struct_size = t->size; | 1524 | u32 struct_size = t->size; |
| 1524 | u32 meta_needed; | ||
| 1525 | u16 i; | 1525 | u16 i; |
| 1526 | 1526 | ||
| 1527 | meta_needed = btf_type_vlen(t) * sizeof(*member); | 1527 | meta_needed = btf_type_vlen(t) * sizeof(*member); |
| @@ -1534,6 +1534,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env, | |||
| 1534 | 1534 | ||
| 1535 | btf_verifier_log_type(env, t, NULL); | 1535 | btf_verifier_log_type(env, t, NULL); |
| 1536 | 1536 | ||
| 1537 | last_offset = 0; | ||
| 1537 | for_each_member(i, t, member) { | 1538 | for_each_member(i, t, member) { |
| 1538 | if (!btf_name_offset_valid(btf, member->name_off)) { | 1539 | if (!btf_name_offset_valid(btf, member->name_off)) { |
| 1539 | btf_verifier_log_member(env, t, member, | 1540 | btf_verifier_log_member(env, t, member, |
| @@ -1555,6 +1556,16 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env, | |||
| 1555 | return -EINVAL; | 1556 | return -EINVAL; |
| 1556 | } | 1557 | } |
| 1557 | 1558 | ||
| 1559 | /* | ||
| 1560 | * ">" instead of ">=" because the last member could be | ||
| 1561 | * "char a[0];" | ||
| 1562 | */ | ||
| 1563 | if (last_offset > member->offset) { | ||
| 1564 | btf_verifier_log_member(env, t, member, | ||
| 1565 | "Invalid member bits_offset"); | ||
| 1566 | return -EINVAL; | ||
| 1567 | } | ||
| 1568 | |||
| 1558 | if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) { | 1569 | if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) { |
| 1559 | btf_verifier_log_member(env, t, member, | 1570 | btf_verifier_log_member(env, t, member, |
| 1560 | "Memmber bits_offset exceeds its struct size"); | 1571 | "Memmber bits_offset exceeds its struct size"); |
| @@ -1562,6 +1573,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env, | |||
| 1562 | } | 1573 | } |
| 1563 | 1574 | ||
| 1564 | btf_verifier_log_member(env, t, member, NULL); | 1575 | btf_verifier_log_member(env, t, member, NULL); |
| 1576 | last_offset = member->offset; | ||
| 1565 | } | 1577 | } |
| 1566 | 1578 | ||
| 1567 | return meta_needed; | 1579 | return meta_needed; |
