Linux MIPS Architecture development
 help / color / mirror / Atom feed
* unkillable process due to setup_frame() failure
@ 2005-09-06 16:42 Atsushi Nemoto
  2005-09-06 18:41 ` Ralf Baechle
  0 siblings, 1 reply; 11+ messages in thread
From: Atsushi Nemoto @ 2005-09-06 16:42 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf

For a long time, this test program is unkillable (by SIGKILL) on
Linux/MIPS.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sighandler(int sig)
{
	printf("SIGNAL %d!\n", sig);
	exit(2);
}
void setup_signal(int sig)
{
	struct sigaction act;
	memset(&act, 0, sizeof(act));
	act.sa_handler = sighandler;
	act.sa_flags = SA_NOMASK | SA_RESTART;
	sigaction(sig, &act, 0);
}

int main(int argc, char **argv)
{
	setup_signal(SIGTRAP);

	__asm__ __volatile__("move $29,$0");
	__asm__ __volatile__("break");
	printf("done!\n");
	return 0;
}

If we run this program,

1.  The "break" instruction raises a exception.
2.  The exception handler queues SIGTRAP(5).
3.  dequeue_signal() dequeue a signal with LOWEST number (i.e. SIGTRAP).
4.  setup_frame() fails due to bad stack pointer and queues SIGSEGV(11).
5.  returns to user process (pc unchanged).
6.  goto 1. (forever)

So, the process can not be kill by SIGKILL.  In 2.6.12, 'sigkill
priority fix' was applied to __dequeue_signal(), but it does not help
while the SIGTRAP is queued to tsk->pending but SIGKILL (by kill
command) is queued to tsk->signal->shared_pending.

I have two proposal fix:

1. Now do_signal() returns 0 if setup_frame() failed.  Therefore if
   do_signal returned 0 (and there is still pending signal), calling
   do_signal again will handle the SIGSIGV.  Like this:

--- linux-mips/arch/mips/kernel/signal.c	2005-08-30 11:02:00.000000000 +0900
+++ linux/arch/mips/kernel/signal.c	2005-09-06 15:07:45.000000000 +0900
@@ -481,6 +481,10 @@
 {
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING) {
-		current->thread.abi->do_signal(oldset, regs);
+		if (unlikely(!current->thread.abi->do_signal(oldset, regs)) &&
+		    unlikely(signal_pending(current))) {
+			/* SIGSEGV mighe be sent in setup_frame */
+			current->thread.abi->do_signal(oldset, regs);
+		}
 	}
 }



2. Make 'sigkill priority fix' can handle this case.  First search
   SIGKILL in tsk->pending and tsk->signal->shared_pending, then
   search another signals.  Like this:

--- linux-mips/kernel/signal.c	2005-08-29 08:41:01.000000000 +0900
+++ linux/kernel/signal.c	2005-09-07 01:33:52.338420760 +0900
@@ -520,19 +520,14 @@
 }
 
 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
-			siginfo_t *info)
+			siginfo_t *info, int sig)
 {
-	int sig = 0;
-
-	/* SIGKILL must have priority, otherwise it is quite easy
-	 * to create an unkillable process, sending sig < SIGKILL
-	 * to self */
-	if (unlikely(sigismember(&pending->signal, SIGKILL))) {
-		if (!sigismember(mask, SIGKILL))
-			sig = SIGKILL;
-	}
-
-	if (likely(!sig))
+	if (sig) {
+		/* check signal with priority first */
+		if (likely(!sigismember(&pending->signal, sig)) ||
+		    sigismember(mask, sig))
+			sig = 0;
+	} else
 		sig = next_signal(pending, mask);
 	if (sig) {
 		if (current->notifier) {
@@ -561,10 +556,18 @@
  */
 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
 {
-	int signr = __dequeue_signal(&tsk->pending, mask, info);
+	/* SIGKILL must have priority, otherwise it is quite easy
+	 * to create an unkillable process, sending sig < SIGKILL
+	 * to self */
+	int signr = __dequeue_signal(&tsk->pending, mask, info, SIGKILL);
+	if (likely(!signr))
+		signr = __dequeue_signal(&tsk->signal->shared_pending,
+					 mask, info, SIGKILL);
+	if (likely(!signr))
+		signr = __dequeue_signal(&tsk->pending, mask, info, 0);
 	if (!signr)
 		signr = __dequeue_signal(&tsk->signal->shared_pending,
-					 mask, info);
+					 mask, info, 0);
  	if (signr && unlikely(sig_kernel_stop(signr))) {
  		/*
  		 * Set a marker that we have dequeued a stop signal.  Our


Which are preferred?  Or is there other solutions?

---
Atsushi Nemoto

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2005-09-15 16:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-06 16:42 unkillable process due to setup_frame() failure Atsushi Nemoto
2005-09-06 18:41 ` Ralf Baechle
2005-09-07  9:14   ` Maciej W. Rozycki
2005-09-07 13:47     ` Ralf Baechle
2005-09-07 14:44       ` Atsushi Nemoto
2005-09-07 14:56         ` Atsushi Nemoto
2005-09-07 15:24         ` Maciej W. Rozycki
2005-09-07 16:11           ` Ralf Baechle
2005-09-07 16:34             ` Maciej W. Rozycki
2005-09-15 16:17         ` Atsushi Nemoto
2005-09-15 16:44           ` Ralf Baechle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox