1/* Stack protector support.
2   Copyright (C) 2005, 2009 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11In addition to the permissions in the GNU General Public License, the
12Free Software Foundation gives you unlimited permission to link the
13compiled version of this file into combinations with other programs,
14and to distribute those combinations without any restriction coming
15from the use of this file.  (The General Public License restrictions
16do apply in other respects; for example, they cover modification of
17the file, and distribution when not linked into a combine
18executable.)
19
20GCC is distributed in the hope that it will be useful, but WITHOUT ANY
21WARRANTY; without even the implied warranty of MERCHANTABILITY or
22FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23for more details.
24
25Under Section 7 of GPL version 3, you are granted additional
26permissions described in the GCC Runtime Library Exception, version
273.1, as published by the Free Software Foundation.
28
29You should have received a copy of the GNU General Public License and
30a copy of the GCC Runtime Library Exception along with this program;
31see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
32<http://www.gnu.org/licenses/>.  */
33
34
35#include "config.h"
36#ifdef HAVE_ALLOCA_H
37# include <alloca.h>
38#endif
39#ifdef HAVE_MALLOC_H
40# include <malloc.h>
41#endif
42#ifdef HAVE_STRING_H
43# include <string.h>
44#endif
45#ifdef HAVE_UNISTD_H
46# include <unistd.h>
47#endif
48#ifdef HAVE_FCNTL_H
49# include <fcntl.h>
50#endif
51#ifdef HAVE_PATHS_H
52# include <paths.h>
53#endif
54#ifndef _PATH_TTY
55/* Native win32 apps don't know about /dev/tty but can print directly
56   to the console using  "CONOUT$"   */
57#if defined (_WIN32) && !defined (__CYGWIN__)
58# define _PATH_TTY "CONOUT$"
59#else
60# define _PATH_TTY "/dev/tty"
61#endif
62#endif
63#ifdef HAVE_SYSLOG_H
64# include <syslog.h>
65#endif
66
67void *__stack_chk_guard = 0;
68
69static void __attribute__ ((constructor))
70__guard_setup (void)
71{
72  unsigned char *p;
73  int fd;
74
75  if (__stack_chk_guard != 0)
76    return;
77
78  fd = open ("/dev/urandom", O_RDONLY);
79  if (fd != -1)
80    {
81      ssize_t size = read (fd, &__stack_chk_guard,
82                           sizeof (__stack_chk_guard));
83      close (fd);
84      if (size == sizeof(__stack_chk_guard) && __stack_chk_guard != 0)
85        return;
86    }
87
88  /* If a random generator can't be used, the protector switches the guard
89     to the "terminator canary".  */
90  p = (unsigned char *) &__stack_chk_guard;
91  p[sizeof(__stack_chk_guard)-1] = 255;
92  p[sizeof(__stack_chk_guard)-2] = '\n';
93  p[0] = 0;
94}
95
96static void
97fail (const char *msg1, size_t msg1len, const char *msg3)
98{
99#ifdef __GNU_LIBRARY__
100  extern char * __progname;
101#else
102  static const char __progname[] = "";
103#endif
104  int fd;
105
106  /* Print error message directly to the tty.  This avoids Bad Things
107     happening if stderr is redirected.  */
108  fd = open (_PATH_TTY, O_WRONLY);
109  if (fd != -1)
110    {
111      static const char msg2[] = " terminated\n";
112      size_t progname_len, len;
113      char *buf, *p;
114
115      progname_len = strlen (__progname);
116      len = msg1len + progname_len + sizeof(msg2)-1 + 1;
117      p = buf = alloca (len);
118
119      memcpy (p, msg1, msg1len);
120      p += msg1len;
121      memcpy (p, __progname, progname_len);
122      p += progname_len;
123      memcpy (p, msg2, sizeof(msg2));
124
125      while (len > 0)
126        {
127          ssize_t wrote = write (fd, buf, len);
128          if (wrote < 0)
129            break;
130          buf += wrote;
131          len -= wrote;
132        }
133      close (fd);
134    }
135
136#ifdef HAVE_SYSLOG_H
137  /* Only send the error to syslog if there was no tty available.  */
138  else
139    syslog (LOG_CRIT, msg3);
140#endif /* HAVE_SYSLOG_H */
141
142  /* Try very hard to exit.  Note that signals may be blocked preventing
143     the first two options from working.  The use of volatile is here to
144     prevent optimizers from "knowing" that __builtin_trap is called first,
145     and that it doesn't return, and so "obviously" the rest of the code
146     is dead.  */
147  {
148    volatile int state;
149    for (state = 0; ; state++)
150      switch (state)
151        {
152        case 0:
153          __builtin_trap ();
154          break;
155        case 1:
156          *(volatile int *)-1L = 0;
157          break;
158        case 2:
159          _exit (127);
160          break;
161        }
162  }
163}
164
165void
166__stack_chk_fail (void)
167{
168  const char *msg = "*** stack smashing detected ***: ";
169  fail (msg, strlen (msg), "stack smashing detected: terminated");
170}
171
172void
173__chk_fail (void)
174{
175  const char *msg = "*** buffer overflow detected ***: ";
176  fail (msg, strlen (msg), "buffer overflow detected: terminated");
177}
178
179#ifdef HAVE_HIDDEN_VISIBILITY
180void
181__attribute__((visibility ("hidden")))
182__stack_chk_fail_local (void)
183{
184  __stack_chk_fail ();
185}
186#endif
187