Linux PARISC architecture development
 help / color / mirror / Atom feed
From: Helge Deller <deller@gmx.de>
To: linux-parisc@vger.kernel.org,
	James Bottomley <James.Bottomley@HansenPartnership.com>,
	John David Anglin <dave.anglin@bell.net>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Subject: [PATCH] parisc: Fix syscall restarts
Date: Sat, 19 Dec 2015 00:30:34 +0100	[thread overview]
Message-ID: <20151218233034.GA24910@p100.box> (raw)

On parisc syscalls which are interrupted by signals sometimes fail to restart
and instead return -ENOSYS which then in the worst case lead to userspace
crashes.
A similiar problem existed on MIPS and was fixed by commit e967ef02 
("MIPS: Fix restart of indirect syscalls").

On parisc the current syscall restart code assumes hat the syscall number is
always loaded in the delay branch of the ble instruction as defined in the
unistd.h header file and as such never restored %r20 before returning to
userspace:
	ble 0x100(%sr2, %r0)
	ldi #syscall_nr, %r20

This assumption is at least not true for code which uses the syscall() glibc
function, which instead uses this syntax:
	ble 0x100(%sr2, %r0)
	copy regX, %r20
where regX depend on how the compiler optimizes the code and register usage.

This patch fixes this problem by adding code to analyze how the syscall number
is loaded in the delay branch and - if needed - copy the syscall number to regX
prior returning to userspace for the syscall restart.

Signed-off-by: Helge Deller <deller@gmx.de>
Cc: stable@vger.kernel.org
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>

diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index dc1ea79..b0414ad 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -435,6 +435,48 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs, int in_syscall)
 		regs->gr[28]);
 }
 
+/*
+ * Check the delay branch in userspace how the syscall number gets loaded into
+ * %r20 and adjust as needed.
+ */
+
+static void check_syscallno_in_delay_branch(struct pt_regs *regs)
+{
+	unsigned int opcode, source_reg;
+	u32 __user *uaddr;
+
+	/* Usually we don't have to restore %r20 (the system call number)
+	 * because it gets loaded in the delay slot of the branch external
+	 * instruction via the ldi instruction.
+	 * In some cases a register-to-register copy instruction might have
+	 * been used instead, in which case we need to copy the syscall
+	 * number into the source register before returning to userspace.
+	 */
+
+	/* A syscall is just a branch, so all
+	 * we have to do is fiddle the return pointer.
+	 */
+	regs->gr[31] -= 8; /* delayed branching */
+
+	/* Get assembler opcode of code in delay branch */
+	uaddr = (unsigned int *) (regs->gr[31] + 1);
+	get_user(opcode, uaddr);
+
+	/* Check if delay branch uses "ldi int,%r20" */
+	if ((opcode & 0xffff0000) == 0x34140000)
+		return;	/* everything ok, just return */
+
+	/* Check if delay branch uses "copy %rX,%r20" */
+	if ((opcode & 0xff00ffff) == 0x08000254) {
+		source_reg = (opcode >> 16) & 31;
+		regs->gr[source_reg] = regs->gr[20];
+		return;
+	}
+
+	pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n",
+		current->comm, task_pid_nr(current), opcode);
+}
+
 static inline void
 syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
@@ -457,10 +499,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 		}
 		/* fallthrough */
 	case -ERESTARTNOINTR:
-		/* A syscall is just a branch, so all
-		 * we have to do is fiddle the return pointer.
-		 */
-		regs->gr[31] -= 8; /* delayed branching */
+		check_syscallno_in_delay_branch(regs);
 		break;
 	}
 }
@@ -510,15 +549,9 @@ insert_restart_trampoline(struct pt_regs *regs)
 	}
 	case -ERESTARTNOHAND:
 	case -ERESTARTSYS:
-	case -ERESTARTNOINTR: {
-		/* Hooray for delayed branching.  We don't
-		 * have to restore %r20 (the system call
-		 * number) because it gets loaded in the delay
-		 * slot of the branch external instruction.
-		 */
-		regs->gr[31] -= 8;
+	case -ERESTARTNOINTR:
+		check_syscallno_in_delay_branch(regs);
 		return;
-	}
 	default:
 		break;
 	}

             reply	other threads:[~2015-12-18 23:30 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-18 23:30 Helge Deller [this message]
2015-12-20 13:59 ` [PATCH] parisc: Fix syscall restarts Mathieu Desnoyers
2015-12-20 14:09   ` Mathieu Desnoyers
2015-12-20 15:49     ` Helge Deller
2015-12-20 16:50       ` James Bottomley
2015-12-20 20:35         ` Helge Deller
2015-12-21  8:03           ` James Bottomley
2015-12-21 14:39             ` Mathieu Desnoyers
2015-12-20 18:31       ` John David Anglin
2015-12-20 19:32         ` Helge Deller
2015-12-20 19:46           ` John David Anglin
2015-12-20 20:06             ` Helge Deller
2015-12-20 23:57             ` John David Anglin
2015-12-21 14:42         ` Mathieu Desnoyers
2015-12-21 15:12           ` John David Anglin
2015-12-20 19:39 ` John David Anglin
2015-12-20 19:48   ` Helge Deller
2015-12-20 20:01     ` John David Anglin
2015-12-20 20:18       ` Helge Deller
2015-12-20 20:45         ` John David Anglin
2015-12-20 20:14 ` John David Anglin
2015-12-20 20:19   ` Helge Deller
2015-12-20 20:21     ` Helge Deller
2015-12-20 20:53       ` John David Anglin
2015-12-21  9:19 ` [PATCH] parisc: Fix syscall restarts (v2) Helge Deller
2015-12-21 13:11   ` John David Anglin
2015-12-21 20:27   ` Mathieu Desnoyers
2015-12-21 20:54     ` Helge Deller
2015-12-24 16:07       ` Mathieu Desnoyers
2015-12-24 16:51         ` John David Anglin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151218233034.GA24910@p100.box \
    --to=deller@gmx.de \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=dave.anglin@bell.net \
    --cc=linux-parisc@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox