History

bpf: Ensure type tags precede modifiers in BTF

It is guaranteed that for modifiers, clang always places type tags before other modifiers, and then the base type. We would like to rely on this guarantee inside the kernel to make it simple to parse type tags from BTF. However, a user would be allowed to construct a BTF without such guarantees. Hence, add a pass to check that in modifier chains, type tags only occur at the head of the chain, and then don't occur later in the chain. If we see a type tag, we can have one or more type tags preceding other modifiers that then never have another type tag. If we see other modifiers, all modifiers following them should never be a type tag. Instead of having to walk chains we verified previously, we can remember the last good modifier type ID which headed a good chain. At that point, we must have verified all other chains headed by type IDs less than it. This makes the verification process less costly, and it becomes a simple O(n) pass.

Kumar Kartikeya Dwivedi committed 4 years ago

Commit eb596b01 parent 0d7fefe1 file · +54 −0Browse files

Unified · Split

kernel/bpf/btf.c+54−0
@@ -4541,6 +4541,48 @@ static int btf_parse_hdr(struct btf_verifier_env *env) · 4540 unmodified lines
4541 return 0;4541 return 0;
4542}4542}
4543 4543
4544static int btf_check_type_tags(struct btf_verifier_env *env,
4545 struct btf *btf, int start_id)
4546{
4547 int i, n, good_id = start_id - 1;
4548 bool in_tags;
4549
4550 n = btf_nr_types(btf);
4551 for (i = start_id; i < n; i++) {
4552 const struct btf_type *t;
4553 u32 cur_id = i;
4554
4555 t = btf_type_by_id(btf, i);
4556 if (!t)
4557 return -EINVAL;
4558 if (!btf_type_is_modifier(t))
4559 continue;
4560
4561 cond_resched();
4562
4563 in_tags = btf_type_is_type_tag(t);
4564 while (btf_type_is_modifier(t)) {
4565 if (btf_type_is_type_tag(t)) {
4566 if (!in_tags) {
4567 btf_verifier_log(env, "Type tags don't precede modifiers");
4568 return -EINVAL;
4569 }
4570 } else if (in_tags) {
4571 in_tags = false;
4572 }
4573 if (cur_id <= good_id)
4574 break;
4575 /* Move to next type */
4576 cur_id = t->type;
4577 t = btf_type_by_id(btf, cur_id);
4578 if (!t)
4579 return -EINVAL;
4580 }
4581 good_id = i;
4582 }
4583 return 0;
4584}
4585
4544static struct btf *btf_parse(bpfptr_t btf_data, u32 btf_data_size,4586static struct btf *btf_parse(bpfptr_t btf_data, u32 btf_data_size,
4545 u32 log_level, char __user *log_ubuf, u32 log_size)4587 u32 log_level, char __user *log_ubuf, u32 log_size)
4546{4588{
@@ -4608,6 +4650,10 @@ static struct btf *btf_parse(bpfptr_t btf_data, u32 btf_data_size, · 61 unmodified lines
4608 if (err)4650 if (err)
4609 goto errout;4651 goto errout;
4610 4652
4653 err = btf_check_type_tags(env, btf, 1);
4654 if (err)
4655 goto errout;
4656
4611 if (log->level && bpf_verifier_log_full(log)) {4657 if (log->level && bpf_verifier_log_full(log)) {
4612 err = -ENOSPC;4658 err = -ENOSPC;
4613 goto errout;4659 goto errout;
@@ -4809,6 +4855,10 @@ struct btf *btf_parse_vmlinux(void) · 195 unmodified lines
4809 if (err)4855 if (err)
4810 goto errout;4856 goto errout;
4811 4857
4858 err = btf_check_type_tags(env, btf, 1);
4859 if (err)
4860 goto errout;
4861
4812 /* btf_parse_vmlinux() runs under bpf_verifier_lock */4862 /* btf_parse_vmlinux() runs under bpf_verifier_lock */
4813 bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);4863 bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
4814 4864
@@ -4894,6 +4944,10 @@ static struct btf *btf_parse_module(const char *module_name, const void *data, u · 79 unmodified lines
4894 if (err)4944 if (err)
4895 goto errout;4945 goto errout;
4896 4946
4947 err = btf_check_type_tags(env, btf, btf_nr_types(base_btf));
4948 if (err)
4949 goto errout;
4950
4897 btf_verifier_env_free(env);4951 btf_verifier_env_free(env);
4898 refcount_set(&btf->refcnt, 1);4952 refcount_set(&btf->refcnt, 1);
4899 return btf;4953 return btf;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t