aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-11-19 18:29:11 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-11-20 13:54:39 -0500
commit838e96904ff3fc6c30e5ebbc611474669856e3c0 (patch)
tree6c29177207be1dea47bc54f4ac9e31a5e71d9bd3 /kernel
parent78a2540e8945678b390a5f41eb82459bc6f0f36c (diff)
bpf: Introduce bpf_func_info
This patch added interface to load a program with the following additional information: . prog_btf_fd . func_info, func_info_rec_size and func_info_cnt where func_info will provide function range and type_id corresponding to each function. The func_info_rec_size is introduced in the UAPI to specify struct bpf_func_info size passed from user space. This intends to make bpf_func_info structure growable in the future. If the kernel gets a different bpf_func_info size from userspace, it will try to handle user request with part of bpf_func_info it can understand. In this patch, kernel can understand struct bpf_func_info { __u32 insn_offset; __u32 type_id; }; If user passed a bpf func_info record size of 16 bytes, the kernel can still handle part of records with the above definition. If verifier agrees with function range provided by the user, the bpf_prog ksym for each function will use the func name provided in the type_id, which is supposed to provide better encoding as it is not limited by 16 bytes program name limitation and this is better for bpf program which contains multiple subprograms. The bpf_prog_info interface is also extended to return btf_id, func_info, func_info_rec_size and func_info_cnt to userspace, so userspace can print out the function prototype for each xlated function. The insn_offset in the returned func_info corresponds to the insn offset for xlated functions. With other jit related fields in bpf_prog_info, userspace can also print out function prototypes for each jited function. Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/btf.c4
-rw-r--r--kernel/bpf/core.c13
-rw-r--r--kernel/bpf/syscall.c59
-rw-r--r--kernel/bpf/verifier.c120
4 files changed, 189 insertions, 7 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 6a2be79b73fc..69da9169819a 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -474,7 +474,7 @@ static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
474 return !*src; 474 return !*src;
475} 475}
476 476
477static const char *btf_name_by_offset(const struct btf *btf, u32 offset) 477const char *btf_name_by_offset(const struct btf *btf, u32 offset)
478{ 478{
479 if (!offset) 479 if (!offset)
480 return "(anon)"; 480 return "(anon)";
@@ -484,7 +484,7 @@ static const char *btf_name_by_offset(const struct btf *btf, u32 offset)
484 return "(invalid-name-offset)"; 484 return "(invalid-name-offset)";
485} 485}
486 486
487static const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) 487const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
488{ 488{
489 if (type_id > btf->nr_types) 489 if (type_id > btf->nr_types)
490 return NULL; 490 return NULL;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 1a796e0799ec..16d77012ad3e 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -21,12 +21,14 @@
21 * Kris Katterjohn - Added many additional checks in bpf_check_classic() 21 * Kris Katterjohn - Added many additional checks in bpf_check_classic()
22 */ 22 */
23 23
24#include <uapi/linux/btf.h>
24#include <linux/filter.h> 25#include <linux/filter.h>
25#include <linux/skbuff.h> 26#include <linux/skbuff.h>
26#include <linux/vmalloc.h> 27#include <linux/vmalloc.h>
27#include <linux/random.h> 28#include <linux/random.h>
28#include <linux/moduleloader.h> 29#include <linux/moduleloader.h>
29#include <linux/bpf.h> 30#include <linux/bpf.h>
31#include <linux/btf.h>
30#include <linux/frame.h> 32#include <linux/frame.h>
31#include <linux/rbtree_latch.h> 33#include <linux/rbtree_latch.h>
32#include <linux/kallsyms.h> 34#include <linux/kallsyms.h>
@@ -390,6 +392,8 @@ bpf_get_prog_addr_region(const struct bpf_prog *prog,
390static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) 392static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym)
391{ 393{
392 const char *end = sym + KSYM_NAME_LEN; 394 const char *end = sym + KSYM_NAME_LEN;
395 const struct btf_type *type;
396 const char *func_name;
393 397
394 BUILD_BUG_ON(sizeof("bpf_prog_") + 398 BUILD_BUG_ON(sizeof("bpf_prog_") +
395 sizeof(prog->tag) * 2 + 399 sizeof(prog->tag) * 2 +
@@ -404,6 +408,15 @@ static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym)
404 408
405 sym += snprintf(sym, KSYM_NAME_LEN, "bpf_prog_"); 409 sym += snprintf(sym, KSYM_NAME_LEN, "bpf_prog_");
406 sym = bin2hex(sym, prog->tag, sizeof(prog->tag)); 410 sym = bin2hex(sym, prog->tag, sizeof(prog->tag));
411
412 /* prog->aux->name will be ignored if full btf name is available */
413 if (prog->aux->btf) {
414 type = btf_type_by_id(prog->aux->btf, prog->aux->type_id);
415 func_name = btf_name_by_offset(prog->aux->btf, type->name_off);
416 snprintf(sym, (size_t)(end - sym), "_%s", func_name);
417 return;
418 }
419
407 if (prog->aux->name[0]) 420 if (prog->aux->name[0])
408 snprintf(sym, (size_t)(end - sym), "_%s", prog->aux->name); 421 snprintf(sym, (size_t)(end - sym), "_%s", prog->aux->name);
409 else 422 else
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index cf5040fd5434..998377808102 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1213,6 +1213,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
1213 /* bpf_prog_free_id() must be called first */ 1213 /* bpf_prog_free_id() must be called first */
1214 bpf_prog_free_id(prog, do_idr_lock); 1214 bpf_prog_free_id(prog, do_idr_lock);
1215 bpf_prog_kallsyms_del_all(prog); 1215 bpf_prog_kallsyms_del_all(prog);
1216 btf_put(prog->aux->btf);
1216 1217
1217 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 1218 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
1218 } 1219 }
@@ -1437,9 +1438,9 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type,
1437} 1438}
1438 1439
1439/* last field in 'union bpf_attr' used by this command */ 1440/* last field in 'union bpf_attr' used by this command */
1440#define BPF_PROG_LOAD_LAST_FIELD expected_attach_type 1441#define BPF_PROG_LOAD_LAST_FIELD func_info_cnt
1441 1442
1442static int bpf_prog_load(union bpf_attr *attr) 1443static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
1443{ 1444{
1444 enum bpf_prog_type type = attr->prog_type; 1445 enum bpf_prog_type type = attr->prog_type;
1445 struct bpf_prog *prog; 1446 struct bpf_prog *prog;
@@ -1525,7 +1526,7 @@ static int bpf_prog_load(union bpf_attr *attr)
1525 goto free_prog; 1526 goto free_prog;
1526 1527
1527 /* run eBPF verifier */ 1528 /* run eBPF verifier */
1528 err = bpf_check(&prog, attr); 1529 err = bpf_check(&prog, attr, uattr);
1529 if (err < 0) 1530 if (err < 0)
1530 goto free_used_maps; 1531 goto free_used_maps;
1531 1532
@@ -2079,6 +2080,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
2079 info.xlated_prog_len = 0; 2080 info.xlated_prog_len = 0;
2080 info.nr_jited_ksyms = 0; 2081 info.nr_jited_ksyms = 0;
2081 info.nr_jited_func_lens = 0; 2082 info.nr_jited_func_lens = 0;
2083 info.func_info_cnt = 0;
2082 goto done; 2084 goto done;
2083 } 2085 }
2084 2086
@@ -2216,6 +2218,55 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
2216 } 2218 }
2217 } 2219 }
2218 2220
2221 if (prog->aux->btf) {
2222 u32 ucnt, urec_size;
2223
2224 info.btf_id = btf_id(prog->aux->btf);
2225
2226 ucnt = info.func_info_cnt;
2227 info.func_info_cnt = prog->aux->func_cnt ? : 1;
2228 urec_size = info.func_info_rec_size;
2229 info.func_info_rec_size = sizeof(struct bpf_func_info);
2230 if (ucnt) {
2231 /* expect passed-in urec_size is what the kernel expects */
2232 if (urec_size != info.func_info_rec_size)
2233 return -EINVAL;
2234
2235 if (bpf_dump_raw_ok()) {
2236 struct bpf_func_info kern_finfo;
2237 char __user *user_finfo;
2238 u32 i, insn_offset;
2239
2240 user_finfo = u64_to_user_ptr(info.func_info);
2241 if (prog->aux->func_cnt) {
2242 ucnt = min_t(u32, info.func_info_cnt, ucnt);
2243 insn_offset = 0;
2244 for (i = 0; i < ucnt; i++) {
2245 kern_finfo.insn_offset = insn_offset;
2246 kern_finfo.type_id = prog->aux->func[i]->aux->type_id;
2247 if (copy_to_user(user_finfo, &kern_finfo,
2248 sizeof(kern_finfo)))
2249 return -EFAULT;
2250
2251 /* func[i]->len holds the prog len */
2252 insn_offset += prog->aux->func[i]->len;
2253 user_finfo += urec_size;
2254 }
2255 } else {
2256 kern_finfo.insn_offset = 0;
2257 kern_finfo.type_id = prog->aux->type_id;
2258 if (copy_to_user(user_finfo, &kern_finfo,
2259 sizeof(kern_finfo)))
2260 return -EFAULT;
2261 }
2262 } else {
2263 info.func_info_cnt = 0;
2264 }
2265 }
2266 } else {
2267 info.func_info_cnt = 0;
2268 }
2269
2219done: 2270done:
2220 if (copy_to_user(uinfo, &info, info_len) || 2271 if (copy_to_user(uinfo, &info, info_len) ||
2221 put_user(info_len, &uattr->info.info_len)) 2272 put_user(info_len, &uattr->info.info_len))
@@ -2501,7 +2552,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
2501 err = map_get_next_key(&attr); 2552 err = map_get_next_key(&attr);
2502 break; 2553 break;
2503 case BPF_PROG_LOAD: 2554 case BPF_PROG_LOAD:
2504 err = bpf_prog_load(&attr); 2555 err = bpf_prog_load(&attr, uattr);
2505 break; 2556 break;
2506 case BPF_OBJ_PIN: 2557 case BPF_OBJ_PIN:
2507 err = bpf_obj_pin(&attr); 2558 err = bpf_obj_pin(&attr);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b5222aa61d54..f102c4fd0c5a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11,10 +11,12 @@
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details. 12 * General Public License for more details.
13 */ 13 */
14#include <uapi/linux/btf.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/types.h> 16#include <linux/types.h>
16#include <linux/slab.h> 17#include <linux/slab.h>
17#include <linux/bpf.h> 18#include <linux/bpf.h>
19#include <linux/btf.h>
18#include <linux/bpf_verifier.h> 20#include <linux/bpf_verifier.h>
19#include <linux/filter.h> 21#include <linux/filter.h>
20#include <net/netlink.h> 22#include <net/netlink.h>
@@ -4639,6 +4641,114 @@ err_free:
4639 return ret; 4641 return ret;
4640} 4642}
4641 4643
4644/* The minimum supported BTF func info size */
4645#define MIN_BPF_FUNCINFO_SIZE 8
4646#define MAX_FUNCINFO_REC_SIZE 252
4647
4648static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env,
4649 union bpf_attr *attr, union bpf_attr __user *uattr)
4650{
4651 u32 i, nfuncs, urec_size, min_size, prev_offset;
4652 u32 krec_size = sizeof(struct bpf_func_info);
4653 struct bpf_func_info krecord = {};
4654 const struct btf_type *type;
4655 void __user *urecord;
4656 struct btf *btf;
4657 int ret = 0;
4658
4659 nfuncs = attr->func_info_cnt;
4660 if (!nfuncs)
4661 return 0;
4662
4663 if (nfuncs != env->subprog_cnt) {
4664 verbose(env, "number of funcs in func_info doesn't match number of subprogs\n");
4665 return -EINVAL;
4666 }
4667
4668 urec_size = attr->func_info_rec_size;
4669 if (urec_size < MIN_BPF_FUNCINFO_SIZE ||
4670 urec_size > MAX_FUNCINFO_REC_SIZE ||
4671 urec_size % sizeof(u32)) {
4672 verbose(env, "invalid func info rec size %u\n", urec_size);
4673 return -EINVAL;
4674 }
4675
4676 btf = btf_get_by_fd(attr->prog_btf_fd);
4677 if (IS_ERR(btf)) {
4678 verbose(env, "unable to get btf from fd\n");
4679 return PTR_ERR(btf);
4680 }
4681
4682 urecord = u64_to_user_ptr(attr->func_info);
4683 min_size = min_t(u32, krec_size, urec_size);
4684
4685 for (i = 0; i < nfuncs; i++) {
4686 ret = bpf_check_uarg_tail_zero(urecord, krec_size, urec_size);
4687 if (ret) {
4688 if (ret == -E2BIG) {
4689 verbose(env, "nonzero tailing record in func info");
4690 /* set the size kernel expects so loader can zero
4691 * out the rest of the record.
4692 */
4693 if (put_user(min_size, &uattr->func_info_rec_size))
4694 ret = -EFAULT;
4695 }
4696 goto free_btf;
4697 }
4698
4699 if (copy_from_user(&krecord, urecord, min_size)) {
4700 ret = -EFAULT;
4701 goto free_btf;
4702 }
4703
4704 /* check insn_offset */
4705 if (i == 0) {
4706 if (krecord.insn_offset) {
4707 verbose(env,
4708 "nonzero insn_offset %u for the first func info record",
4709 krecord.insn_offset);
4710 ret = -EINVAL;
4711 goto free_btf;
4712 }
4713 } else if (krecord.insn_offset <= prev_offset) {
4714 verbose(env,
4715 "same or smaller insn offset (%u) than previous func info record (%u)",
4716 krecord.insn_offset, prev_offset);
4717 ret = -EINVAL;
4718 goto free_btf;
4719 }
4720
4721 if (env->subprog_info[i].start != krecord.insn_offset) {
4722 verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n");
4723 ret = -EINVAL;
4724 goto free_btf;
4725 }
4726
4727 /* check type_id */
4728 type = btf_type_by_id(btf, krecord.type_id);
4729 if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) {
4730 verbose(env, "invalid type id %d in func info",
4731 krecord.type_id);
4732 ret = -EINVAL;
4733 goto free_btf;
4734 }
4735
4736 if (i == 0)
4737 prog->aux->type_id = krecord.type_id;
4738 env->subprog_info[i].type_id = krecord.type_id;
4739
4740 prev_offset = krecord.insn_offset;
4741 urecord += urec_size;
4742 }
4743
4744 prog->aux->btf = btf;
4745 return 0;
4746
4747free_btf:
4748 btf_put(btf);
4749 return ret;
4750}
4751
4642/* check %cur's range satisfies %old's */ 4752/* check %cur's range satisfies %old's */
4643static bool range_within(struct bpf_reg_state *old, 4753static bool range_within(struct bpf_reg_state *old,
4644 struct bpf_reg_state *cur) 4754 struct bpf_reg_state *cur)
@@ -5939,6 +6049,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
5939 func[i]->aux->name[0] = 'F'; 6049 func[i]->aux->name[0] = 'F';
5940 func[i]->aux->stack_depth = env->subprog_info[i].stack_depth; 6050 func[i]->aux->stack_depth = env->subprog_info[i].stack_depth;
5941 func[i]->jit_requested = 1; 6051 func[i]->jit_requested = 1;
6052 /* the btf will be freed only at prog->aux */
6053 func[i]->aux->btf = prog->aux->btf;
6054 func[i]->aux->type_id = env->subprog_info[i].type_id;
5942 func[i] = bpf_int_jit_compile(func[i]); 6055 func[i] = bpf_int_jit_compile(func[i]);
5943 if (!func[i]->jited) { 6056 if (!func[i]->jited) {
5944 err = -ENOTSUPP; 6057 err = -ENOTSUPP;
@@ -6325,7 +6438,8 @@ static void free_states(struct bpf_verifier_env *env)
6325 kfree(env->explored_states); 6438 kfree(env->explored_states);
6326} 6439}
6327 6440
6328int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) 6441int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
6442 union bpf_attr __user *uattr)
6329{ 6443{
6330 struct bpf_verifier_env *env; 6444 struct bpf_verifier_env *env;
6331 struct bpf_verifier_log *log; 6445 struct bpf_verifier_log *log;
@@ -6397,6 +6511,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
6397 if (ret < 0) 6511 if (ret < 0)
6398 goto skip_full_check; 6512 goto skip_full_check;
6399 6513
6514 ret = check_btf_func(env->prog, env, attr, uattr);
6515 if (ret < 0)
6516 goto skip_full_check;
6517
6400 ret = do_check(env); 6518 ret = do_check(env);
6401 if (env->cur_state) { 6519 if (env->cur_state) {
6402 free_verifier_state(env->cur_state, true); 6520 free_verifier_state(env->cur_state, true);