aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-05-24 14:21:09 -0400
committerAlexei Starovoitov <ast@kernel.org>2018-05-24 21:18:19 -0400
commit41bdc4b40ed6fb26c6acc655ed9a243a348709c9 (patch)
tree84be65f3afa34f4313729d0c7fc7141ca51a0243 /kernel/bpf/syscall.c
parentf8d959a5b188dc81e57a6bac34a1b2986f61e2fd (diff)
bpf: introduce bpf subcommand BPF_TASK_FD_QUERY
Currently, suppose a userspace application has loaded a bpf program and attached it to a tracepoint/kprobe/uprobe, and a bpf introspection tool, e.g., bpftool, wants to show which bpf program is attached to which tracepoint/kprobe/uprobe. Such attachment information will be really useful to understand the overall bpf deployment in the system. There is a name field (16 bytes) for each program, which could be used to encode the attachment point. There are some drawbacks for this approaches. First, bpftool user (e.g., an admin) may not really understand the association between the name and the attachment point. Second, if one program is attached to multiple places, encoding a proper name which can imply all these attachments becomes difficult. This patch introduces a new bpf subcommand BPF_TASK_FD_QUERY. Given a pid and fd, if the <pid, fd> is associated with a tracepoint/kprobe/uprobe perf event, BPF_TASK_FD_QUERY will return . prog_id . tracepoint name, or . k[ret]probe funcname + offset or kernel addr, or . u[ret]probe filename + offset to the userspace. The user can use "bpftool prog" to find more information about bpf program itself with prog_id. Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-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.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;