|
22 | 22 | #include <linux/skmsg.h> |
23 | 23 | #include <linux/perf_event.h> |
24 | 24 | #include <linux/bsearch.h> |
| 25 | +#include <linux/kobject.h> |
| 26 | +#include <linux/sysfs.h> |
25 | 27 | #include <net/sock.h> |
26 | 28 |
|
27 | 29 | /* BTF (BPF Type Format) is the meta data format which describes |
@@ -4476,6 +4478,75 @@ struct btf *btf_parse_vmlinux(void) |
4476 | 4478 | return ERR_PTR(err); |
4477 | 4479 | } |
4478 | 4480 |
|
| 4481 | +static struct btf *btf_parse_module(const char *module_name, const void *data, unsigned int data_size) |
| 4482 | +{ |
| 4483 | + struct btf_verifier_env *env = NULL; |
| 4484 | + struct bpf_verifier_log *log; |
| 4485 | + struct btf *btf = NULL, *base_btf; |
| 4486 | + int err; |
| 4487 | + |
| 4488 | + base_btf = bpf_get_btf_vmlinux(); |
| 4489 | + if (IS_ERR(base_btf)) |
| 4490 | + return base_btf; |
| 4491 | + if (!base_btf) |
| 4492 | + return ERR_PTR(-EINVAL); |
| 4493 | + |
| 4494 | + env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); |
| 4495 | + if (!env) |
| 4496 | + return ERR_PTR(-ENOMEM); |
| 4497 | + |
| 4498 | + log = &env->log; |
| 4499 | + log->level = BPF_LOG_KERNEL; |
| 4500 | + |
| 4501 | + btf = kzalloc(sizeof(*btf), GFP_KERNEL | __GFP_NOWARN); |
| 4502 | + if (!btf) { |
| 4503 | + err = -ENOMEM; |
| 4504 | + goto errout; |
| 4505 | + } |
| 4506 | + env->btf = btf; |
| 4507 | + |
| 4508 | + btf->base_btf = base_btf; |
| 4509 | + btf->start_id = base_btf->nr_types; |
| 4510 | + btf->start_str_off = base_btf->hdr.str_len; |
| 4511 | + btf->kernel_btf = true; |
| 4512 | + snprintf(btf->name, sizeof(btf->name), "%s", module_name); |
| 4513 | + |
| 4514 | + btf->data = kvmalloc(data_size, GFP_KERNEL | __GFP_NOWARN); |
| 4515 | + if (!btf->data) { |
| 4516 | + err = -ENOMEM; |
| 4517 | + goto errout; |
| 4518 | + } |
| 4519 | + memcpy(btf->data, data, data_size); |
| 4520 | + btf->data_size = data_size; |
| 4521 | + |
| 4522 | + err = btf_parse_hdr(env); |
| 4523 | + if (err) |
| 4524 | + goto errout; |
| 4525 | + |
| 4526 | + btf->nohdr_data = btf->data + btf->hdr.hdr_len; |
| 4527 | + |
| 4528 | + err = btf_parse_str_sec(env); |
| 4529 | + if (err) |
| 4530 | + goto errout; |
| 4531 | + |
| 4532 | + err = btf_check_all_metas(env); |
| 4533 | + if (err) |
| 4534 | + goto errout; |
| 4535 | + |
| 4536 | + btf_verifier_env_free(env); |
| 4537 | + refcount_set(&btf->refcnt, 1); |
| 4538 | + return btf; |
| 4539 | + |
| 4540 | +errout: |
| 4541 | + btf_verifier_env_free(env); |
| 4542 | + if (btf) { |
| 4543 | + kvfree(btf->data); |
| 4544 | + kvfree(btf->types); |
| 4545 | + kfree(btf); |
| 4546 | + } |
| 4547 | + return ERR_PTR(err); |
| 4548 | +} |
| 4549 | + |
4479 | 4550 | struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog) |
4480 | 4551 | { |
4481 | 4552 | struct bpf_prog *tgt_prog = prog->aux->dst_prog; |
@@ -5651,3 +5722,126 @@ bool btf_id_set_contains(const struct btf_id_set *set, u32 id) |
5651 | 5722 | { |
5652 | 5723 | return bsearch(&id, set->ids, set->cnt, sizeof(u32), btf_id_cmp_func) != NULL; |
5653 | 5724 | } |
| 5725 | + |
| 5726 | +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES |
| 5727 | +struct btf_module { |
| 5728 | + struct list_head list; |
| 5729 | + struct module *module; |
| 5730 | + struct btf *btf; |
| 5731 | + struct bin_attribute *sysfs_attr; |
| 5732 | +}; |
| 5733 | + |
| 5734 | +static LIST_HEAD(btf_modules); |
| 5735 | +static DEFINE_MUTEX(btf_module_mutex); |
| 5736 | + |
| 5737 | +static ssize_t |
| 5738 | +btf_module_read(struct file *file, struct kobject *kobj, |
| 5739 | + struct bin_attribute *bin_attr, |
| 5740 | + char *buf, loff_t off, size_t len) |
| 5741 | +{ |
| 5742 | + const struct btf *btf = bin_attr->private; |
| 5743 | + |
| 5744 | + memcpy(buf, btf->data + off, len); |
| 5745 | + return len; |
| 5746 | +} |
| 5747 | + |
| 5748 | +static int btf_module_notify(struct notifier_block *nb, unsigned long op, |
| 5749 | + void *module) |
| 5750 | +{ |
| 5751 | + struct btf_module *btf_mod, *tmp; |
| 5752 | + struct module *mod = module; |
| 5753 | + struct btf *btf; |
| 5754 | + int err = 0; |
| 5755 | + |
| 5756 | + if (mod->btf_data_size == 0 || |
| 5757 | + (op != MODULE_STATE_COMING && op != MODULE_STATE_GOING)) |
| 5758 | + goto out; |
| 5759 | + |
| 5760 | + switch (op) { |
| 5761 | + case MODULE_STATE_COMING: |
| 5762 | + btf_mod = kzalloc(sizeof(*btf_mod), GFP_KERNEL); |
| 5763 | + if (!btf_mod) { |
| 5764 | + err = -ENOMEM; |
| 5765 | + goto out; |
| 5766 | + } |
| 5767 | + btf = btf_parse_module(mod->name, mod->btf_data, mod->btf_data_size); |
| 5768 | + if (IS_ERR(btf)) { |
| 5769 | + pr_warn("failed to validate module [%s] BTF: %ld\n", |
| 5770 | + mod->name, PTR_ERR(btf)); |
| 5771 | + kfree(btf_mod); |
| 5772 | + err = PTR_ERR(btf); |
| 5773 | + goto out; |
| 5774 | + } |
| 5775 | + err = btf_alloc_id(btf); |
| 5776 | + if (err) { |
| 5777 | + btf_free(btf); |
| 5778 | + kfree(btf_mod); |
| 5779 | + goto out; |
| 5780 | + } |
| 5781 | + |
| 5782 | + mutex_lock(&btf_module_mutex); |
| 5783 | + btf_mod->module = module; |
| 5784 | + btf_mod->btf = btf; |
| 5785 | + list_add(&btf_mod->list, &btf_modules); |
| 5786 | + mutex_unlock(&btf_module_mutex); |
| 5787 | + |
| 5788 | + if (IS_ENABLED(CONFIG_SYSFS)) { |
| 5789 | + struct bin_attribute *attr; |
| 5790 | + |
| 5791 | + attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
| 5792 | + if (!attr) |
| 5793 | + goto out; |
| 5794 | + |
| 5795 | + sysfs_bin_attr_init(attr); |
| 5796 | + attr->attr.name = btf->name; |
| 5797 | + attr->attr.mode = 0444; |
| 5798 | + attr->size = btf->data_size; |
| 5799 | + attr->private = btf; |
| 5800 | + attr->read = btf_module_read; |
| 5801 | + |
| 5802 | + err = sysfs_create_bin_file(btf_kobj, attr); |
| 5803 | + if (err) { |
| 5804 | + pr_warn("failed to register module [%s] BTF in sysfs: %d\n", |
| 5805 | + mod->name, err); |
| 5806 | + kfree(attr); |
| 5807 | + err = 0; |
| 5808 | + goto out; |
| 5809 | + } |
| 5810 | + |
| 5811 | + btf_mod->sysfs_attr = attr; |
| 5812 | + } |
| 5813 | + |
| 5814 | + break; |
| 5815 | + case MODULE_STATE_GOING: |
| 5816 | + mutex_lock(&btf_module_mutex); |
| 5817 | + list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) { |
| 5818 | + if (btf_mod->module != module) |
| 5819 | + continue; |
| 5820 | + |
| 5821 | + list_del(&btf_mod->list); |
| 5822 | + if (btf_mod->sysfs_attr) |
| 5823 | + sysfs_remove_bin_file(btf_kobj, btf_mod->sysfs_attr); |
| 5824 | + btf_put(btf_mod->btf); |
| 5825 | + kfree(btf_mod->sysfs_attr); |
| 5826 | + kfree(btf_mod); |
| 5827 | + break; |
| 5828 | + } |
| 5829 | + mutex_unlock(&btf_module_mutex); |
| 5830 | + break; |
| 5831 | + } |
| 5832 | +out: |
| 5833 | + return notifier_from_errno(err); |
| 5834 | +} |
| 5835 | + |
| 5836 | +static struct notifier_block btf_module_nb = { |
| 5837 | + .notifier_call = btf_module_notify, |
| 5838 | +}; |
| 5839 | + |
| 5840 | +static int __init btf_module_init(void) |
| 5841 | +{ |
| 5842 | + register_module_notifier(&btf_module_nb); |
| 5843 | + return 0; |
| 5844 | +} |
| 5845 | + |
| 5846 | +fs_initcall(btf_module_init); |
| 5847 | +#endif /* CONFIG_DEBUG_INFO_BTF_MODULES */ |
0 commit comments