[02/12] Make __stack_chk_fail() not use other glibc facilities.

Message ID 1455963826-21885-3-git-send-email-nix@esperi.org.uk
State New, archived
Headers

Commit Message

Nix Feb. 20, 2016, 10:23 a.m. UTC
  From: Nick Alcock <nick.alcock@oracle.com>

After this patch series is complete, glibc exports a __stack_chk_fail()
implementation for use by all other programs, including other parts of
glibc.

Unfortunately this means that we have to rip out the existing
implementation (that simply calls __fortify_fail()) and replace it with
another which does not call into glibc: otherwise, you get this build
failure, when libdl ends up pulling in sizeable pieces of glibc at the
early static link stage, then understandably clashing with libc_pic later:

gcc   -nostdlib -nostartfiles -r -o /home/oranix/oracle/src/foo/libc_pic.os \
 -Wl,-d -Wl,--whole-archive /home/oranix/oracle/src/foo/libc_pic.a -o /home/oranix/oracle/src/foo/libc_pic.os
/home/oranix/oracle/src/foo/libc_pic.a(init-first.os):(.data+0x0): multiple definition of `__libc_multiple_libcs'
/home/oranix/oracle/src/foo/elf/dl-allobjs.os:(.bss+0xf8): first defined here
/home/oranix/oracle/src/foo/libc_pic.a(libc_fatal.os): In function `__GI___libc_fatal':
/home/oranix/oracle/src/glibc/libio/../sysdeps/posix/libc_fatal.c:182: multiple definition of `__GI___libc_fatal'
/home/oranix/oracle/src/foo/elf/dl-allobjs.os:/home/oranix/oracle/src/glibc/elf/dl-minimal.c:199: first defined here
/home/oranix/oracle/src/foo/libc_pic.a(libc_fatal.os): In function `__GI___libc_fatal':
/home/oranix/oracle/src/glibc/libio/../sysdeps/posix/libc_fatal.c:182: multiple definition of `__libc_fatal'
/home/oranix/oracle/src/foo/elf/dl-allobjs.os:/home/oranix/oracle/src/glibc/elf/dl-minimal.c:199: first defined here
/home/oranix/oracle/src/foo/libc_pic.a(dl-addr.os): In function `_dl_addr_inside_object':
/home/oranix/oracle/src/glibc/elf/dl-addr.c:151: multiple definition of `_dl_addr_inside_object'
/home/oranix/oracle/src/foo/elf/dl-allobjs.os:/home/oranix/oracle/src/glibc/elf/dl-open.c:744: first defined here

Back in 2008 when I wrote this I replaced it with the then-current
gentoo replacement stack-smasher: it had nice extra features like
automatically dumping core on a stack smash and logging via syslog, but
most importantly it did not rely on the rest of glibc.

I am completely happy with this piece being thrown out, as long as we
find some other fix for this double-pull-in bug! (It might be as easy as
changing the way dl-allobjs.os is linked, but I honestly don't know
how).  But in general this approach seems safer to me anyway: after
we've been actively attacked, we probably shouldn't be relying on the
complexities of libio with all its vtables and function pointers and the
like: an attacker could easily have smashed those, too.
---
 debug/Makefile         |   1 +
 debug/stack_chk_fail.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 288 insertions(+), 6 deletions(-)
  

Comments

Nix Feb. 20, 2016, 12:06 p.m. UTC | #1
On 20 Feb 2016, nix@esperi.org.uk stated:

> From: Nick Alcock <nick.alcock@oracle.com>
>
> After this patch series is complete, glibc exports a __stack_chk_fail()
> implementation for use by all other programs, including other parts of
> glibc.

Magnus Granberg has now pointed me at a much more recent version of this
change, which replaces __chk_fail() to the same end and reimplement
__stack_chk_fail() in terms of it. I'll incorporate that in the next
version. (The only concern is that this has received changes from lots
of people. Maybe I'll have to reimplement it entirely to avoid
copyright-assignment concerns. What a drag...)
  
Mike Frysinger Feb. 20, 2016, 5:19 p.m. UTC | #2
On 20 Feb 2016 12:06, Nix wrote:
> On 20 Feb 2016, nix@esperi.org.uk stated:
> > From: Nick Alcock <nick.alcock@oracle.com>
> >
> > After this patch series is complete, glibc exports a __stack_chk_fail()
> > implementation for use by all other programs, including other parts of
> > glibc.
> 
> Magnus Granberg has now pointed me at a much more recent version of this
> change, which replaces __chk_fail() to the same end and reimplement
> __stack_chk_fail() in terms of it. I'll incorporate that in the next
> version. (The only concern is that this has received changes from lots
> of people. Maybe I'll have to reimplement it entirely to avoid
> copyright-assignment concerns. What a drag...)

yes, you will.  you (and Oracle) have CLA papers already signed for glibc
right ?  if not, there isn't much point in following up on this series if
you don't plan to.

it needs a rewrite anyways to not use INLINE_SYSCALL but INTERNAL_SYSCALL. 
i had done this locally, stashed it, but then lost it when cleaning up the
repo later :(.

all that said, i don't think we want to import the Gentoo one anyways.
it changes a lot of behavior that we shouldn't conflate here -- the
crash/syslog handling is contentious.  maybe something like (untested):

void
__attribute__ ((noreturn)) internal_function
__fortify_fail (const char *msg)
{
#ifdef __SSP__
  int fd = -1;

  const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
  if (on_2 == NULL || *on_2 == '\0')
    fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1)
    fd = STDERR_FILENO;

#define IOVS(s) { s, strlen (s) }
  struct iovec iov[5] = {
    IOVS ("*** "),
    IOVS (msg),
    IOVS (" ***: "),
    IOVS (__libc_argv[0] ?: "<unknown>"),
    IOVS (" terminated\n"),
  };
  TEMP_FAILURE_RETRY (__writev (fd, iov, 5));

  abort ();
#else
  /* The loop is added only to keep gcc happy.  */
  while (1)
    __libc_message (2, "*** %s ***: %s terminated\n",
            msg, __libc_argv[0] ?: "<unknown>");
#endif
}
-mike
  
Joseph Myers Feb. 20, 2016, 5:36 p.m. UTC | #3
You can't use defined(__NR_socket) && defined(__NR_connect) as a condition 
for whether to use socketcall, because of architectures that added the 
separate syscalls more recently than socketcall support.  Instead you need 
to use the kernel-features.h macros: if __ASSUME_SOCKETCALL is not 
defined, or the macros such as __ASSUME_SOCKET_SYSCALL and 
__ASSUME_CONNECT_SYSCALL for the individual syscalls are defined, then use 
individual syscalls, otherwise use socketcall.

(Apart from this, we may want to look at bug 12189 again and figure out 
how much of this code is desirable anyway.)
  
Nix Feb. 21, 2016, 12:44 p.m. UTC | #4
On 20 Feb 2016, Mike Frysinger outgrape:

> On 20 Feb 2016 12:06, Nix wrote:
>> Magnus Granberg has now pointed me at a much more recent version of this
>> change, which replaces __chk_fail() to the same end and reimplement
>> __stack_chk_fail() in terms of it. I'll incorporate that in the next
>> version. (The only concern is that this has received changes from lots
>> of people. Maybe I'll have to reimplement it entirely to avoid
>> copyright-assignment concerns. What a drag...)
>
> yes, you will.  you (and Oracle) have CLA papers already signed for glibc
> right ?  if not, there isn't much point in following up on this series if
> you don't plan to.

Oracle has a disclaimer signed, of couse, but I'll need to start the
copyright papers dance for myself (I have signed papers for other GNU
projects, but not glibc yet).

If people were going to laugh this out of the barn there seemed to be no
point, but if people are receptive, I'm happy to sign.

(I'm in the UK, which unfortunately means, I think, that I'm still
condemned to posting off papers made of real paper.)

> it needs a rewrite anyways to not use INLINE_SYSCALL but INTERNAL_SYSCALL. 
> i had done this locally, stashed it, but then lost it when cleaning up the
> repo later :(.

Frankly, I was rather hoping that someone could figure out what I
hadn't yet -- the right way to prevent the intermediate link failing
when the original __stack_chk_fail() is used.

> all that said, i don't think we want to import the Gentoo one anyways.
> it changes a lot of behavior that we shouldn't conflate here -- the
> crash/syslog handling is contentious.  maybe something like (untested):
>
> void
> __attribute__ ((noreturn)) internal_function
> __fortify_fail (const char *msg)
> {
> #ifdef __SSP__
>   int fd = -1;
>
>   const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
>   if (on_2 == NULL || *on_2 == '\0')
>     fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);

I fear this use of open_not_cancel_2() may bring back the same behaviour
we're trying to avoid :(
  
Mike Frysinger Feb. 22, 2016, 1:20 a.m. UTC | #5
On 21 Feb 2016 12:44, Nix wrote:
> On 20 Feb 2016, Mike Frysinger outgrape:
> > On 20 Feb 2016 12:06, Nix wrote:
> >> Magnus Granberg has now pointed me at a much more recent version of this
> >> change, which replaces __chk_fail() to the same end and reimplement
> >> __stack_chk_fail() in terms of it. I'll incorporate that in the next
> >> version. (The only concern is that this has received changes from lots
> >> of people. Maybe I'll have to reimplement it entirely to avoid
> >> copyright-assignment concerns. What a drag...)
> >
> > yes, you will.  you (and Oracle) have CLA papers already signed for glibc
> > right ?  if not, there isn't much point in following up on this series if
> > you don't plan to.
> 
> Oracle has a disclaimer signed, of couse, but I'll need to start the
> copyright papers dance for myself (I have signed papers for other GNU
> projects, but not glibc yet).

a disclaimer is not the same thing as a CLA.  what exactly are you
referring to here ?

> > it needs a rewrite anyways to not use INLINE_SYSCALL but INTERNAL_SYSCALL. 
> > i had done this locally, stashed it, but then lost it when cleaning up the
> > repo later :(.
> 
> Frankly, I was rather hoping that someone could figure out what I
> hadn't yet -- the right way to prevent the intermediate link failing
> when the original __stack_chk_fail() is used.

i haven't looked closely at the loop.  i assumed the fail relied on more
printf machinery.

> > all that said, i don't think we want to import the Gentoo one anyways.
> > it changes a lot of behavior that we shouldn't conflate here -- the
> > crash/syslog handling is contentious.  maybe something like (untested):
> >
> > void
> > __attribute__ ((noreturn)) internal_function
> > __fortify_fail (const char *msg)
> > {
> > #ifdef __SSP__
> >   int fd = -1;
> >
> >   const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
> >   if (on_2 == NULL || *on_2 == '\0')
> >     fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
> 
> I fear this use of open_not_cancel_2() may bring back the same behaviour
> we're trying to avoid :(

if this triggers the loop, then you'll need INTERNAL_SYSCALL.  if that
fixes the loop, then we can probably not make it depend on __SSP__ at
all.
-mike
  
Nix Feb. 22, 2016, 12:32 p.m. UTC | #6
On 22 Feb 2016, Mike Frysinger told this:

> On 21 Feb 2016 12:44, Nix wrote:
>> On 20 Feb 2016, Mike Frysinger outgrape:
>> > On 20 Feb 2016 12:06, Nix wrote:
>> >> Magnus Granberg has now pointed me at a much more recent version of this
>> >> change, which replaces __chk_fail() to the same end and reimplement
>> >> __stack_chk_fail() in terms of it. I'll incorporate that in the next
>> >> version. (The only concern is that this has received changes from lots
>> >> of people. Maybe I'll have to reimplement it entirely to avoid
>> >> copyright-assignment concerns. What a drag...)
>> >
>> > yes, you will.  you (and Oracle) have CLA papers already signed for glibc
>> > right ?  if not, there isn't much point in following up on this series if
>> > you don't plan to.
>> 
>> Oracle has a disclaimer signed, of couse, but I'll need to start the
>> copyright papers dance for myself (I have signed papers for other GNU
>> projects, but not glibc yet).
>
> a disclaimer is not the same thing as a CLA.  what exactly are you
> referring to here ?

Well, when I had to do this last (years ago), there was an employer's
disclaimer of rights and there were assignment-and-grantback papers for
the individual to sign for the project in question. I still have the
latter to do for glibc.

>> > it needs a rewrite anyways to not use INLINE_SYSCALL but INTERNAL_SYSCALL. 
>> > i had done this locally, stashed it, but then lost it when cleaning up the
>> > repo later :(.
>> 
>> Frankly, I was rather hoping that someone could figure out what I
>> hadn't yet -- the right way to prevent the intermediate link failing
>> when the original __stack_chk_fail() is used.
>
> i haven't looked closely at the loop.  i assumed the fail relied on more
> printf machinery.

Yeah, but the question is just why that incremental link is trying to
pull the stuff in twice rather than depending on the canonical copy in
libc -- presumably because everything is still statically linked at that
point. If that gets solved, the only reason for this patch being in this
series goes away.

>> > all that said, i don't think we want to import the Gentoo one anyways.
>> > it changes a lot of behavior that we shouldn't conflate here -- the
>> > crash/syslog handling is contentious.  maybe something like (untested):
>> >
>> > void
>> > __attribute__ ((noreturn)) internal_function
>> > __fortify_fail (const char *msg)
>> > {
>> > #ifdef __SSP__
>> >   int fd = -1;
>> >
>> >   const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
>> >   if (on_2 == NULL || *on_2 == '\0')
>> >     fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
>> 
>> I fear this use of open_not_cancel_2() may bring back the same behaviour
>> we're trying to avoid :(
>
> if this triggers the loop, then you'll need INTERNAL_SYSCALL.  if that
> fixes the loop, then we can probably not make it depend on __SSP__ at
> all.

True enough. I'll give it a try, and thanks for the help!
  

Patch

diff --git a/debug/Makefile b/debug/Makefile
index 6b5f31e..535f10a 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -53,6 +53,7 @@  routines  = backtrace backtracesyms backtracesymsfd noophooks \
 static-only-routines := warning-nop stack_chk_fail_local
 
 CFLAGS-backtrace.c = -fno-omit-frame-pointer
+CFLAGS-stack_chk_fail.c = -DSSP_SMASH_DUMPS_CORE
 CFLAGS-sprintf_chk.c = $(libio-mtsafe)
 CFLAGS-snprintf_chk.c = $(libio-mtsafe)
 CFLAGS-vsprintf_chk.c = $(libio-mtsafe)
diff --git a/debug/stack_chk_fail.c b/debug/stack_chk_fail.c
index 4d0796f..c6ce7dc 100644
--- a/debug/stack_chk_fail.c
+++ b/debug/stack_chk_fail.c
@@ -15,15 +15,296 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stdio.h>
+/* Copyright (C) 2006-2007 Gentoo Foundation Inc.
+ * License terms as above.
+ *
+ * Hardened Gentoo SSP handler
+ *
+ * An SSP failure handler that does not use functions from the rest of
+ * glibc; it uses the INTERNAL_SYSCALL methods directly.  This ensures
+ * no possibility of recursion into the handler.
+ *
+ * Direct all bug reports to http://bugs.gentoo.org/
+ *
+ * Re-written from the glibc-2.3 Hardened Gentoo SSP handler
+ * by Kevin F. Quinn - <kevquinn[@]gentoo.org>
+ *
+ * The following people contributed to the glibc-2.3 Hardened
+ * Gentoo SSP handler, from which this implementation draws much:
+ *
+ * Ned Ludd - <solar[@]gentoo.org>
+ * Alexander Gabert - <pappy[@]gentoo.org>
+ * The PaX Team - <pageexec[@]freemail.hu>
+ * Peter S. Mazinger - <ps.m[@]gmx.net>
+ * Yoann Vandoorselaere - <yoann[@]prelude-ids.org>
+ * Robert Connolly - <robert[@]linuxfromscratch.org>
+ * Cory Visi <cory[@]visi.name>
+ * Mike Frysinger <vapier[@]gentoo.org>
+ */
+
+#include <errno.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/types.h>
+
+#include <sysdep-cancel.h>
+#include <sys/syscall.h>
+
+#include <kernel-features.h>
+
+#include <alloca.h>
+/* from sysdeps */
+#include <socketcall.h>
+/* for the stuff in bits/socket.h */
+#include <sys/socket.h>
+#include <sys/un.h>
+
+
+/* Sanity check on SYSCALL macro names - force compilation
+ * failure if the names used here do not exist
+ */
+#if !defined __NR_socketcall && !defined __NR_socket
+# error Cannot do syscall socket or socketcall
+#endif
+#if !defined __NR_socketcall && !defined __NR_connect
+# error Cannot do syscall connect or socketcall
+#endif
+#ifndef __NR_write
+# error Cannot do syscall write
+#endif
+#ifndef __NR_close
+# error Cannot do syscall close
+#endif
+#ifndef __NR_getpid
+# error Cannot do syscall getpid
+#endif
+#ifndef __NR_kill
+# error Cannot do syscall kill
+#endif
+#ifndef __NR_exit
+# error Cannot do syscall exit
+#endif
+#ifdef SSP_SMASH_DUMPS_CORE
+# define ENABLE_SSP_SMASH_DUMPS_CORE 1
+# if !defined _KERNEL_NSIG && !defined _NSIG
+#  error No _NSIG or _KERNEL_NSIG for rt_sigaction
+# endif
+# if !defined __NR_sigaction && !defined __NR_rt_sigaction
+#  error Cannot do syscall sigaction or rt_sigaction
+# endif
+/* Although rt_sigaction expects sizeof(sigset_t) - it expects the size
+ * of the _kernel_ sigset_t which is not the same as the user sigset_t.
+ * Most arches have this as _NSIG bits - mips has _KERNEL_NSIG bits for
+ * some reason.
+ */
+# ifdef _KERNEL_NSIG
+#  define _SSP_NSIG _KERNEL_NSIG
+# else
+#  define _SSP_NSIG _NSIG
+# endif
+#else
+# define _SSP_NSIG 0
+# define ENABLE_SSP_SMASH_DUMPS_CORE 0
+#endif
+
+/* Define DO_SIGACTION - default to newer rt signal interface but
+ * fallback to old as needed.
+ */
+#ifdef __NR_rt_sigaction
+# define DO_SIGACTION(signum, act, oldact) \
+	INLINE_SYSCALL(rt_sigaction, 4, signum, act, oldact, _SSP_NSIG/8)
+#else
+# define DO_SIGACTION(signum, act, oldact) \
+	INLINE_SYSCALL(sigaction, 3, signum, act, oldact)
+#endif
+
+/* Define DO_SOCKET/DO_CONNECT functions to deal with socketcall vs socket/connect */
+#if defined(__NR_socket) && defined(__NR_connect)
+# define USE_OLD_SOCKETCALL 0
+#else
+# define USE_OLD_SOCKETCALL 1
+#endif
+/* stub out the __NR_'s so we can let gcc optimize away dead code */
+#ifndef __NR_socketcall
+# define __NR_socketcall 0
+#endif
+#ifndef __NR_socket
+# define __NR_socket 0
+#endif
+#ifndef __NR_connect
+# define __NR_connect 0
+#endif
+#define DO_SOCKET(result, domain, type, protocol) \
+	do { \
+		if (USE_OLD_SOCKETCALL) { \
+			socketargs[0] = domain; \
+			socketargs[1] = type; \
+			socketargs[2] = protocol; \
+			socketargs[3] = 0; \
+			result = INLINE_SYSCALL(socketcall, 2, SOCKOP_socket, socketargs); \
+		} else \
+			result = INLINE_SYSCALL(socket, 3, domain, type, protocol); \
+	} while (0)
+#define DO_CONNECT(result, sockfd, serv_addr, addrlen) \
+	do { \
+		if (USE_OLD_SOCKETCALL) { \
+			socketargs[0] = sockfd; \
+			socketargs[1] = (unsigned long int)serv_addr; \
+			socketargs[2] = addrlen; \
+			socketargs[3] = 0; \
+			result = INLINE_SYSCALL(socketcall, 2, SOCKOP_connect, socketargs); \
+		} else \
+			result = INLINE_SYSCALL(connect, 3, sockfd, serv_addr, addrlen); \
+	} while (0)
+
+#ifndef _PATH_LOG
+# define _PATH_LOG "/dev/log"
+#endif
+
+static const char path_log[] = _PATH_LOG;
+
+/* For building glibc with SSP switched on, define __progname to a
+ * constant if building for the run-time loader, to avoid pulling
+ * in more of libc.so into ld.so
+ */
+#ifdef IS_IN_rtld
+static char *__progname = "<rtld>";
+#else
+extern char *__progname;
+#endif
+
 
+/* Common handler code, used by stack_chk_fail and __stack_smash_handler
+ * Inlined to ensure no self-references to the handler within itself.
+ * Data static to avoid putting more than necessary on the stack,
+ * to aid core debugging.
+ * The copy in rtld must be hidden to ensure that it gets no relocations
+ * and thus does not crash if called during libc startup.
+ */
+__attribute__ ((__noreturn__ , __always_inline__))
+#ifdef IS_IN_rtld
+attribute_hidden
+#endif
+static inline void
+__hardened_gentoo_stack_chk_fail(char func[], int damaged)
+{
+#define MESSAGE_BUFSIZ 256
+	static pid_t pid;
+	static int plen, i;
+	static char message[MESSAGE_BUFSIZ];
+	static const char msg_ssa[] = ": stack smashing attack";
+	static const char msg_inf[] = " in function ";
+	static const char msg_ssd[] = "*** stack smashing detected ***: ";
+	static const char msg_terminated[] = " - terminated\n";
+	static const char msg_unknown[] = "<unknown>";
+	static int log_socket, connect_result;
+	static struct sockaddr_un sock;
+	static unsigned long int socketargs[4];
+
+	/* Build socket address
+	 */
+	sock.sun_family = AF_UNIX;
+	i = 0;
+	while ((path_log[i] != '\0') && (i<(sizeof(sock.sun_path)-1))) {
+		sock.sun_path[i] = path_log[i];
+		i++;
+	}
+	sock.sun_path[i] = '\0';
+
+	/* Try SOCK_DGRAM connection to syslog */
+	connect_result = -1;
+	DO_SOCKET(log_socket, AF_UNIX, SOCK_DGRAM, 0);
+	if (log_socket != -1)
+		DO_CONNECT(connect_result, log_socket, &sock, sizeof(sock));
+	if (connect_result == -1) {
+		if (log_socket != -1)
+			INLINE_SYSCALL(close, 1, log_socket);
+		/* Try SOCK_STREAM connection to syslog */
+		DO_SOCKET(log_socket, AF_UNIX, SOCK_STREAM, 0);
+		if (log_socket != -1)
+			DO_CONNECT(connect_result, log_socket, &sock, sizeof(sock));
+	}
+
+	/* Build message.  Messages are generated both in the old style and new style,
+	 * so that log watchers that are configured for the old-style message continue
+	 * to work.
+	 */
+#define strconcat(str) \
+		{i=0; while ((str[i] != '\0') && ((i+plen)<(MESSAGE_BUFSIZ-1))) \
+		{\
+			message[plen+i]=str[i];\
+			i++;\
+		}\
+		plen+=i;}
+
+	/* R.Henderson post-gcc-4 style message */
+	plen = 0;
+	strconcat(msg_ssd);
+	if (__progname != (char *)0)
+		strconcat(__progname)
+	else
+		strconcat(msg_unknown);
+	strconcat(msg_terminated);
+
+	/* Write out error message to STDERR, to syslog if open */
+	INLINE_SYSCALL(write, 3, STDERR_FILENO, message, plen);
+	if (connect_result != -1)
+		INLINE_SYSCALL(write, 3, log_socket, message, plen);
+
+	/* Dr. Etoh pre-gcc-4 style message */
+	plen = 0;
+	if (__progname != (char *)0)
+		strconcat(__progname)
+	else
+		strconcat(msg_unknown);
+	strconcat(msg_ssa);
+	strconcat(msg_inf);
+	if (func != NULL)
+		strconcat(func)
+	else
+		strconcat(msg_unknown);
+	strconcat(msg_terminated);
+	/* Write out error message to STDERR, to syslog if open */
+	INLINE_SYSCALL(write, 3, STDERR_FILENO, message, plen);
+	if (connect_result != -1)
+		INLINE_SYSCALL(write, 3, log_socket, message, plen);
 
-extern char **__libc_argv attribute_hidden;
+	/* Write out error message to STDERR, to syslog if open */
+	INLINE_SYSCALL(write, 3, STDERR_FILENO, message, plen);
+	if (connect_result != -1)
+		INLINE_SYSCALL(write, 3, log_socket, message, plen);
+
+	if (log_socket != -1)
+		INLINE_SYSCALL(close, 1, log_socket);
+
+	/* Suicide */
+	pid = INLINE_SYSCALL(getpid, 0);
+
+	if (ENABLE_SSP_SMASH_DUMPS_CORE) {
+		static struct sigaction default_abort_act;
+		/* Remove any user-supplied handler for SIGABRT, before using it */
+		default_abort_act.sa_handler = SIG_DFL;
+		default_abort_act.sa_sigaction = NULL;
+		__sigfillset(&default_abort_act.sa_mask);
+		default_abort_act.sa_flags = 0;
+		if (DO_SIGACTION(SIGABRT, &default_abort_act, NULL) == 0)
+			INLINE_SYSCALL(kill, 2, pid, SIGABRT);
+	}
+
+	/* Note; actions cannot be added to SIGKILL */
+	INLINE_SYSCALL(kill, 2, pid, SIGKILL);
+
+	/* In case the kill didn't work, exit anyway
+	 * The loop prevents gcc thinking this routine returns
+	 */
+	while (1)
+		INLINE_SYSCALL(exit, 0);
+}
 
-void
-__attribute__ ((noreturn))
-__stack_chk_fail (void)
+__attribute__ ((__noreturn__))
+void __stack_chk_fail(void)
 {
-  __fortify_fail ("stack smashing detected");
+	__hardened_gentoo_stack_chk_fail(NULL, 0);
 }