diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-24 08:18:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-24 08:18:19 -0400 |
commit | 2ce413ec1694eca3a4fa738b6d9007c728a0d40a (patch) | |
tree | 427f27f51f48d40980b304f7e181771688dc4def | |
parent | 64dd76559d4ba281f020af7c87f16071394d1f70 (diff) | |
parent | 784e0300fe9fe4aa81bd7df9d59e138f56bb605b (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.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.c | 4 | ||||
-rw-r--r-- | arch/x86/entry/common.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/signal.c | 2 | ||||
-rw-r--r-- | include/linux/sched.h | 23 | ||||
-rw-r--r-- | kernel/rseq.c | 7 | ||||
-rw-r--r-- | tools/testing/selftests/rseq/rseq-arm.h | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/testing/selftests/rseq/run_param_test.sh | 0 |
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 | ||
1802 | void __rseq_handle_notify_resume(struct pt_regs *regs); | 1802 | void __rseq_handle_notify_resume(struct ksignal *sig, struct pt_regs *regs); |
1803 | 1803 | ||
1804 | static inline void rseq_handle_notify_resume(struct pt_regs *regs) | 1804 | static 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 | ||
1810 | static inline void rseq_signal_deliver(struct pt_regs *regs) | 1811 | static 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, ¤t->rseq_event_mask); | 1815 | __set_bit(RSEQ_EVENT_SIGNAL_BIT, ¤t->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 | */ |
1838 | static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags) | 1838 | static 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) | |||
1864 | static inline void rseq_set_notify_resume(struct task_struct *t) | 1863 | static inline void rseq_set_notify_resume(struct task_struct *t) |
1865 | { | 1864 | { |
1866 | } | 1865 | } |
1867 | static inline void rseq_handle_notify_resume(struct pt_regs *regs) | 1866 | static inline void rseq_handle_notify_resume(struct ksignal *ksig, |
1867 | struct pt_regs *regs) | ||
1868 | { | 1868 | { |
1869 | } | 1869 | } |
1870 | static inline void rseq_signal_deliver(struct pt_regs *regs) | 1870 | static inline void rseq_signal_deliver(struct ksignal *ksig, |
1871 | struct pt_regs *regs) | ||
1871 | { | 1872 | { |
1872 | } | 1873 | } |
1873 | static inline void rseq_preempt(struct task_struct *t) | 1874 | static 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 | */ |
254 | void __rseq_handle_notify_resume(struct pt_regs *regs) | 254 | void __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 | ||
270 | error: | 270 | error: |
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 | |||