aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2018-12-07 19:42:25 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-12-09 16:54:38 -0500
commitc454a46b5efd8eff8880e88ece2976e60a26bf35 (patch)
treefa0791a8524e5a13b2798ba6fee34d517df3dfa4 /kernel/bpf/syscall.c
parent6baefa1aa46f0e90aefbd13b8c926e89068fabba (diff)
bpf: Add bpf_line_info support
This patch adds bpf_line_info support. It accepts an array of bpf_line_info objects during BPF_PROG_LOAD. The "line_info", "line_info_cnt" and "line_info_rec_size" are added to the "union bpf_attr". The "line_info_rec_size" makes bpf_line_info extensible in the future. The new "check_btf_line()" ensures the userspace line_info is valid for the kernel to use. When the verifier is translating/patching the bpf_prog (through "bpf_patch_insn_single()"), the line_infos' insn_off is also adjusted by the newly added "bpf_adj_linfo()". If the bpf_prog is jited, this patch also provides the jited addrs (in aux->jited_linfo) for the corresponding line_info.insn_off. "bpf_prog_fill_jited_linfo()" is added to fill the aux->jited_linfo. It is currently called by the x86 jit. Other jits can also use "bpf_prog_fill_jited_linfo()" and it will be done in the followup patches. In the future, if it deemed necessary, a particular jit could also provide its own "bpf_prog_fill_jited_linfo()" implementation. A few "*line_info*" fields are added to the bpf_prog_info such that the user can get the xlated line_info back (i.e. the line_info with its insn_off reflecting the translated prog). The jited_line_info is available if the prog is jited. It is an array of __u64. If the prog is not jited, jited_line_info_cnt is 0. The verifier's verbose log with line_info will be done in a follow up patch. Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r--kernel/bpf/syscall.c83
1 files changed, 77 insertions, 6 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index aa05aa38f4a8..19c88cff7880 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1215,6 +1215,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
1215 bpf_prog_kallsyms_del_all(prog); 1215 bpf_prog_kallsyms_del_all(prog);
1216 btf_put(prog->aux->btf); 1216 btf_put(prog->aux->btf);
1217 kvfree(prog->aux->func_info); 1217 kvfree(prog->aux->func_info);
1218 bpf_prog_free_linfo(prog);
1218 1219
1219 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 1220 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
1220 } 1221 }
@@ -1439,7 +1440,7 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type,
1439} 1440}
1440 1441
1441/* last field in 'union bpf_attr' used by this command */ 1442/* last field in 'union bpf_attr' used by this command */
1442#define BPF_PROG_LOAD_LAST_FIELD func_info_cnt 1443#define BPF_PROG_LOAD_LAST_FIELD line_info_cnt
1443 1444
1444static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) 1445static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
1445{ 1446{
@@ -1560,6 +1561,7 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
1560 return err; 1561 return err;
1561 1562
1562free_used_maps: 1563free_used_maps:
1564 bpf_prog_free_linfo(prog);
1563 kvfree(prog->aux->func_info); 1565 kvfree(prog->aux->func_info);
1564 btf_put(prog->aux->btf); 1566 btf_put(prog->aux->btf);
1565 bpf_prog_kallsyms_del_subprogs(prog); 1567 bpf_prog_kallsyms_del_subprogs(prog);
@@ -2041,6 +2043,37 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
2041 return insns; 2043 return insns;
2042} 2044}
2043 2045
2046static int set_info_rec_size(struct bpf_prog_info *info)
2047{
2048 /*
2049 * Ensure info.*_rec_size is the same as kernel expected size
2050 *
2051 * or
2052 *
2053 * Only allow zero *_rec_size if both _rec_size and _cnt are
2054 * zero. In this case, the kernel will set the expected
2055 * _rec_size back to the info.
2056 */
2057
2058 if ((info->func_info_cnt || info->func_info_rec_size) &&
2059 info->func_info_rec_size != sizeof(struct bpf_func_info))
2060 return -EINVAL;
2061
2062 if ((info->line_info_cnt || info->line_info_rec_size) &&
2063 info->line_info_rec_size != sizeof(struct bpf_line_info))
2064 return -EINVAL;
2065
2066 if ((info->jited_line_info_cnt || info->jited_line_info_rec_size) &&
2067 info->jited_line_info_rec_size != sizeof(__u64))
2068 return -EINVAL;
2069
2070 info->func_info_rec_size = sizeof(struct bpf_func_info);
2071 info->line_info_rec_size = sizeof(struct bpf_line_info);
2072 info->jited_line_info_rec_size = sizeof(__u64);
2073
2074 return 0;
2075}
2076
2044static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 2077static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
2045 const union bpf_attr *attr, 2078 const union bpf_attr *attr,
2046 union bpf_attr __user *uattr) 2079 union bpf_attr __user *uattr)
@@ -2083,11 +2116,9 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
2083 return -EFAULT; 2116 return -EFAULT;
2084 } 2117 }
2085 2118
2086 if ((info.func_info_cnt || info.func_info_rec_size) && 2119 err = set_info_rec_size(&info);
2087 info.func_info_rec_size != sizeof(struct bpf_func_info)) 2120 if (err)
2088 return -EINVAL; 2121 return err;
2089
2090 info.func_info_rec_size = sizeof(struct bpf_func_info);
2091 2122
2092 if (!capable(CAP_SYS_ADMIN)) { 2123 if (!capable(CAP_SYS_ADMIN)) {
2093 info.jited_prog_len = 0; 2124 info.jited_prog_len = 0;
@@ -2095,6 +2126,8 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
2095 info.nr_jited_ksyms = 0; 2126 info.nr_jited_ksyms = 0;
2096 info.nr_jited_func_lens = 0; 2127 info.nr_jited_func_lens = 0;
2097 info.func_info_cnt = 0; 2128 info.func_info_cnt = 0;
2129 info.line_info_cnt = 0;
2130 info.jited_line_info_cnt = 0;
2098 goto done; 2131 goto done;
2099 } 2132 }
2100 2133
@@ -2251,6 +2284,44 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
2251 } 2284 }
2252 } 2285 }
2253 2286
2287 ulen = info.line_info_cnt;
2288 info.line_info_cnt = prog->aux->nr_linfo;
2289 if (info.line_info_cnt && ulen) {
2290 if (bpf_dump_raw_ok()) {
2291 __u8 __user *user_linfo;
2292
2293 user_linfo = u64_to_user_ptr(info.line_info);
2294 ulen = min_t(u32, info.line_info_cnt, ulen);
2295 if (copy_to_user(user_linfo, prog->aux->linfo,
2296 info.line_info_rec_size * ulen))
2297 return -EFAULT;
2298 } else {
2299 info.line_info = 0;
2300 }
2301 }
2302
2303 ulen = info.jited_line_info_cnt;
2304 if (prog->aux->jited_linfo)
2305 info.jited_line_info_cnt = prog->aux->nr_linfo;
2306 else
2307 info.jited_line_info_cnt = 0;
2308 if (info.jited_line_info_cnt && ulen) {
2309 if (bpf_dump_raw_ok()) {
2310 __u64 __user *user_linfo;
2311 u32 i;
2312
2313 user_linfo = u64_to_user_ptr(info.jited_line_info);
2314 ulen = min_t(u32, info.jited_line_info_cnt, ulen);
2315 for (i = 0; i < ulen; i++) {
2316 if (put_user((__u64)(long)prog->aux->jited_linfo[i],
2317 &user_linfo[i]))
2318 return -EFAULT;
2319 }
2320 } else {
2321 info.jited_line_info = 0;
2322 }
2323 }
2324
2254done: 2325done:
2255 if (copy_to_user(uinfo, &info, info_len) || 2326 if (copy_to_user(uinfo, &info, info_len) ||
2256 put_user(info_len, &uattr->info.info_len)) 2327 put_user(info_len, &uattr->info.info_len))