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