aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/bpf.h4
-rw-r--r--include/uapi/linux/perf_event.h22
-rw-r--r--kernel/bpf/core.c21
-rw-r--r--kernel/events/core.c3
-rw-r--r--kernel/trace/bpf_trace.c23
5 files changed, 73 insertions, 0 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index e55e4255a210..f812ac508e9f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -254,6 +254,7 @@ typedef unsigned long (*bpf_ctx_copy_t)(void *dst, const void *src,
254 254
255u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, 255u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
256 void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy); 256 void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy);
257int bpf_event_query_prog_array(struct perf_event *event, void __user *info);
257 258
258int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, 259int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
259 union bpf_attr __user *uattr); 260 union bpf_attr __user *uattr);
@@ -285,6 +286,9 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
285 286
286void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, 287void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs,
287 struct bpf_prog *old_prog); 288 struct bpf_prog *old_prog);
289int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
290 __u32 __user *prog_ids, u32 request_cnt,
291 __u32 __user *prog_cnt);
288int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array, 292int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
289 struct bpf_prog *exclude_prog, 293 struct bpf_prog *exclude_prog,
290 struct bpf_prog *include_prog, 294 struct bpf_prog *include_prog,
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index b9a4953018ed..769533696483 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -418,6 +418,27 @@ struct perf_event_attr {
418 __u16 __reserved_2; /* align to __u64 */ 418 __u16 __reserved_2; /* align to __u64 */
419}; 419};
420 420
421/*
422 * Structure used by below PERF_EVENT_IOC_QUERY_BPF command
423 * to query bpf programs attached to the same perf tracepoint
424 * as the given perf event.
425 */
426struct perf_event_query_bpf {
427 /*
428 * The below ids array length
429 */
430 __u32 ids_len;
431 /*
432 * Set by the kernel to indicate the number of
433 * available programs
434 */
435 __u32 prog_cnt;
436 /*
437 * User provided buffer to store program ids
438 */
439 __u32 ids[0];
440};
441
421#define perf_flags(attr) (*(&(attr)->read_format + 1)) 442#define perf_flags(attr) (*(&(attr)->read_format + 1))
422 443
423/* 444/*
@@ -433,6 +454,7 @@ struct perf_event_attr {
433#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) 454#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
434#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) 455#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32)
435#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) 456#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32)
457#define PERF_EVENT_IOC_QUERY_BPF _IOWR('$', 10, struct perf_event_query_bpf *)
436 458
437enum perf_event_ioc_flags { 459enum perf_event_ioc_flags {
438 PERF_IOC_FLAG_GROUP = 1U << 0, 460 PERF_IOC_FLAG_GROUP = 1U << 0,
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 86b50aa26ee8..b16c6f8f42b6 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1462,6 +1462,8 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
1462 rcu_read_lock(); 1462 rcu_read_lock();
1463 prog = rcu_dereference(progs)->progs; 1463 prog = rcu_dereference(progs)->progs;
1464 for (; *prog; prog++) { 1464 for (; *prog; prog++) {
1465 if (*prog == &dummy_bpf_prog.prog)
1466 continue;
1465 id = (*prog)->aux->id; 1467 id = (*prog)->aux->id;
1466 if (copy_to_user(prog_ids + i, &id, sizeof(id))) { 1468 if (copy_to_user(prog_ids + i, &id, sizeof(id))) {
1467 rcu_read_unlock(); 1469 rcu_read_unlock();
@@ -1545,6 +1547,25 @@ int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
1545 return 0; 1547 return 0;
1546} 1548}
1547 1549
1550int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
1551 __u32 __user *prog_ids, u32 request_cnt,
1552 __u32 __user *prog_cnt)
1553{
1554 u32 cnt = 0;
1555
1556 if (array)
1557 cnt = bpf_prog_array_length(array);
1558
1559 if (copy_to_user(prog_cnt, &cnt, sizeof(cnt)))
1560 return -EFAULT;
1561
1562 /* return early if user requested only program count or nothing to copy */
1563 if (!request_cnt || !cnt)
1564 return 0;
1565
1566 return bpf_prog_array_copy_to_user(array, prog_ids, request_cnt);
1567}
1568
1548static void bpf_prog_free_deferred(struct work_struct *work) 1569static void bpf_prog_free_deferred(struct work_struct *work)
1549{ 1570{
1550 struct bpf_prog_aux *aux; 1571 struct bpf_prog_aux *aux;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 16beab4767e1..f10609e539d4 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4723,6 +4723,9 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon
4723 rcu_read_unlock(); 4723 rcu_read_unlock();
4724 return 0; 4724 return 0;
4725 } 4725 }
4726
4727 case PERF_EVENT_IOC_QUERY_BPF:
4728 return bpf_event_query_prog_array(event, (void __user *)arg);
4726 default: 4729 default:
4727 return -ENOTTY; 4730 return -ENOTTY;
4728 } 4731 }
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 0ce99c379c30..b143f2a05aff 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -820,3 +820,26 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
820unlock: 820unlock:
821 mutex_unlock(&bpf_event_mutex); 821 mutex_unlock(&bpf_event_mutex);
822} 822}
823
824int bpf_event_query_prog_array(struct perf_event *event, void __user *info)
825{
826 struct perf_event_query_bpf __user *uquery = info;
827 struct perf_event_query_bpf query = {};
828 int ret;
829
830 if (!capable(CAP_SYS_ADMIN))
831 return -EPERM;
832 if (event->attr.type != PERF_TYPE_TRACEPOINT)
833 return -EINVAL;
834 if (copy_from_user(&query, uquery, sizeof(query)))
835 return -EFAULT;
836
837 mutex_lock(&bpf_event_mutex);
838 ret = bpf_prog_array_copy_info(event->tp_event->prog_array,
839 uquery->ids,
840 query.ids_len,
841 &uquery->prog_cnt);
842 mutex_unlock(&bpf_event_mutex);
843
844 return ret;
845}