| @@ -48,6 +48,8 @@ · 47 unmodified lines |
| 48 | #include <linux/parser.h> | 48 | #include <linux/parser.h> |
| 49 | #include <linux/sched/clock.h> | 49 | #include <linux/sched/clock.h> |
| 50 | #include <linux/sched/mm.h> | 50 | #include <linux/sched/mm.h> |
| | 51 | #include <linux/proc_ns.h> |
| | 52 | #include <linux/mount.h> |
| 51 | | 53 | |
| 52 | #include "internal.h" | 54 | #include "internal.h" |
| 53 | | 55 | |
| @@ -379,6 +381,7 @@ static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); · 325 unmodified lines |
| 379 | | 381 | |
| 380 | static atomic_t nr_mmap_events __read_mostly; | 382 | static atomic_t nr_mmap_events __read_mostly; |
| 381 | static atomic_t nr_comm_events __read_mostly; | 383 | static atomic_t nr_comm_events __read_mostly; |
| | 384 | static atomic_t nr_namespaces_events __read_mostly; |
| 382 | static atomic_t nr_task_events __read_mostly; | 385 | static atomic_t nr_task_events __read_mostly; |
| 383 | static atomic_t nr_freq_events __read_mostly; | 386 | static atomic_t nr_freq_events __read_mostly; |
| 384 | static atomic_t nr_switch_events __read_mostly; | 387 | static atomic_t nr_switch_events __read_mostly; |
| @@ -3991,6 +3994,8 @@ static void unaccount_event(struct perf_event *event) · 3606 unmodified lines |
| 3991 | atomic_dec(&nr_mmap_events); | 3994 | atomic_dec(&nr_mmap_events); |
| 3992 | if (event->attr.comm) | 3995 | if (event->attr.comm) |
| 3993 | atomic_dec(&nr_comm_events); | 3996 | atomic_dec(&nr_comm_events); |
| | 3997 | if (event->attr.namespaces) |
| | 3998 | atomic_dec(&nr_namespaces_events); |
| 3994 | if (event->attr.task) | 3999 | if (event->attr.task) |
| 3995 | atomic_dec(&nr_task_events); | 4000 | atomic_dec(&nr_task_events); |
| 3996 | if (event->attr.freq) | 4001 | if (event->attr.freq) |
| @@ -6491,6 +6496,7 @@ static void perf_event_task(struct task_struct *task, · 2494 unmodified lines |
| 6491 | void perf_event_fork(struct task_struct *task) | 6496 | void perf_event_fork(struct task_struct *task) |
| 6492 | { | 6497 | { |
| 6493 | perf_event_task(task, NULL, 1); | 6498 | perf_event_task(task, NULL, 1); |
| | 6499 | perf_event_namespaces(task); |
| 6494 | } | 6500 | } |
| 6495 | | 6501 | |
| 6496 | /* | 6502 | /* |
| @@ -6592,6 +6598,132 @@ void perf_event_comm(struct task_struct *task, bool exec) · 95 unmodified lines |
| 6592 | perf_event_comm_event(&comm_event); | 6598 | perf_event_comm_event(&comm_event); |
| 6593 | } | 6599 | } |
| 6594 | | 6600 | |
| | 6601 | /* |
| | 6602 | * namespaces tracking |
| | 6603 | */ |
| | 6604 | |
| | 6605 | struct perf_namespaces_event { |
| | 6606 | struct task_struct *task; |
| | 6607 | |
| | 6608 | struct { |
| | 6609 | struct perf_event_header header; |
| | 6610 | |
| | 6611 | u32 pid; |
| | 6612 | u32 tid; |
| | 6613 | u64 nr_namespaces; |
| | 6614 | struct perf_ns_link_info link_info[NR_NAMESPACES]; |
| | 6615 | } event_id; |
| | 6616 | }; |
| | 6617 | |
| | 6618 | static int perf_event_namespaces_match(struct perf_event *event) |
| | 6619 | { |
| | 6620 | return event->attr.namespaces; |
| | 6621 | } |
| | 6622 | |
| | 6623 | static void perf_event_namespaces_output(struct perf_event *event, |
| | 6624 | void *data) |
| | 6625 | { |
| | 6626 | struct perf_namespaces_event *namespaces_event = data; |
| | 6627 | struct perf_output_handle handle; |
| | 6628 | struct perf_sample_data sample; |
| | 6629 | int ret; |
| | 6630 | |
| | 6631 | if (!perf_event_namespaces_match(event)) |
| | 6632 | return; |
| | 6633 | |
| | 6634 | perf_event_header__init_id(&namespaces_event->event_id.header, |
| | 6635 | &sample, event); |
| | 6636 | ret = perf_output_begin(&handle, event, |
| | 6637 | namespaces_event->event_id.header.size); |
| | 6638 | if (ret) |
| | 6639 | return; |
| | 6640 | |
| | 6641 | namespaces_event->event_id.pid = perf_event_pid(event, |
| | 6642 | namespaces_event->task); |
| | 6643 | namespaces_event->event_id.tid = perf_event_tid(event, |
| | 6644 | namespaces_event->task); |
| | 6645 | |
| | 6646 | perf_output_put(&handle, namespaces_event->event_id); |
| | 6647 | |
| | 6648 | perf_event__output_id_sample(event, &handle, &sample); |
| | 6649 | |
| | 6650 | perf_output_end(&handle); |
| | 6651 | } |
| | 6652 | |
| | 6653 | static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info, |
| | 6654 | struct task_struct *task, |
| | 6655 | const struct proc_ns_operations *ns_ops) |
| | 6656 | { |
| | 6657 | struct path ns_path; |
| | 6658 | struct inode *ns_inode; |
| | 6659 | void *error; |
| | 6660 | |
| | 6661 | error = ns_get_path(&ns_path, task, ns_ops); |
| | 6662 | if (!error) { |
| | 6663 | ns_inode = ns_path.dentry->d_inode; |
| | 6664 | ns_link_info->dev = new_encode_dev(ns_inode->i_sb->s_dev); |
| | 6665 | ns_link_info->ino = ns_inode->i_ino; |
| | 6666 | } |
| | 6667 | } |
| | 6668 | |
| | 6669 | void perf_event_namespaces(struct task_struct *task) |
| | 6670 | { |
| | 6671 | struct perf_namespaces_event namespaces_event; |
| | 6672 | struct perf_ns_link_info *ns_link_info; |
| | 6673 | |
| | 6674 | if (!atomic_read(&nr_namespaces_events)) |
| | 6675 | return; |
| | 6676 | |
| | 6677 | namespaces_event = (struct perf_namespaces_event){ |
| | 6678 | .task = task, |
| | 6679 | .event_id = { |
| | 6680 | .header = { |
| | 6681 | .type = PERF_RECORD_NAMESPACES, |
| | 6682 | .misc = 0, |
| | 6683 | .size = sizeof(namespaces_event.event_id), |
| | 6684 | }, |
| | 6685 | /* .pid */ |
| | 6686 | /* .tid */ |
| | 6687 | .nr_namespaces = NR_NAMESPACES, |
| | 6688 | /* .link_info[NR_NAMESPACES] */ |
| | 6689 | }, |
| | 6690 | }; |
| | 6691 | |
| | 6692 | ns_link_info = namespaces_event.event_id.link_info; |
| | 6693 | |
| | 6694 | perf_fill_ns_link_info(&ns_link_info[MNT_NS_INDEX], |
| | 6695 | task, &mntns_operations); |
| | 6696 | |
| | 6697 | #ifdef CONFIG_USER_NS |
| | 6698 | perf_fill_ns_link_info(&ns_link_info[USER_NS_INDEX], |
| | 6699 | task, &userns_operations); |
| | 6700 | #endif |
| | 6701 | #ifdef CONFIG_NET_NS |
| | 6702 | perf_fill_ns_link_info(&ns_link_info[NET_NS_INDEX], |
| | 6703 | task, &netns_operations); |
| | 6704 | #endif |
| | 6705 | #ifdef CONFIG_UTS_NS |
| | 6706 | perf_fill_ns_link_info(&ns_link_info[UTS_NS_INDEX], |
| | 6707 | task, &utsns_operations); |
| | 6708 | #endif |
| | 6709 | #ifdef CONFIG_IPC_NS |
| | 6710 | perf_fill_ns_link_info(&ns_link_info[IPC_NS_INDEX], |
| | 6711 | task, &ipcns_operations); |
| | 6712 | #endif |
| | 6713 | #ifdef CONFIG_PID_NS |
| | 6714 | perf_fill_ns_link_info(&ns_link_info[PID_NS_INDEX], |
| | 6715 | task, &pidns_operations); |
| | 6716 | #endif |
| | 6717 | #ifdef CONFIG_CGROUPS |
| | 6718 | perf_fill_ns_link_info(&ns_link_info[CGROUP_NS_INDEX], |
| | 6719 | task, &cgroupns_operations); |
| | 6720 | #endif |
| | 6721 | |
| | 6722 | perf_iterate_sb(perf_event_namespaces_output, |
| | 6723 | &namespaces_event, |
| | 6724 | NULL); |
| | 6725 | } |
| | 6726 | |
| 6595 | /* | 6727 | /* |
| 6596 | * mmap tracking | 6728 | * mmap tracking |
| 6597 | */ | 6729 | */ |
| @@ -9146,6 +9278,8 @@ static void account_event(struct perf_event *event) · 2548 unmodified lines |
| 9146 | atomic_inc(&nr_mmap_events); | 9278 | atomic_inc(&nr_mmap_events); |
| 9147 | if (event->attr.comm) | 9279 | if (event->attr.comm) |
| 9148 | atomic_inc(&nr_comm_events); | 9280 | atomic_inc(&nr_comm_events); |
| | 9281 | if (event->attr.namespaces) |
| | 9282 | atomic_inc(&nr_namespaces_events); |
| 9149 | if (event->attr.task) | 9283 | if (event->attr.task) |
| 9150 | atomic_inc(&nr_task_events); | 9284 | atomic_inc(&nr_task_events); |
| 9151 | if (event->attr.freq) | 9285 | if (event->attr.freq) |
| @@ -9691,6 +9825,11 @@ SYSCALL_DEFINE5(perf_event_open, · 539 unmodified lines |
| 9691 | return -EACCES; | 9825 | return -EACCES; |
| 9692 | } | 9826 | } |
| 9693 | | 9827 | |
| | 9828 | if (attr.namespaces) { |
| | 9829 | if (!capable(CAP_SYS_ADMIN)) |
| | 9830 | return -EACCES; |
| | 9831 | } |
| | 9832 | |
| 9694 | if (attr.freq) { | 9833 | if (attr.freq) { |
| 9695 | if (attr.sample_freq > sysctl_perf_event_sample_rate) | 9834 | if (attr.sample_freq > sysctl_perf_event_sample_rate) |
| 9696 | return -EINVAL; | 9835 | return -EINVAL; |