[4.1] 5efbf4c use an alternative stack for SIGSEGV and test for stack overflow
PÃ¥l Hermunn Johansen
hermunn at varnish-software.com
Tue Sep 19 14:18:05 UTC 2017
commit 5efbf4c4145ac17d5ba692c2db88f6b29535b6f5
Author: Nils Goroll <nils.goroll at uplex.de>
Date: Wed Aug 23 08:08:59 2017 +0200
use an alternative stack for SIGSEGV and test for stack overflow
Previously, we could run out of stack handling stack overflows, leaving
users with unspecific SIGSEGV crashes and no panic message.
By providing a single alternative stack exclusively for SIGSEGV handling
where sigaltstack() is available, we increase chances for our signal handler
to finish successfully.
In particular, this will make it easier to diagnose stack overflows by
comparing the failing address with the stack info from the panic output.
This could be further improved by giving advise to increase thread_pool_stack
if si_addr is near the stack boundaries.
c00057.vtc now triggers a stack overflow instead of raising a SIGSEGV.
Merges #2396
diff --git a/bin/varnishd/mgt/mgt_child.c b/bin/varnishd/mgt/mgt_child.c
index 80bb861..64c73fe 100644
--- a/bin/varnishd/mgt/mgt_child.c
+++ b/bin/varnishd/mgt/mgt_child.c
@@ -392,9 +392,23 @@ mgt_launch_child(struct cli *cli)
memset(&sa, 0, sizeof sa);
sa.sa_sigaction = child_signal_handler;
sa.sa_flags = SA_SIGINFO;
- (void)sigaction(SIGSEGV, &sa, NULL);
(void)sigaction(SIGBUS, &sa, NULL);
(void)sigaction(SIGABRT, &sa, NULL);
+
+#ifdef HAVE_SIGALTSTACK
+ stack_t ss;
+ size_t sz = SIGSTKSZ + 4096;
+ if (sz < mgt_param.wthread_stacksize)
+ sz = mgt_param.wthread_stacksize;
+ ss.ss_sp = malloc(sz);
+ AN(ss.ss_sp);
+ ss.ss_size = sz;
+ ss.ss_flags = 0;
+ AZ(sigaltstack(&ss, NULL));
+ sa.sa_flags |= SA_ONSTACK;
+#endif
+ (void)sigaction(SIGSEGV, &sa, NULL);
+
}
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGTERM, SIG_DFL);
diff --git a/bin/varnishtest/tests/c00057.vtc b/bin/varnishtest/tests/c00057.vtc
index ba0ec1e..d8008af 100644
--- a/bin/varnishtest/tests/c00057.vtc
+++ b/bin/varnishtest/tests/c00057.vtc
@@ -5,13 +5,32 @@ server s1 {
txresp
} -start
-varnish v1 -cliok "param.set vcc_allow_inline_c true"
-varnish v1 -vcl+backend {
+varnish v1 \
+ -arg "-p vcc_allow_inline_c=true" \
+ -arg "-p thread_pool_stack=48k" \
+ -vcl+backend {
C{
#include <signal.h>
#include <unistd.h>
+#include <stdio.h>
+
+static void _accessor(volatile char *p) {
+ p[0] = 'V'; p[1] = '\0';
+ fprintf(stderr, "%p %s\n", p, p);
+}
+void (*accessor)(volatile char *p) = _accessor;
+
}C
- sub vcl_recv { C{ raise(SIGSEGV); sleep(2); }C }
+ sub vcl_recv { C{
+ int i;
+ volatile char overflow[48*1024];
+
+ /* for downwards stack, take care to hit a single guard page */
+ for (i = 47*1024; i >= 0; i -= 1024)
+ accessor(overflow + i);
+ /* NOTREACHED */
+ sleep(2);
+ }C }
} -start
client c1 {
diff --git a/configure.ac b/configure.ac
index f15d1b5..64c28d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,6 +258,7 @@ AC_CHECK_FUNCS([setppriv])
AC_CHECK_FUNCS([fallocate])
AC_CHECK_FUNCS([closefrom])
AC_CHECK_FUNCS([vsyslog])
+AC_CHECK_FUNCS([sigaltstack])
save_LIBS="${LIBS}"
LIBS="${PTHREAD_LIBS}"
More information about the varnish-commit
mailing list