(VG_(do__NR_sigaction)): Don't allow setting of
handlers for SIGKILL or SIGSTOP.  This fixes
valgrind: vg_signals.c:723 (vgPlain_do__NR_sigaction):
Assertion `our_old_handler == ((void *)0)' failed.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@40 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/ChangeLog b/ChangeLog
index d51cc8d..e3265b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2002-03-29  Julian Seward  <sewardj@localhost.localdomain>
+
+	* vg_signals.c (VG_(do__NR_sigaction)): Don't allow setting of
+	handlers for SIGKILL or SIGSTOP.  This fixes
+	valgrind: vg_signals.c:723 (vgPlain_do__NR_sigaction): 
+	Assertion `our_old_handler == ((void *)0)' failed.
+	
 2002-03-29  Alexandre Duret-Lutz  <duret_g@epita.fr>
 
 	* vg_syscall_mem.c: wrapper for ioctl TIOCGPGRP.
diff --git a/coregrind/vg_kerneliface.h b/coregrind/vg_kerneliface.h
index 480188c..15ce80d 100644
--- a/coregrind/vg_kerneliface.h
+++ b/coregrind/vg_kerneliface.h
@@ -132,6 +132,11 @@
 #define VKI_MAP_PRIVATE    0x02            /* Changes are private.  */
 
 
+/* Copied from /usr/src/linux-2.4.9-13/include/asm/errno.h */
+
+#define VKI_EINVAL          22      /* Invalid argument */
+
+
 /* Gawd ... hack ... */
 
 typedef struct vki__user_cap_header_struct {
diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c
index ed7ef67..2372fc4 100644
--- a/coregrind/vg_signals.c
+++ b/coregrind/vg_signals.c
@@ -688,7 +688,17 @@
          (UInt)(new_action ? new_action->ksa_flags : 0) );
    /* VG_(ppSigProcMask)(); */
 
-   if (param1 < 1 || param1 >= VKI_KNSIG) goto bad;
+   /* Rule out various error conditions.  The aim is to ensure that if
+      the call is passed to the kernel it will definitely succeed. */
+
+   /* Reject out-of-range signal numbers. */
+   if (param1 < 1 || param1 >= VKI_KNSIG) goto bad_signo;
+
+   /* Reject attempts to set a handler (or set ignore) for SIGKILL. */
+   if ( (param1 == VKI_SIGKILL || param1 == VKI_SIGSTOP)
+       && new_action
+       && new_action->ksa_handler != VKI_SIG_DFL)
+      goto bad_sigkill;
 
    our_old_handler = VG_(sighandler)[param1];
    /* VG_(printf)("old handler = 0x%x\n", our_old_handler); */
@@ -714,6 +724,7 @@
 
    KERNEL_DO_SYSCALL(res);
    /* VG_(printf)("RES = %d\n", res); */
+
    /* If the client asks for the old handler, maintain our fiction
       by stuffing in the handler it thought it asked for ... */
    if (old_action) {
@@ -742,11 +753,18 @@
    VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)0;
    return;
 
-  bad:
+  bad_signo:
    VG_(message)(Vg_UserMsg,
                 "Warning: bad signal number %d in __NR_sigaction.", 
                 param1);
-   VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-1);
+   VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
+   return;
+
+  bad_sigkill:
+   VG_(message)(Vg_UserMsg,
+                "Warning: attempt to set SIGKILL handler in __NR_sigaction.", 
+                param1);
+   VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
    return;
 }
 
diff --git a/tests/sigkill.c b/tests/sigkill.c
new file mode 100644
index 0000000..c4c7b77
--- /dev/null
+++ b/tests/sigkill.c
@@ -0,0 +1,35 @@
+
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void
+abend (int sig)
+{
+  printf ("Abended on signal %d\n", sig);
+  exit (2);
+}
+
+int
+main (void)
+{
+  struct sigaction  sa;
+
+  int i;
+  for (i = 1; i <= 64; i++) {
+     sa.sa_flags   = 0;
+     sigemptyset( &sa.sa_mask );
+     sa.sa_handler = abend;
+     errno = 0;
+     fprintf(stderr, "setting signal %d: ", i);
+     sigaction (i /*SIGKILL*/, &sa, NULL);
+     perror ("");
+     errno = 0;
+     fprintf(stderr, "getting signal %d: ", i);
+     sigaction (i /*SIGKILL*/, NULL, &sa);
+     perror ("");
+     fprintf(stderr, "\n");
+  }
+  return 0;
+}
diff --git a/tests/signal1.c b/tests/signal1.c
index 68a5cad..a35975c 100644
--- a/tests/signal1.c
+++ b/tests/signal1.c
@@ -11,7 +11,7 @@
    printf ( "signal returns\n" );
 }
 
-void main ( void )
+int main ( void )
 {
    spin = 1;
    printf ( "installing sig handler\n" );
@@ -19,4 +19,5 @@
    printf ( "entering busy wait\n" );
    while (spin) { };
    printf ( "exited\n" );
+   return 0;
 }
diff --git a/tests/signal2.c b/tests/signal2.c
index 6892d33..5797537 100644
--- a/tests/signal2.c
+++ b/tests/signal2.c
@@ -8,11 +8,12 @@
    exit(1);
 }
 
-void main ( void )
+int main ( void )
 {
    printf ( "installing sig handler\n" );
    signal(SIGSEGV, sig_hdlr);
    printf ( "doing bad thing\n" );
    * (int*) 0 = 0;
    printf ( "exited normally ?!\n" );
+   return 0;
 }
diff --git a/tests/signal3.c b/tests/signal3.c
index e2b4d17..6c1cc68 100644
--- a/tests/signal3.c
+++ b/tests/signal3.c
@@ -26,8 +26,9 @@
    assert(ret == 0);
 }
 
-void main ( void )
+int main ( void )
 {
    hdp_init_profiling();
    while (1) {}
+   return 0;
 }
diff --git a/vg_kerneliface.h b/vg_kerneliface.h
index 480188c..15ce80d 100644
--- a/vg_kerneliface.h
+++ b/vg_kerneliface.h
@@ -132,6 +132,11 @@
 #define VKI_MAP_PRIVATE    0x02            /* Changes are private.  */
 
 
+/* Copied from /usr/src/linux-2.4.9-13/include/asm/errno.h */
+
+#define VKI_EINVAL          22      /* Invalid argument */
+
+
 /* Gawd ... hack ... */
 
 typedef struct vki__user_cap_header_struct {
diff --git a/vg_signals.c b/vg_signals.c
index ed7ef67..2372fc4 100644
--- a/vg_signals.c
+++ b/vg_signals.c
@@ -688,7 +688,17 @@
          (UInt)(new_action ? new_action->ksa_flags : 0) );
    /* VG_(ppSigProcMask)(); */
 
-   if (param1 < 1 || param1 >= VKI_KNSIG) goto bad;
+   /* Rule out various error conditions.  The aim is to ensure that if
+      the call is passed to the kernel it will definitely succeed. */
+
+   /* Reject out-of-range signal numbers. */
+   if (param1 < 1 || param1 >= VKI_KNSIG) goto bad_signo;
+
+   /* Reject attempts to set a handler (or set ignore) for SIGKILL. */
+   if ( (param1 == VKI_SIGKILL || param1 == VKI_SIGSTOP)
+       && new_action
+       && new_action->ksa_handler != VKI_SIG_DFL)
+      goto bad_sigkill;
 
    our_old_handler = VG_(sighandler)[param1];
    /* VG_(printf)("old handler = 0x%x\n", our_old_handler); */
@@ -714,6 +724,7 @@
 
    KERNEL_DO_SYSCALL(res);
    /* VG_(printf)("RES = %d\n", res); */
+
    /* If the client asks for the old handler, maintain our fiction
       by stuffing in the handler it thought it asked for ... */
    if (old_action) {
@@ -742,11 +753,18 @@
    VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)0;
    return;
 
-  bad:
+  bad_signo:
    VG_(message)(Vg_UserMsg,
                 "Warning: bad signal number %d in __NR_sigaction.", 
                 param1);
-   VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-1);
+   VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
+   return;
+
+  bad_sigkill:
+   VG_(message)(Vg_UserMsg,
+                "Warning: attempt to set SIGKILL handler in __NR_sigaction.", 
+                param1);
+   VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
    return;
 }