linux/arch
Al Viro ef8deb2ab7 arm: fix really nasty sigreturn bug
commit 653d48b221 upstream.

If a signal hits us outside of a syscall and another gets delivered
when we are in sigreturn (e.g. because it had been in sa_mask for
the first one and got sent to us while we'd been in the first handler),
we have a chance of returning from the second handler to location one
insn prior to where we ought to return.  If r0 happens to contain -513
(-ERESTARTNOINTR), sigreturn will get confused into doing restart
syscall song and dance.

Incredible joy to debug, since it manifests as random, infrequent and
very hard to reproduce double execution of instructions in userland
code...

The fix is simple - mark it "don't bother with restarts" in wrapper,
i.e. set r8 to 0 in sys_sigreturn and sys_rt_sigreturn wrappers,
suppressing the syscall restart handling on return from these guys.
They can't legitimately return a restart-worthy error anyway.

Testcase:
	#include <unistd.h>
	#include <signal.h>
	#include <stdlib.h>
	#include <sys/time.h>
	#include <errno.h>

	void f(int n)
	{
		__asm__ __volatile__(
			"ldr r0, [%0]\n"
			"b 1f\n"
			"b 2f\n"
			"1:b .\n"
			"2:\n" : : "r"(&n));
	}

	void handler1(int sig) { }
	void handler2(int sig) { raise(1); }
	void handler3(int sig) { exit(0); }

	main()
	{
		struct sigaction s = {.sa_handler = handler2};
		struct itimerval t1 = { .it_value = {1} };
		struct itimerval t2 = { .it_value = {2} };

		signal(1, handler1);

		sigemptyset(&s.sa_mask);
		sigaddset(&s.sa_mask, 1);
		sigaction(SIGALRM, &s, NULL);

		signal(SIGVTALRM, handler3);

		setitimer(ITIMER_REAL, &t1, NULL);
		setitimer(ITIMER_VIRTUAL, &t2, NULL);

		f(-513); /* -ERESTARTNOINTR */

		write(1, "buggered\n", 9);
		return 1;
	}

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-09-20 13:18:12 -07:00
..
alpha untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
arm arm: fix really nasty sigreturn bug 2010-09-20 13:18:12 -07:00
avr32 untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
blackfin Blackfin: set ARCH_KMALLOC_MINALIGN 2010-07-05 11:10:50 -07:00
cris untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
frv frv: set ARCH_KMALLOC_MINALIGN 2010-07-05 11:10:49 -07:00
h8300 untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
ia64 compat: Make compat_alloc_user_space() incorporate the access_ok() 2010-09-20 13:17:57 -07:00
m32r untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
m68k m68k: set ARCH_KMALLOC_MINALIGN 2010-07-05 11:10:48 -07:00
m68knommu untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
microblaze untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
mips compat: Make compat_alloc_user_space() incorporate the access_ok() 2010-09-20 13:17:57 -07:00
mn10300 mn10300: set ARCH_KMALLOC_MINALIGN 2010-07-05 11:10:47 -07:00
parisc compat: Make compat_alloc_user_space() incorporate the access_ok() 2010-09-20 13:17:57 -07:00
powerpc compat: Make compat_alloc_user_space() incorporate the access_ok() 2010-09-20 13:17:57 -07:00
s390 compat: Make compat_alloc_user_space() incorporate the access_ok() 2010-09-20 13:17:57 -07:00
score untangle the do_mremap() mess 2010-01-18 10:19:11 -08:00
sh sh: Fix FDPIC binary loader 2010-04-26 07:41:17 -07:00
sparc compat: Make compat_alloc_user_space() incorporate the access_ok() 2010-09-20 13:17:57 -07:00
um x86: Fix breakage of UML from the changes in the rwsem system 2010-04-26 07:41:28 -07:00
x86 x86-64, compat: Retruncate rax after ia32 syscall entry tracing 2010-09-20 13:17:57 -07:00
xtensa xtensa: set ARCH_KMALLOC_MINALIGN 2010-07-05 11:10:50 -07:00
.gitignore
Kconfig oprofile: remove tracing build dependency 2010-03-15 08:49:47 -07:00