diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 788456c18617..388d4feda348 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -18,7 +18,9 @@ | |||
18 | #include <linux/vmalloc.h> | 18 | #include <linux/vmalloc.h> |
19 | #include <linux/mmzone.h> | 19 | #include <linux/mmzone.h> |
20 | #include <linux/anon_inodes.h> | 20 | #include <linux/anon_inodes.h> |
21 | #include <linux/fdtable.h> | ||
21 | #include <linux/file.h> | 22 | #include <linux/file.h> |
23 | #include <linux/fs.h> | ||
22 | #include <linux/license.h> | 24 | #include <linux/license.h> |
23 | #include <linux/filter.h> | 25 | #include <linux/filter.h> |
24 | #include <linux/version.h> | 26 | #include <linux/version.h> |
@@ -2178,6 +2180,132 @@ static int bpf_btf_get_fd_by_id(const union bpf_attr *attr) | |||
2178 | return btf_get_fd_by_id(attr->btf_id); | 2180 | return btf_get_fd_by_id(attr->btf_id); |
2179 | } | 2181 | } |
2180 | 2182 | ||
2183 | static int bpf_task_fd_query_copy(const union bpf_attr *attr, | ||
2184 | union bpf_attr __user *uattr, | ||
2185 | u32 prog_id, u32 fd_type, | ||
2186 | const char *buf, u64 probe_offset, | ||
2187 | u64 probe_addr) | ||
2188 | { | ||
2189 | char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf); | ||
2190 | u32 len = buf ? strlen(buf) : 0, input_len; | ||
2191 | int err = 0; | ||
2192 | |||
2193 | if (put_user(len, &uattr->task_fd_query.buf_len)) | ||
2194 | return -EFAULT; | ||
2195 | input_len = attr->task_fd_query.buf_len; | ||
2196 | if (input_len && ubuf) { | ||
2197 | if (!len) { | ||
2198 | /* nothing to copy, just make ubuf NULL terminated */ | ||
2199 | char zero = '\0'; | ||
2200 | |||
2201 | if (put_user(zero, ubuf)) | ||
2202 | return -EFAULT; | ||
2203 | } else if (input_len >= len + 1) { | ||
2204 | /* ubuf can hold the string with NULL terminator */ | ||
2205 | if (copy_to_user(ubuf, buf, len + 1)) | ||
2206 | return -EFAULT; | ||
2207 | } else { | ||
2208 | /* ubuf cannot hold the string with NULL terminator, | ||
2209 | * do a partial copy with NULL terminator. | ||
2210 | */ | ||
2211 | char zero = '\0'; | ||
2212 | |||
2213 | err = -ENOSPC; | ||
2214 | if (copy_to_user(ubuf, buf, input_len - 1)) | ||
2215 | return -EFAULT; | ||
2216 | if (put_user(zero, ubuf + input_len - 1)) | ||
2217 | return -EFAULT; | ||
2218 | } | ||
2219 | } | ||
2220 | |||
2221 | if (put_user(prog_id, &uattr->task_fd_query.prog_id) || | ||
2222 | put_user(fd_type, &uattr->task_fd_query.fd_type) || | ||
2223 | put_user(probe_offset, &uattr->task_fd_query.probe_offset) || | ||
2224 | put_user(probe_addr, &uattr->task_fd_query.probe_addr)) | ||
2225 | return -EFAULT; | ||
2226 | |||
2227 | return err; | ||
2228 | } | ||
2229 | |||
2230 | #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr | ||
2231 | |||
2232 | static int bpf_task_fd_query(const union bpf_attr *attr, | ||
2233 | union bpf_attr __user *uattr) | ||
2234 | { | ||
2235 | pid_t pid = attr->task_fd_query.pid; | ||
2236 | u32 fd = attr->task_fd_query.fd; | ||
2237 | const struct perf_event *event; | ||
2238 | struct files_struct *files; | ||
2239 | struct task_struct *task; | ||
2240 | struct file *file; | ||
2241 | int err; | ||
2242 | |||
2243 | if (CHECK_ATTR(BPF_TASK_FD_QUERY)) | ||
2244 | return -EINVAL; | ||
2245 | |||
2246 | if (!capable(CAP_SYS_ADMIN)) | ||
2247 | return -EPERM; | ||
2248 | |||
2249 | if (attr->task_fd_query.flags != 0) | ||
2250 | return -EINVAL; | ||
2251 | |||
2252 | task = get_pid_task(find_vpid(pid), PIDTYPE_PID); | ||
2253 | if (!task) | ||
2254 | return -ENOENT; | ||
2255 | |||
2256 | files = get_files_struct(task); | ||
2257 | put_task_struct(task); | ||
2258 | if (!files) | ||
2259 | return -ENOENT; | ||
2260 | |||
2261 | err = 0; | ||
2262 | spin_lock(&files->file_lock); | ||
2263 | file = fcheck_files(files, fd); | ||
2264 | if (!file) | ||
2265 | err = -EBADF; | ||
2266 | else | ||
2267 | get_file(file); | ||
2268 | spin_unlock(&files->file_lock); | ||
2269 | put_files_struct(files); | ||
2270 | |||
2271 | if (err) | ||
2272 | goto out; | ||
2273 | |||
2274 | if (file->f_op == &bpf_raw_tp_fops) { | ||
2275 | struct bpf_raw_tracepoint *raw_tp = file->private_data; | ||
2276 | struct bpf_raw_event_map *btp = raw_tp->btp; | ||
2277 | |||
2278 | err = bpf_task_fd_query_copy(attr, uattr, | ||
2279 | raw_tp->prog->aux->id, | ||
2280 | BPF_FD_TYPE_RAW_TRACEPOINT, | ||
2281 | btp->tp->name, 0, 0); | ||
2282 | goto put_file; | ||
2283 | } | ||
2284 | |||
2285 | event = perf_get_event(file); | ||
2286 | if (!IS_ERR(event)) { | ||
2287 | u64 probe_offset, probe_addr; | ||
2288 | u32 prog_id, fd_type; | ||
2289 | const char *buf; | ||
2290 | |||
2291 | err = bpf_get_perf_event_info(event, &prog_id, &fd_type, | ||
2292 | &buf, &probe_offset, | ||
2293 | &probe_addr); | ||
2294 | if (!err) | ||
2295 | err = bpf_task_fd_query_copy(attr, uattr, prog_id, | ||
2296 | fd_type, buf, | ||
2297 | probe_offset, | ||
2298 | probe_addr); | ||
2299 | goto put_file; | ||
2300 | } | ||
2301 | |||
2302 | err = -ENOTSUPP; | ||
2303 | put_file: | ||
2304 | fput(file); | ||
2305 | out: | ||
2306 | return err; | ||
2307 | } | ||
2308 | |||
2181 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) | 2309 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) |
2182 | { | 2310 | { |
2183 | union bpf_attr attr = {}; | 2311 | union bpf_attr attr = {}; |
@@ -2264,6 +2392,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
2264 | case BPF_BTF_GET_FD_BY_ID: | 2392 | case BPF_BTF_GET_FD_BY_ID: |
2265 | err = bpf_btf_get_fd_by_id(&attr); | 2393 | err = bpf_btf_get_fd_by_id(&attr); |
2266 | break; | 2394 | break; |
2395 | case BPF_TASK_FD_QUERY: | ||
2396 | err = bpf_task_fd_query(&attr, uattr); | ||
2397 | break; | ||
2267 | default: | 2398 | default: |
2268 | err = -EINVAL; | 2399 | err = -EINVAL; |
2269 | break; | 2400 | break; |