aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r--kernel/bpf/syscall.c131
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
2183static 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
2232static 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;
2303put_file:
2304 fput(file);
2305out:
2306 return err;
2307}
2308
2181SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 2309SYSCALL_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;