about summary refs log tree commit diff
path: root/debug/tst-longjmp_chk.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-05-15 19:28:04 -0700
committerUlrich Drepper <drepper@redhat.com>2009-05-15 19:37:13 -0700
commitb50f8e42ba3010f0141e6a482e0820f658e89b63 (patch)
tree80cef469731d5857499883d45fd3424730f0db7c /debug/tst-longjmp_chk.c
parentf1342e0be8e222dbca077beca94b5937564e8c4b (diff)
downloadglibc-b50f8e42ba3010f0141e6a482e0820f658e89b63.tar.gz
glibc-b50f8e42ba3010f0141e6a482e0820f658e89b63.tar.xz
glibc-b50f8e42ba3010f0141e6a482e0820f658e89b63.zip
Check for valid stack frame in longjmp.
If longjmp restores the stack frame to an address which is beyond
the stack frame at the time of the longjmp call it would install
an uninitialized stack frame.  If compiled with _FORTIFY_SOURCE
defined, longjmp will now bail out in this situation.
Diffstat (limited to 'debug/tst-longjmp_chk.c')
-rw-r--r--debug/tst-longjmp_chk.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/debug/tst-longjmp_chk.c b/debug/tst-longjmp_chk.c
new file mode 100644
index 0000000000..8892974cc7
--- /dev/null
+++ b/debug/tst-longjmp_chk.c
@@ -0,0 +1,86 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static jmp_buf b;
+
+
+static void
+__attribute__ ((noinline))
+f (void)
+{
+  char buf[1000];
+  asm volatile ("" : "=m" (buf));
+
+  if (setjmp (b) != 0)
+    {
+      puts ("second longjmp succeeded");
+      exit (1);
+    }
+}
+
+
+static bool expected_to_fail;
+
+
+static void
+handler (int sig)
+{
+  if (expected_to_fail)
+    _exit (0);
+  else
+    {
+      static const char msg[] = "unexpected longjmp failure\n";
+      TEMP_FAILURE_RETRY (write (STDOUT_FILENO, msg, sizeof (msg) - 1));
+      _exit (1);
+    }
+}
+
+
+int
+main (void)
+{
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGABRT, &sa, NULL);
+
+  /* Avoid all the buffer overflow messages on stderr.  */
+  int fd = open (_PATH_DEVNULL, O_WRONLY);
+  if (fd == -1)
+    close (STDERR_FILENO);
+  else
+    {
+      dup2 (fd, STDERR_FILENO);
+      close (fd);
+    }
+  setenv ("LIBC_FATAL_STDERR_", "1", 1);
+
+
+  expected_to_fail = false;
+
+  if (setjmp (b) == 0)
+    {
+      longjmp (b, 1);
+      /* NOTREACHED */
+      printf ("first longjmp returned\n");
+      return 1;
+    }
+
+
+  expected_to_fail = true;
+
+  f ();
+  longjmp (b, 1);
+
+  puts ("second longjmp returned");
+  return 1;
+}