ssp.c revision 256866
168651Skris/* Stack protector support. 268651Skris Copyright (C) 2005 Free Software Foundation, Inc. 3238405Sjkim 4238405SjkimThis file is part of GCC. 5238405Sjkim 6238405SjkimGCC is free software; you can redistribute it and/or modify it under 768651Skristhe terms of the GNU General Public License as published by the Free 868651SkrisSoftware Foundation; either version 2, or (at your option) any later 968651Skrisversion. 1068651Skris 1168651SkrisIn addition to the permissions in the GNU General Public License, the 1268651SkrisFree Software Foundation gives you unlimited permission to link the 1368651Skriscompiled version of this file into combinations with other programs, 1468651Skrisand to distribute those combinations without any restriction coming 1568651Skrisfrom the use of this file. (The General Public License restrictions 1668651Skrisdo apply in other respects; for example, they cover modification of 1768651Skristhe file, and distribution when not linked into a combine 18109998Smarkmexecutable.) 1968651Skris 2068651SkrisGCC is distributed in the hope that it will be useful, but WITHOUT ANY 2168651SkrisWARRANTY; without even the implied warranty of MERCHANTABILITY or 2268651SkrisFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2368651Skrisfor more details. 2468651Skris 25109998SmarkmYou should have received a copy of the GNU General Public License 2668651Skrisalong with GCC; see the file COPYING. If not, write to the Free 2768651SkrisSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 28109998Smarkm02110-1301, USA. */ 2968651Skris 30109998Smarkm/* As a special exception, if you link this library with files compiled with 3168651Skris GCC to produce an executable, this does not cause the resulting executable 3268651Skris to be covered by the GNU General Public License. This exception does not 33109998Smarkm however invalidate any other reasons why the executable file might be 3468651Skris covered by the GNU General Public License. */ 3568651Skris 36109998Smarkm#include "config.h" 3768651Skris#ifdef HAVE_ALLOCA_H 38109998Smarkm# include <alloca.h> 39109998Smarkm#endif 4068651Skris#ifdef HAVE_STRING_H 4168651Skris# include <string.h> 4268651Skris#endif 4368651Skris#ifdef HAVE_UNISTD_H 4468651Skris# include <unistd.h> 4568651Skris#endif 4668651Skris#ifdef HAVE_FCNTL_H 4768651Skris# include <fcntl.h> 4868651Skris#endif 4968651Skris#ifdef HAVE_PATHS_H 5068651Skris# include <paths.h> 5168651Skris#endif 5268651Skris#ifndef _PATH_TTY 5368651Skris# define _PATH_TTY "/dev/tty" 5468651Skris#endif 55109998Smarkm#ifdef HAVE_SYSLOG_H 5668651Skris# include <syslog.h> 57109998Smarkm#endif 58109998Smarkm 5968651Skrisvoid *__stack_chk_guard = 0; 6068651Skris 6168651Skrisstatic void __attribute__ ((constructor)) 6268651Skris__guard_setup (void) 6368651Skris{ 6468651Skris unsigned char *p; 6568651Skris int fd; 6668651Skris 6768651Skris if (__stack_chk_guard != 0) 6868651Skris return; 6968651Skris 7068651Skris fd = open ("/dev/urandom", O_RDONLY); 7168651Skris if (fd != -1) 7268651Skris { 7368651Skris ssize_t size = read (fd, &__stack_chk_guard, 7468651Skris sizeof (__stack_chk_guard)); 7568651Skris close (fd); 7668651Skris if (size == sizeof(__stack_chk_guard) && __stack_chk_guard != 0) 7768651Skris return; 78238405Sjkim } 79238405Sjkim 8068651Skris /* If a random generator can't be used, the protector switches the guard 8168651Skris to the "terminator canary". */ 8268651Skris p = (unsigned char *) &__stack_chk_guard; 8368651Skris p[sizeof(__stack_chk_guard)-1] = 255; 8468651Skris p[sizeof(__stack_chk_guard)-2] = '\n'; 8568651Skris p[0] = 0; 8668651Skris} 8768651Skris 8868651Skrisstatic void 89238405Sjkimfail (const char *msg1, size_t msg1len, const char *msg3) 9068651Skris{ 9168651Skris#ifdef __GNU_LIBRARY__ 9268651Skris extern char * __progname; 9368651Skris#else 9468651Skris static const char __progname[] = ""; 95109998Smarkm#endif 9668651Skris int fd; 9768651Skris 9868651Skris /* Print error message directly to the tty. This avoids Bad Things 9968651Skris happening if stderr is redirected. */ 10068651Skris fd = open (_PATH_TTY, O_WRONLY); 10168651Skris if (fd != -1) 10268651Skris { 10368651Skris static const char msg2[] = " terminated\n"; 10468651Skris size_t progname_len, len; 10568651Skris char *buf, *p; 10668651Skris 10768651Skris progname_len = strlen (__progname); 10868651Skris len = msg1len + progname_len + sizeof(msg2)-1 + 1; 10968651Skris p = buf = alloca (len); 11068651Skris 11168651Skris memcpy (p, msg1, msg1len); 11268651Skris p += msg1len; 11368651Skris memcpy (p, __progname, progname_len); 11468651Skris p += progname_len; 11568651Skris memcpy (p, msg2, sizeof(msg2)); 11668651Skris 11768651Skris while (len > 0) 11868651Skris { 11968651Skris ssize_t wrote = write (fd, buf, len); 12068651Skris if (wrote < 0) 12168651Skris break; 12268651Skris buf += wrote; 12368651Skris len -= wrote; 12468651Skris } 12568651Skris close (fd); 126160814Ssimon } 12768651Skris 12868651Skris#ifdef HAVE_SYSLOG_H 129160814Ssimon /* Only send the error to syslog if there was no tty available. */ 13068651Skris else 13168651Skris syslog (LOG_CRIT, "%s", msg3); 13268651Skris#endif /* HAVE_SYSLOG_H */ 133109998Smarkm 13468651Skris /* Try very hard to exit. Note that signals may be blocked preventing 13568651Skris the first two options from working. The use of volatile is here to 13668651Skris prevent optimizers from "knowing" that __builtin_trap is called first, 13768651Skris and that it doesn't return, and so "obviously" the rest of the code 13868651Skris is dead. */ 13968651Skris { 14068651Skris volatile int state; 14168651Skris for (state = 0; ; state++) 14268651Skris switch (state) 14368651Skris { 14468651Skris case 0: 14568651Skris __builtin_trap (); 14668651Skris break; 14768651Skris case 1: 14868651Skris *(volatile int *)-1L = 0; 14968651Skris break; 15068651Skris case 2: 15168651Skris _exit (127); 15268651Skris break; 15368651Skris } 15468651Skris } 15568651Skris} 15668651Skris 15768651Skrisvoid 15868651Skris__stack_chk_fail (void) 15968651Skris{ 16068651Skris const char *msg = "*** stack smashing detected ***: "; 16168651Skris fail (msg, strlen (msg), "stack smashing detected: terminated"); 16268651Skris} 16368651Skris 16468651Skrisvoid 16568651Skris__chk_fail (void) 16668651Skris{ 16768651Skris const char *msg = "*** buffer overflow detected ***: "; 16868651Skris fail (msg, strlen (msg), "buffer overflow detected: terminated"); 16968651Skris} 17068651Skris 17168651Skris#ifdef HAVE_HIDDEN_VISIBILITY 17268651Skrisvoid 17368651Skris__attribute__((visibility ("hidden"))) 17468651Skris__stack_chk_fail_local (void) 175238405Sjkim{ 17668651Skris __stack_chk_fail (); 17768651Skris} 17868651Skris#endif 17968651Skris