diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/events/core.c | 139 | ||||
| -rw-r--r-- | kernel/fork.c | 2 | ||||
| -rw-r--r-- | kernel/kprobes.c | 5 | ||||
| -rw-r--r-- | kernel/nsproxy.c | 3 |
4 files changed, 147 insertions, 2 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index 6f41548f2e32..16c877a121c8 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -48,6 +48,8 @@ | |||
| 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); | |||
| 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) | |||
| 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, | |||
| 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 | /* |
| @@ -6593,6 +6599,132 @@ void perf_event_comm(struct task_struct *task, bool exec) | |||
| 6593 | } | 6599 | } |
| 6594 | 6600 | ||
| 6595 | /* | 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 | |||
| 6727 | /* | ||
| 6596 | * mmap tracking | 6728 | * mmap tracking |
| 6597 | */ | 6729 | */ |
| 6598 | 6730 | ||
| @@ -9146,6 +9278,8 @@ static void account_event(struct perf_event *event) | |||
| 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, | |||
| 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; |
diff --git a/kernel/fork.c b/kernel/fork.c index 6c463c80e93d..afa2947286cd 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -2352,6 +2352,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) | |||
| 2352 | } | 2352 | } |
| 2353 | } | 2353 | } |
| 2354 | 2354 | ||
| 2355 | perf_event_namespaces(current); | ||
| 2356 | |||
| 2355 | bad_unshare_cleanup_cred: | 2357 | bad_unshare_cleanup_cred: |
| 2356 | if (new_cred) | 2358 | if (new_cred) |
| 2357 | put_cred(new_cred); | 2359 | put_cred(new_cred); |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 448759d4a263..4780ec236035 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -1740,11 +1740,12 @@ void unregister_kprobes(struct kprobe **kps, int num) | |||
| 1740 | } | 1740 | } |
| 1741 | EXPORT_SYMBOL_GPL(unregister_kprobes); | 1741 | EXPORT_SYMBOL_GPL(unregister_kprobes); |
| 1742 | 1742 | ||
| 1743 | int __weak __kprobes kprobe_exceptions_notify(struct notifier_block *self, | 1743 | int __weak kprobe_exceptions_notify(struct notifier_block *self, |
| 1744 | unsigned long val, void *data) | 1744 | unsigned long val, void *data) |
| 1745 | { | 1745 | { |
| 1746 | return NOTIFY_DONE; | 1746 | return NOTIFY_DONE; |
| 1747 | } | 1747 | } |
| 1748 | NOKPROBE_SYMBOL(kprobe_exceptions_notify); | ||
| 1748 | 1749 | ||
| 1749 | static struct notifier_block kprobe_exceptions_nb = { | 1750 | static struct notifier_block kprobe_exceptions_nb = { |
| 1750 | .notifier_call = kprobe_exceptions_notify, | 1751 | .notifier_call = kprobe_exceptions_notify, |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 782102e59eed..f6c5d330059a 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/file.h> | 26 | #include <linux/file.h> |
| 27 | #include <linux/syscalls.h> | 27 | #include <linux/syscalls.h> |
| 28 | #include <linux/cgroup.h> | 28 | #include <linux/cgroup.h> |
| 29 | #include <linux/perf_event.h> | ||
| 29 | 30 | ||
| 30 | static struct kmem_cache *nsproxy_cachep; | 31 | static struct kmem_cache *nsproxy_cachep; |
| 31 | 32 | ||
| @@ -262,6 +263,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) | |||
| 262 | goto out; | 263 | goto out; |
| 263 | } | 264 | } |
| 264 | switch_task_namespaces(tsk, new_nsproxy); | 265 | switch_task_namespaces(tsk, new_nsproxy); |
| 266 | |||
| 267 | perf_event_namespaces(tsk); | ||
| 265 | out: | 268 | out: |
| 266 | fput(file); | 269 | fput(file); |
| 267 | return err; | 270 | return err; |
