diff options
-rw-r--r-- | include/linux/btf.h | 5 | ||||
-rw-r--r-- | kernel/bpf/btf.c | 37 | ||||
-rw-r--r-- | kernel/bpf/local_storage.c | 17 |
3 files changed, 36 insertions, 23 deletions
diff --git a/include/linux/btf.h b/include/linux/btf.h index 58000d7e06e3..12502e25e767 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | 8 | ||
9 | struct btf; | 9 | struct btf; |
10 | struct btf_member; | ||
10 | struct btf_type; | 11 | struct btf_type; |
11 | union bpf_attr; | 12 | union bpf_attr; |
12 | 13 | ||
@@ -46,7 +47,9 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj, | |||
46 | struct seq_file *m); | 47 | struct seq_file *m); |
47 | int btf_get_fd_by_id(u32 id); | 48 | int btf_get_fd_by_id(u32 id); |
48 | u32 btf_id(const struct btf *btf); | 49 | u32 btf_id(const struct btf *btf); |
49 | bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size); | 50 | bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s, |
51 | const struct btf_member *m, | ||
52 | u32 expected_offset, u32 expected_size); | ||
50 | 53 | ||
51 | #ifdef CONFIG_BPF_SYSCALL | 54 | #ifdef CONFIG_BPF_SYSCALL |
52 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); | 55 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); |
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 93b6905e3a9b..e804b26a0506 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c | |||
@@ -546,22 +546,41 @@ static bool btf_type_int_is_regular(const struct btf_type *t) | |||
546 | } | 546 | } |
547 | 547 | ||
548 | /* | 548 | /* |
549 | * Check that given type is a regular int and has the expected size. | 549 | * Check that given struct member is a regular int with expected |
550 | * offset and size. | ||
550 | */ | 551 | */ |
551 | bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size) | 552 | bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s, |
553 | const struct btf_member *m, | ||
554 | u32 expected_offset, u32 expected_size) | ||
552 | { | 555 | { |
553 | u8 nr_bits, nr_bytes; | 556 | const struct btf_type *t; |
554 | u32 int_data; | 557 | u32 id, int_data; |
558 | u8 nr_bits; | ||
555 | 559 | ||
556 | if (!btf_type_is_int(t)) | 560 | id = m->type; |
561 | t = btf_type_id_size(btf, &id, NULL); | ||
562 | if (!t || !btf_type_is_int(t)) | ||
557 | return false; | 563 | return false; |
558 | 564 | ||
559 | int_data = btf_type_int(t); | 565 | int_data = btf_type_int(t); |
560 | nr_bits = BTF_INT_BITS(int_data); | 566 | nr_bits = BTF_INT_BITS(int_data); |
561 | nr_bytes = BITS_ROUNDUP_BYTES(nr_bits); | 567 | if (btf_type_kflag(s)) { |
562 | if (BITS_PER_BYTE_MASKED(nr_bits) || | 568 | u32 bitfield_size = BTF_MEMBER_BITFIELD_SIZE(m->offset); |
563 | BTF_INT_OFFSET(int_data) || | 569 | u32 bit_offset = BTF_MEMBER_BIT_OFFSET(m->offset); |
564 | nr_bytes != expected_size) | 570 | |
571 | /* if kflag set, int should be a regular int and | ||
572 | * bit offset should be at byte boundary. | ||
573 | */ | ||
574 | return !bitfield_size && | ||
575 | BITS_ROUNDUP_BYTES(bit_offset) == expected_offset && | ||
576 | BITS_ROUNDUP_BYTES(nr_bits) == expected_size; | ||
577 | } | ||
578 | |||
579 | if (BTF_INT_OFFSET(int_data) || | ||
580 | BITS_PER_BYTE_MASKED(m->offset) || | ||
581 | BITS_ROUNDUP_BYTES(m->offset) != expected_offset || | ||
582 | BITS_PER_BYTE_MASKED(nr_bits) || | ||
583 | BITS_ROUNDUP_BYTES(nr_bits) != expected_size) | ||
565 | return false; | 584 | return false; |
566 | 585 | ||
567 | return true; | 586 | return true; |
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 5eca03da0989..07a34ef562a0 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c | |||
@@ -315,9 +315,8 @@ static int cgroup_storage_check_btf(const struct bpf_map *map, | |||
315 | const struct btf_type *key_type, | 315 | const struct btf_type *key_type, |
316 | const struct btf_type *value_type) | 316 | const struct btf_type *value_type) |
317 | { | 317 | { |
318 | const struct btf_type *t; | ||
319 | struct btf_member *m; | 318 | struct btf_member *m; |
320 | u32 id, size; | 319 | u32 offset, size; |
321 | 320 | ||
322 | /* Key is expected to be of struct bpf_cgroup_storage_key type, | 321 | /* Key is expected to be of struct bpf_cgroup_storage_key type, |
323 | * which is: | 322 | * which is: |
@@ -338,25 +337,17 @@ static int cgroup_storage_check_btf(const struct bpf_map *map, | |||
338 | * The first field must be a 64 bit integer at 0 offset. | 337 | * The first field must be a 64 bit integer at 0 offset. |
339 | */ | 338 | */ |
340 | m = (struct btf_member *)(key_type + 1); | 339 | m = (struct btf_member *)(key_type + 1); |
341 | if (m->offset) | ||
342 | return -EINVAL; | ||
343 | id = m->type; | ||
344 | t = btf_type_id_size(btf, &id, NULL); | ||
345 | size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, cgroup_inode_id); | 340 | size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, cgroup_inode_id); |
346 | if (!t || !btf_type_is_reg_int(t, size)) | 341 | if (!btf_member_is_reg_int(btf, key_type, m, 0, size)) |
347 | return -EINVAL; | 342 | return -EINVAL; |
348 | 343 | ||
349 | /* | 344 | /* |
350 | * The second field must be a 32 bit integer at 64 bit offset. | 345 | * The second field must be a 32 bit integer at 64 bit offset. |
351 | */ | 346 | */ |
352 | m++; | 347 | m++; |
353 | if (m->offset != offsetof(struct bpf_cgroup_storage_key, attach_type) * | 348 | offset = offsetof(struct bpf_cgroup_storage_key, attach_type); |
354 | BITS_PER_BYTE) | ||
355 | return -EINVAL; | ||
356 | id = m->type; | ||
357 | t = btf_type_id_size(btf, &id, NULL); | ||
358 | size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, attach_type); | 349 | size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, attach_type); |
359 | if (!t || !btf_type_is_reg_int(t, size)) | 350 | if (!btf_member_is_reg_int(btf, key_type, m, offset, size)) |
360 | return -EINVAL; | 351 | return -EINVAL; |
361 | 352 | ||
362 | return 0; | 353 | return 0; |