diff options
author | Martin KaFai Lau <kafai@fb.com> | 2018-12-07 19:42:25 -0500 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-12-09 16:54:38 -0500 |
commit | c454a46b5efd8eff8880e88ece2976e60a26bf35 (patch) | |
tree | fa0791a8524e5a13b2798ba6fee34d517df3dfa4 /kernel/bpf/syscall.c | |
parent | 6baefa1aa46f0e90aefbd13b8c926e89068fabba (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.c | 83 |
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 | ||
1444 | static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) | 1445 | static 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 | ||
1562 | free_used_maps: | 1563 | free_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 | ||
2046 | static 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 | |||
2044 | static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, | 2077 | static 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 | |||
2254 | done: | 2325 | done: |
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)) |