| @@ -48,6 +48,8 @@ · 47 unmodified lines |
| 48 | 48 | #include <linux/parser.h> |
| 49 | 49 | #include <linux/sched/clock.h> |
| 50 | 50 | #include <linux/sched/mm.h> |
| 51 | +#include <linux/proc_ns.h> |
| 52 | +#include <linux/mount.h> |
| 51 | 53 | |
| 52 | 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 | 382 | static atomic_t nr_mmap_events __read_mostly; |
| 381 | 383 | static atomic_t nr_comm_events __read_mostly; |
| 384 | +static atomic_t nr_namespaces_events __read_mostly; |
| 382 | 385 | static atomic_t nr_task_events __read_mostly; |
| 383 | 386 | static atomic_t nr_freq_events __read_mostly; |
| 384 | 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 | 3994 | atomic_dec(&nr_mmap_events); |
| 3992 | 3995 | if (event->attr.comm) |
| 3993 | 3996 | atomic_dec(&nr_comm_events); |
| 3997 | + if (event->attr.namespaces) |
| 3998 | + atomic_dec(&nr_namespaces_events); |
| 3994 | 3999 | if (event->attr.task) |
| 3995 | 4000 | atomic_dec(&nr_task_events); |
| 3996 | 4001 | if (event->attr.freq) |
| @@ -6491,6 +6496,7 @@ static void perf_event_task(struct task_struct *task, · 2494 unmodified lines |
| 6491 | 6496 | void perf_event_fork(struct task_struct *task) |
| 6492 | 6497 | { |
| 6493 | 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 | 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 | 6728 | * mmap tracking |
| 6597 | 6729 | */ |
| @@ -9146,6 +9278,8 @@ static void account_event(struct perf_event *event) · 2548 unmodified lines |
| 9146 | 9278 | atomic_inc(&nr_mmap_events); |
| 9147 | 9279 | if (event->attr.comm) |
| 9148 | 9280 | atomic_inc(&nr_comm_events); |
| 9281 | + if (event->attr.namespaces) |
| 9282 | + atomic_inc(&nr_namespaces_events); |
| 9149 | 9283 | if (event->attr.task) |
| 9150 | 9284 | atomic_inc(&nr_task_events); |
| 9151 | 9285 | if (event->attr.freq) |
| @@ -9691,6 +9825,11 @@ SYSCALL_DEFINE5(perf_event_open, · 539 unmodified lines |
| 9691 | 9825 | return -EACCES; |
| 9692 | 9826 | } |
| 9693 | 9827 | |
| 9828 | + if (attr.namespaces) { |
| 9829 | + if (!capable(CAP_SYS_ADMIN)) |
| 9830 | + return -EACCES; |
| 9831 | + } |
| 9832 | + |
| 9694 | 9833 | if (attr.freq) { |
| 9695 | 9834 | if (attr.sample_freq > sysctl_perf_event_sample_rate) |
| 9696 | 9835 | return -EINVAL; |