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

Showing the changes to kernel (1 of 1 file). Show all

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
45414541 return 0;
45424542 }
45434543
4544+static 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+
45444586 static struct btf *btf_parse(bpfptr_t btf_data, u32 btf_data_size,
45454587 u32 log_level, char __user *log_ubuf, u32 log_size)
45464588 {
@@ -4608,6 +4650,10 @@ static struct btf *btf_parse(bpfptr_t btf_data, u32 btf_data_size, · 61 unmodified lines
46084650 if (err)
46094651 goto errout;
46104652
4653+ err = btf_check_type_tags(env, btf, 1);
4654+ if (err)
4655+ goto errout;
4656+
46114657 if (log->level && bpf_verifier_log_full(log)) {
46124658 err = -ENOSPC;
46134659 goto errout;
@@ -4809,6 +4855,10 @@ struct btf *btf_parse_vmlinux(void) · 195 unmodified lines
48094855 if (err)
48104856 goto errout;
48114857
4858+ err = btf_check_type_tags(env, btf, 1);
4859+ if (err)
4860+ goto errout;
4861+
48124862 /* btf_parse_vmlinux() runs under bpf_verifier_lock */
48134863 bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
48144864
@@ -4894,6 +4944,10 @@ static struct btf *btf_parse_module(const char *module_name, const void *data, u · 79 unmodified lines
48944944 if (err)
48954945 goto errout;
48964946
4947+ err = btf_check_type_tags(env, btf, btf_nr_types(base_btf));
4948+ if (err)
4949+ goto errout;
4950+
48974951 btf_verifier_env_free(env);
48984952 refcount_set(&btf->refcnt, 1);
48994953 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