aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-24 08:18:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-24 08:18:19 -0400
commit2ce413ec1694eca3a4fa738b6d9007c728a0d40a (patch)
tree427f27f51f48d40980b304f7e181771688dc4def
parent64dd76559d4ba281f020af7c87f16071394d1f70 (diff)
parent784e0300fe9fe4aa81bd7df9d59e138f56bb605b (diff)
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull rseq fixes from Thomas Gleixer: "A pile of rseq related fixups: - Prevent infinite recursion when delivering SIGSEGV - Remove the abort of rseq critical section on fork() as syscalls inside rseq critical sections are explicitely forbidden. So no point in doing the abort on the child. - Align the rseq structure on 32 bytes in the ARM selftest code. - Fix file permissions of the test script" * 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: rseq: Avoid infinite recursion when delivering SIGSEGV rseq/cleanup: Do not abort rseq c.s. in child on fork() rseq/selftests/arm: Align 'struct rseq_cs' on 32 bytes rseq/selftests: Make run_param_test.sh executable
-rw-r--r--arch/arm/kernel/signal.c4
-rw-r--r--arch/powerpc/kernel/signal.c4
-rw-r--r--arch/x86/entry/common.c2
-rw-r--r--arch/x86/kernel/signal.c2
-rw-r--r--include/linux/sched.h23
-rw-r--r--kernel/rseq.c7
-rw-r--r--tools/testing/selftests/rseq/rseq-arm.h1
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/rseq/run_param_test.sh0
8 files changed, 23 insertions, 20 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index f09e9d66d605..dec130e7078c 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -544,7 +544,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
544 * Increment event counter and perform fixup for the pre-signal 544 * Increment event counter and perform fixup for the pre-signal
545 * frame. 545 * frame.
546 */ 546 */
547 rseq_signal_deliver(regs); 547 rseq_signal_deliver(ksig, regs);
548 548
549 /* 549 /*
550 * Set up the stack frame 550 * Set up the stack frame
@@ -666,7 +666,7 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
666 } else { 666 } else {
667 clear_thread_flag(TIF_NOTIFY_RESUME); 667 clear_thread_flag(TIF_NOTIFY_RESUME);
668 tracehook_notify_resume(regs); 668 tracehook_notify_resume(regs);
669 rseq_handle_notify_resume(regs); 669 rseq_handle_notify_resume(NULL, regs);
670 } 670 }
671 } 671 }
672 local_irq_disable(); 672 local_irq_disable();
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 17fe4339ba59..b3e8db376ecd 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -134,7 +134,7 @@ static void do_signal(struct task_struct *tsk)
134 /* Re-enable the breakpoints for the signal stack */ 134 /* Re-enable the breakpoints for the signal stack */
135 thread_change_pc(tsk, tsk->thread.regs); 135 thread_change_pc(tsk, tsk->thread.regs);
136 136
137 rseq_signal_deliver(tsk->thread.regs); 137 rseq_signal_deliver(&ksig, tsk->thread.regs);
138 138
139 if (is32) { 139 if (is32) {
140 if (ksig.ka.sa.sa_flags & SA_SIGINFO) 140 if (ksig.ka.sa.sa_flags & SA_SIGINFO)
@@ -170,7 +170,7 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
170 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 170 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
171 clear_thread_flag(TIF_NOTIFY_RESUME); 171 clear_thread_flag(TIF_NOTIFY_RESUME);
172 tracehook_notify_resume(regs); 172 tracehook_notify_resume(regs);
173 rseq_handle_notify_resume(regs); 173 rseq_handle_notify_resume(NULL, regs);
174 } 174 }
175 175
176 user_enter(); 176 user_enter();
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index 92190879b228..3b2490b81918 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -164,7 +164,7 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags)
164 if (cached_flags & _TIF_NOTIFY_RESUME) { 164 if (cached_flags & _TIF_NOTIFY_RESUME) {
165 clear_thread_flag(TIF_NOTIFY_RESUME); 165 clear_thread_flag(TIF_NOTIFY_RESUME);
166 tracehook_notify_resume(regs); 166 tracehook_notify_resume(regs);
167 rseq_handle_notify_resume(regs); 167 rseq_handle_notify_resume(NULL, regs);
168 } 168 }
169 169
170 if (cached_flags & _TIF_USER_RETURN_NOTIFY) 170 if (cached_flags & _TIF_USER_RETURN_NOTIFY)
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 445ca11ff863..92a3b312a53c 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -692,7 +692,7 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
692 * Increment event counter and perform fixup for the pre-signal 692 * Increment event counter and perform fixup for the pre-signal
693 * frame. 693 * frame.
694 */ 694 */
695 rseq_signal_deliver(regs); 695 rseq_signal_deliver(ksig, regs);
696 696
697 /* Set up the stack frame */ 697 /* Set up the stack frame */
698 if (is_ia32_frame(ksig)) { 698 if (is_ia32_frame(ksig)) {
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 87bf02d93a27..9256118bd40c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1799,20 +1799,22 @@ static inline void rseq_set_notify_resume(struct task_struct *t)
1799 set_tsk_thread_flag(t, TIF_NOTIFY_RESUME); 1799 set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
1800} 1800}
1801 1801
1802void __rseq_handle_notify_resume(struct pt_regs *regs); 1802void __rseq_handle_notify_resume(struct ksignal *sig, struct pt_regs *regs);
1803 1803
1804static inline void rseq_handle_notify_resume(struct pt_regs *regs) 1804static inline void rseq_handle_notify_resume(struct ksignal *ksig,
1805 struct pt_regs *regs)
1805{ 1806{
1806 if (current->rseq) 1807 if (current->rseq)
1807 __rseq_handle_notify_resume(regs); 1808 __rseq_handle_notify_resume(ksig, regs);
1808} 1809}
1809 1810
1810static inline void rseq_signal_deliver(struct pt_regs *regs) 1811static inline void rseq_signal_deliver(struct ksignal *ksig,
1812 struct pt_regs *regs)
1811{ 1813{
1812 preempt_disable(); 1814 preempt_disable();
1813 __set_bit(RSEQ_EVENT_SIGNAL_BIT, &current->rseq_event_mask); 1815 __set_bit(RSEQ_EVENT_SIGNAL_BIT, &current->rseq_event_mask);
1814 preempt_enable(); 1816 preempt_enable();
1815 rseq_handle_notify_resume(regs); 1817 rseq_handle_notify_resume(ksig, regs);
1816} 1818}
1817 1819
1818/* rseq_preempt() requires preemption to be disabled. */ 1820/* rseq_preempt() requires preemption to be disabled. */
@@ -1831,9 +1833,7 @@ static inline void rseq_migrate(struct task_struct *t)
1831 1833
1832/* 1834/*
1833 * If parent process has a registered restartable sequences area, the 1835 * If parent process has a registered restartable sequences area, the
1834 * child inherits. Only applies when forking a process, not a thread. In 1836 * child inherits. Only applies when forking a process, not a thread.
1835 * case a parent fork() in the middle of a restartable sequence, set the
1836 * resume notifier to force the child to retry.
1837 */ 1837 */
1838static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags) 1838static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags)
1839{ 1839{
@@ -1847,7 +1847,6 @@ static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags)
1847 t->rseq_len = current->rseq_len; 1847 t->rseq_len = current->rseq_len;
1848 t->rseq_sig = current->rseq_sig; 1848 t->rseq_sig = current->rseq_sig;
1849 t->rseq_event_mask = current->rseq_event_mask; 1849 t->rseq_event_mask = current->rseq_event_mask;
1850 rseq_preempt(t);
1851 } 1850 }
1852} 1851}
1853 1852
@@ -1864,10 +1863,12 @@ static inline void rseq_execve(struct task_struct *t)
1864static inline void rseq_set_notify_resume(struct task_struct *t) 1863static inline void rseq_set_notify_resume(struct task_struct *t)
1865{ 1864{
1866} 1865}
1867static inline void rseq_handle_notify_resume(struct pt_regs *regs) 1866static inline void rseq_handle_notify_resume(struct ksignal *ksig,
1867 struct pt_regs *regs)
1868{ 1868{
1869} 1869}
1870static inline void rseq_signal_deliver(struct pt_regs *regs) 1870static inline void rseq_signal_deliver(struct ksignal *ksig,
1871 struct pt_regs *regs)
1871{ 1872{
1872} 1873}
1873static inline void rseq_preempt(struct task_struct *t) 1874static inline void rseq_preempt(struct task_struct *t)
diff --git a/kernel/rseq.c b/kernel/rseq.c
index ae306f90c514..22b6acf1ad63 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -251,10 +251,10 @@ static int rseq_ip_fixup(struct pt_regs *regs)
251 * respect to other threads scheduled on the same CPU, and with respect 251 * respect to other threads scheduled on the same CPU, and with respect
252 * to signal handlers. 252 * to signal handlers.
253 */ 253 */
254void __rseq_handle_notify_resume(struct pt_regs *regs) 254void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
255{ 255{
256 struct task_struct *t = current; 256 struct task_struct *t = current;
257 int ret; 257 int ret, sig;
258 258
259 if (unlikely(t->flags & PF_EXITING)) 259 if (unlikely(t->flags & PF_EXITING))
260 return; 260 return;
@@ -268,7 +268,8 @@ void __rseq_handle_notify_resume(struct pt_regs *regs)
268 return; 268 return;
269 269
270error: 270error:
271 force_sig(SIGSEGV, t); 271 sig = ksig ? ksig->sig : 0;
272 force_sigsegv(sig, t);
272} 273}
273 274
274#ifdef CONFIG_DEBUG_RSEQ 275#ifdef CONFIG_DEBUG_RSEQ
diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h
index 3b055f9aeaab..3cea19877227 100644
--- a/tools/testing/selftests/rseq/rseq-arm.h
+++ b/tools/testing/selftests/rseq/rseq-arm.h
@@ -57,6 +57,7 @@ do { \
57#define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \ 57#define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
58 abort_label, version, flags, \ 58 abort_label, version, flags, \
59 start_ip, post_commit_offset, abort_ip) \ 59 start_ip, post_commit_offset, abort_ip) \
60 ".balign 32\n\t" \
60 __rseq_str(table_label) ":\n\t" \ 61 __rseq_str(table_label) ":\n\t" \
61 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ 62 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
62 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \ 63 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
diff --git a/tools/testing/selftests/rseq/run_param_test.sh b/tools/testing/selftests/rseq/run_param_test.sh
index 3acd6d75ff9f..3acd6d75ff9f 100644..100755
--- a/tools/testing/selftests/rseq/run_param_test.sh
+++ b/tools/testing/selftests/rseq/run_param_test.sh