--- debug/stack_chk_fail.c.ORIG 2006-09-28 09:43:35.000000000 +0200 +++ debug/stack_chk_fail.c 2006-09-28 09:44:42.000000000 +0200 @@ -16,22 +16,267 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#if defined __SSP__ || defined __SSP_ALL__ + +/* An SSP failure handler that: + * 1) does not use any function calls - which would + * otherwise lead to nested calls to stack_chk_fail() + * 2) uses no functions from the rest of libc, which + * can lead to build problems pulling in copies of + * swathes of libc into the other libraries. + * This handler would not be valid on architectures for + * which a pointer is not either a 32-bit or 64-bit + * integer. It's definitely ok for i386, x86_64, and ppc. + */ + +#if defined __linux__ + +/* When including headers, define out the function names used + * via syscalls, since the syscall macros require that the functions + * they declare have the predefined names. This prevents duplicate + * declaration issues, which are warnings on gcc-3 but have become + * errors on gcc-4. + */ +#define exit lcexit +#include +#undef exit +#define write lcwrite +#define getpid lcgetpid +#define close lcclose +#include +#undef write +#undef getpid +#undef close +#define kill lckill +#include +#undef kill +#include +#include + + +#ifndef __dietlibc__ + +#include + +/* from sysdeps */ +#include + +/* for the stuff in bits/socket.h */ +#include + +#include + +#endif + +/* Re-configure errno to a local one */ +#ifdef errno +#undef errno +#endif +#define errno __stack_chk_fail_errno +static unsigned long int __stack_chk_fail_errno; + +static ssize_t write(int fd, const void *buf, size_t count) __attribute__ ((always_inline)); +static _syscall3(ssize_t,write, int,fd, const void *,buf, size_t,count); + +static void exit(int status) __attribute__ ((always_inline)); +static _syscall1(void,exit, int,status); + +static int kill(pid_t pid, int sig) __attribute__ ((always_inline)); +static _syscall2(int,kill, pid_t,pid, int,sig); + +static pid_t getpid(void) __attribute__ ((always_inline)); +static _syscall0(pid_t,getpid); + +#ifndef __dietlibc__ + +static int close(int fd) __attribute__ ((always_inline)); +static _syscall1(int,close, int,fd); + + +/* socketcall is present on most arches (including x86, arm (some), ppc, ppc64, mips, mips64, sparc, sparc64) + * x86_86 and some arm do not have it, but does have socket and connect syscalls + * Assume this when socketcall is not available. + */ +#ifdef __NR_socketcall + +static long socketcall(int call, unsigned long *args) __attribute__ ((always_inline)); +static _syscall2(long,socketcall, int,call, unsigned long *,args); + +#define DO_SOCKET(result,domain,type,protocol) \ + socketargs[0] = domain; \ + socketargs[1] = type; \ + socketargs[2] = protocol; \ + socketargs[3] = 0; \ + result = socketcall(SOCKOP_socket, socketargs) + +#define DO_CONNECT(result,sockfd,serv_addr,addrlen) \ + socketargs[0] = sockfd; \ + socketargs[1] = (unsigned long int)serv_addr; \ + socketargs[2] = addrlen; \ + socketargs[3] = 0; \ + result = socketcall(SOCKOP_connect, socketargs) + +#else + +#ifndef __NR_local_inline_socket +#define __NR_local_inline_socket __NR_socket +#endif + +#ifndef __NR_local_inline_connect +#define __NR_local_inline_connect __NR_connect +#endif + +static int local_inline_socket(int domain, int type, int protocol) __attribute__ ((always_inline)) ; +static _syscall3(int,local_inline_socket, int,domain, int,type, int,protocol); + +#define DO_SOCKET(result,domain,type,protocol) \ + result = local_inline_socket(domain,type,protocol) + +static int local_inline_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) __attribute__ ((always_inline)) ; +static _syscall3(int,local_inline_connect, int,sockfd, const struct sockaddr *,serv_addr, socklen_t,addrlen); + +#define DO_CONNECT(result,sockfd,serv_addr,addrlen) \ + result = local_inline_connect(sockfd,(struct sockaddr *)serv_addr, addrlen) + +#endif + +#ifndef _PATH_LOG +#define _PATH_LOG "/dev/log" +#endif + +const char path_log[]=_PATH_LOG; + +extern char *__progname; + +#else + +static char *__progname = ""; + +#endif + +#else +/* not building on linux */ + +#error "Gentoo SSP support: glibc can only be built with SSP on Linux" + +#endif + +#else +/* not SSP */ + +#warning "Gentoo SSP support: building standard upstream handler, glibc itself is not protected" + #include #include extern char **__libc_argv attribute_hidden; +#endif +/* endif SSP */ + +#if defined ENABLE_OLD_SSP_COMPAT void __attribute__ ((noreturn)) +__attribute__ ((alias("__stack_smash_handler"))) __stack_chk_fail (void) { +#else /* defined ENABLE_OLD_SSP_COMPAT */ +void +__attribute__ ((noreturn)) +__stack_chk_fail (void) +{ +#endif /* defined ENABLE_OLD_SSP_COMPAT */ + +#if defined __SSP__ || defined __SSP_ALL__ + + #define MESSAGE_BUFSIZ 512 + pid_t pid; + int plen, i; + char message[MESSAGE_BUFSIZ]; + const char msg_prefix[]="*** stack smashing detected ***: "; + const char msg_suffix[]=" terminated\n"; + const char msg_unknown[]=""; +#ifndef __dietlibc__ + int log_socket, connect_result; + struct sockaddr_un sock; +#ifdef __NR_socketcall + unsigned long int *socketargs=(unsigned long int *)alloca(sizeof(unsigned long int)*4); +#endif +#endif + + /* build message */ +#define strconcat(str) \ + i=0; while ((str[i] != '\0') && ((i+plen)<(MESSAGE_BUFSIZ-1))) {\ + message[plen+i]=str[i];\ + i++;\ + }\ + plen+=i; + plen=0; + strconcat(msg_prefix); + if (__progname != (char *)0) { + strconcat(__progname); + } else { + strconcat(msg_unknown); + } + strconcat(msg_suffix); + message[plen++]='\0'; + + /* Write out error message to STDERR */ + write(STDERR_FILENO, message, plen); + +#ifndef __dietlibc__ + /* Log to syslog; socket write to /dev/log */ + + /* 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) { + close(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))); + } + } + /* If a successful connection was made, log the message */ + if (connect_result != -1) { + write(log_socket,message,plen); + } + if (log_socket != -1) { + close(log_socket); + } +#endif + + /* Suicide - note; sigactions can't be added to SIGKILL, nor can it be masked */ + pid=getpid(); + kill(pid,SIGKILL); + + /* In case the kill didn't work, exit anyway + * The loop prevents gcc thinking this routine returns + */ + while (1) exit(EXIT_FAILURE); + +#else + /* The loop is added only to keep gcc happy. */ while (1) __libc_message (1, "*** stack smashing detected ***: %s terminated\n", __libc_argv[0] ?: ""); -} -#ifdef ENABLE_OLD_SSP_COMPAT -strong_alias (__stack_chk_fail, __stack_smash_handler) #endif +} +