aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/Kconfig10
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/thread_info.h7
-rw-r--r--arch/x86/kernel/process.c2
-rw-r--r--arch/x86/kernel/signal.c3
-rw-r--r--include/linux/user-return-notifier.h42
-rw-r--r--kernel/user-return-notifier.c46
7 files changed, 109 insertions, 2 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index 7f418bbc261a..4e312fffbfd7 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -83,6 +83,13 @@ config KRETPROBES
83 def_bool y 83 def_bool y
84 depends on KPROBES && HAVE_KRETPROBES 84 depends on KPROBES && HAVE_KRETPROBES
85 85
86config USER_RETURN_NOTIFIER
87 bool
88 depends on HAVE_USER_RETURN_NOTIFIER
89 help
90 Provide a kernel-internal notification when a cpu is about to
91 switch to user mode.
92
86config HAVE_IOREMAP_PROT 93config HAVE_IOREMAP_PROT
87 bool 94 bool
88 95
@@ -126,4 +133,7 @@ config HAVE_DMA_API_DEBUG
126config HAVE_DEFAULT_NO_SPIN_MUTEXES 133config HAVE_DEFAULT_NO_SPIN_MUTEXES
127 bool 134 bool
128 135
136config HAVE_USER_RETURN_NOTIFIER
137 bool
138
129source "kernel/gcov/Kconfig" 139source "kernel/gcov/Kconfig"
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8da93745c087..1df175d15aa8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -50,6 +50,7 @@ config X86
50 select HAVE_KERNEL_BZIP2 50 select HAVE_KERNEL_BZIP2
51 select HAVE_KERNEL_LZMA 51 select HAVE_KERNEL_LZMA
52 select HAVE_ARCH_KMEMCHECK 52 select HAVE_ARCH_KMEMCHECK
53 select HAVE_USER_RETURN_NOTIFIER
53 54
54config OUTPUT_FORMAT 55config OUTPUT_FORMAT
55 string 56 string
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index d27d0a2fec4c..375c917c37d2 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -83,6 +83,7 @@ struct thread_info {
83#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ 83#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
84#define TIF_SECCOMP 8 /* secure computing */ 84#define TIF_SECCOMP 8 /* secure computing */
85#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ 85#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
86#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
86#define TIF_NOTSC 16 /* TSC is not accessible in userland */ 87#define TIF_NOTSC 16 /* TSC is not accessible in userland */
87#define TIF_IA32 17 /* 32bit process */ 88#define TIF_IA32 17 /* 32bit process */
88#define TIF_FORK 18 /* ret_from_fork */ 89#define TIF_FORK 18 /* ret_from_fork */
@@ -107,6 +108,7 @@ struct thread_info {
107#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) 108#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
108#define _TIF_SECCOMP (1 << TIF_SECCOMP) 109#define _TIF_SECCOMP (1 << TIF_SECCOMP)
109#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) 110#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
111#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
110#define _TIF_NOTSC (1 << TIF_NOTSC) 112#define _TIF_NOTSC (1 << TIF_NOTSC)
111#define _TIF_IA32 (1 << TIF_IA32) 113#define _TIF_IA32 (1 << TIF_IA32)
112#define _TIF_FORK (1 << TIF_FORK) 114#define _TIF_FORK (1 << TIF_FORK)
@@ -142,13 +144,14 @@ struct thread_info {
142 144
143/* Only used for 64 bit */ 145/* Only used for 64 bit */
144#define _TIF_DO_NOTIFY_MASK \ 146#define _TIF_DO_NOTIFY_MASK \
145 (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME) 147 (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \
148 _TIF_USER_RETURN_NOTIFY)
146 149
147/* flags to check in __switch_to() */ 150/* flags to check in __switch_to() */
148#define _TIF_WORK_CTXSW \ 151#define _TIF_WORK_CTXSW \
149 (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC) 152 (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC)
150 153
151#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW 154#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
152#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) 155#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
153 156
154#define PREEMPT_ACTIVE 0x10000000 157#define PREEMPT_ACTIVE 0x10000000
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 5284cd2b5776..e51b056fc88f 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -9,6 +9,7 @@
9#include <linux/pm.h> 9#include <linux/pm.h>
10#include <linux/clockchips.h> 10#include <linux/clockchips.h>
11#include <linux/random.h> 11#include <linux/random.h>
12#include <linux/user-return-notifier.h>
12#include <trace/events/power.h> 13#include <trace/events/power.h>
13#include <asm/system.h> 14#include <asm/system.h>
14#include <asm/apic.h> 15#include <asm/apic.h>
@@ -224,6 +225,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
224 */ 225 */
225 memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); 226 memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
226 } 227 }
228 propagate_user_return_notify(prev_p, next_p);
227} 229}
228 230
229int sys_fork(struct pt_regs *regs) 231int sys_fork(struct pt_regs *regs)
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 6a44a76055ad..c49f90f7957a 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -19,6 +19,7 @@
19#include <linux/stddef.h> 19#include <linux/stddef.h>
20#include <linux/personality.h> 20#include <linux/personality.h>
21#include <linux/uaccess.h> 21#include <linux/uaccess.h>
22#include <linux/user-return-notifier.h>
22 23
23#include <asm/processor.h> 24#include <asm/processor.h>
24#include <asm/ucontext.h> 25#include <asm/ucontext.h>
@@ -872,6 +873,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
872 if (current->replacement_session_keyring) 873 if (current->replacement_session_keyring)
873 key_replace_session_keyring(); 874 key_replace_session_keyring();
874 } 875 }
876 if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
877 fire_user_return_notifiers();
875 878
876#ifdef CONFIG_X86_32 879#ifdef CONFIG_X86_32
877 clear_thread_flag(TIF_IRET); 880 clear_thread_flag(TIF_IRET);
diff --git a/include/linux/user-return-notifier.h b/include/linux/user-return-notifier.h
new file mode 100644
index 000000000000..b6ac056291d7
--- /dev/null
+++ b/include/linux/user-return-notifier.h
@@ -0,0 +1,42 @@
1#ifndef _LINUX_USER_RETURN_NOTIFIER_H
2#define _LINUX_USER_RETURN_NOTIFIER_H
3
4#ifdef CONFIG_USER_RETURN_NOTIFIER
5
6#include <linux/list.h>
7#include <linux/sched.h>
8
9struct user_return_notifier {
10 void (*on_user_return)(struct user_return_notifier *urn);
11 struct hlist_node link;
12};
13
14
15void user_return_notifier_register(struct user_return_notifier *urn);
16void user_return_notifier_unregister(struct user_return_notifier *urn);
17
18static inline void propagate_user_return_notify(struct task_struct *prev,
19 struct task_struct *next)
20{
21 if (test_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY)) {
22 clear_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY);
23 set_tsk_thread_flag(next, TIF_USER_RETURN_NOTIFY);
24 }
25}
26
27void fire_user_return_notifiers(void);
28
29#else
30
31struct user_return_notifier {};
32
33static inline void propagate_user_return_notify(struct task_struct *prev,
34 struct task_struct *next)
35{
36}
37
38static inline void fire_user_return_notifiers(void) {}
39
40#endif
41
42#endif
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
new file mode 100644
index 000000000000..530ccb816513
--- /dev/null
+++ b/kernel/user-return-notifier.c
@@ -0,0 +1,46 @@
1
2#include <linux/user-return-notifier.h>
3#include <linux/percpu.h>
4#include <linux/sched.h>
5#include <linux/module.h>
6
7static DEFINE_PER_CPU(struct hlist_head, return_notifier_list);
8
9#define URN_LIST_HEAD per_cpu(return_notifier_list, raw_smp_processor_id())
10
11/*
12 * Request a notification when the current cpu returns to userspace. Must be
13 * called in atomic context. The notifier will also be called in atomic
14 * context.
15 */
16void user_return_notifier_register(struct user_return_notifier *urn)
17{
18 set_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
19 hlist_add_head(&urn->link, &URN_LIST_HEAD);
20}
21EXPORT_SYMBOL_GPL(user_return_notifier_register);
22
23/*
24 * Removes a registered user return notifier. Must be called from atomic
25 * context, and from the same cpu registration occured in.
26 */
27void user_return_notifier_unregister(struct user_return_notifier *urn)
28{
29 hlist_del(&urn->link);
30 if (hlist_empty(&URN_LIST_HEAD))
31 clear_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
32}
33EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
34
35/* Calls registered user return notifiers */
36void fire_user_return_notifiers(void)
37{
38 struct user_return_notifier *urn;
39 struct hlist_node *tmp1, *tmp2;
40 struct hlist_head *head;
41
42 head = &get_cpu_var(return_notifier_list);
43 hlist_for_each_entry_safe(urn, tmp1, tmp2, head, link)
44 urn->on_user_return(urn);
45 put_cpu_var();
46}