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