OSDN Git Service

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