1 /* Copyright (C) 2005 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 /* Copyright (C) 2006-2007 Gentoo Foundation Inc.
20 * License terms as above.
22 * Hardened Gentoo SSP handler
24 * An SSP failure handler that does not use functions from the rest of
25 * glibc; it uses the INTERNAL_SYSCALL methods directly. This ensures
26 * no possibility of recursion into the handler.
28 * Direct all bug reports to http://bugs.gentoo.org/
30 * Re-written from the glibc-2.3 Hardened Gentoo SSP handler
31 * by Kevin F. Quinn - <kevquinn[@]gentoo.org>
33 * The following people contributed to the glibc-2.3 Hardened
34 * Gentoo SSP handler, from which this implementation draws much:
36 * Ned Ludd - <solar[@]gentoo.org>
37 * Alexander Gabert - <pappy[@]gentoo.org>
38 * The PaX Team - <pageexec[@]freemail.hu>
39 * Peter S. Mazinger - <ps.m[@]gmx.net>
40 * Yoann Vandoorselaere - <yoann[@]prelude-ids.org>
41 * Robert Connolly - <robert[@]linuxfromscratch.org>
42 * Cory Visi <cory[@]visi.name>
43 * Mike Frysinger <vapier[@]gentoo.org>
51 #include <sys/types.h>
53 #include <sysdep-cancel.h>
54 #include <sys/syscall.h>
55 #include <bp-checks.h>
57 #include <kernel-features.h>
61 #include <socketcall.h>
62 /* for the stuff in bits/socket.h */
63 #include <sys/socket.h>
67 /* Sanity check on SYSCALL macro names - force compilation
68 * failure if the names used here do not exist
70 #if !defined __NR_socketcall && !defined __NR_socket
71 # error Cannot do syscall socket or socketcall
73 #if !defined __NR_socketcall && !defined __NR_connect
74 # error Cannot do syscall connect or socketcall
77 # error Cannot do syscall write
80 # error Cannot do syscall close
83 # error Cannot do syscall getpid
86 # error Cannot do syscall kill
89 # error Cannot do syscall exit
91 #ifdef SSP_SMASH_DUMPS_CORE
92 # define ENABLE_SSP_SMASH_DUMPS_CORE 1
93 # if !defined _KERNEL_NSIG && !defined _NSIG
94 # error No _NSIG or _KERNEL_NSIG for rt_sigaction
96 # if !defined __NR_sigaction && !defined __NR_rt_sigaction
97 # error Cannot do syscall sigaction or rt_sigaction
99 /* Although rt_sigaction expects sizeof(sigset_t) - it expects the size
100 * of the _kernel_ sigset_t which is not the same as the user sigset_t.
101 * Most arches have this as _NSIG bits - mips has _KERNEL_NSIG bits for
105 # define _SSP_NSIG _KERNEL_NSIG
107 # define _SSP_NSIG _NSIG
111 # define ENABLE_SSP_SMASH_DUMPS_CORE 0
114 /* Define DO_SIGACTION - default to newer rt signal interface but
115 * fallback to old as needed.
117 #ifdef __NR_rt_sigaction
118 # define DO_SIGACTION(signum, act, oldact) \
119 INLINE_SYSCALL(rt_sigaction, 4, signum, act, oldact, _SSP_NSIG/8)
121 # define DO_SIGACTION(signum, act, oldact) \
122 INLINE_SYSCALL(sigaction, 3, signum, act, oldact)
125 /* Define DO_SOCKET/DO_CONNECT functions to deal with socketcall vs socket/connect */
126 #if defined(__NR_socket) && defined(__NR_connect)
127 # define USE_OLD_SOCKETCALL 0
129 # define USE_OLD_SOCKETCALL 1
131 /* stub out the __NR_'s so we can let gcc optimize away dead code */
132 #ifndef __NR_socketcall
133 # define __NR_socketcall 0
136 # define __NR_socket 0
139 # define __NR_connect 0
141 #define DO_SOCKET(result, domain, type, protocol) \
143 if (USE_OLD_SOCKETCALL) { \
144 socketargs[0] = domain; \
145 socketargs[1] = type; \
146 socketargs[2] = protocol; \
148 result = INLINE_SYSCALL(socketcall, 2, SOCKOP_socket, socketargs); \
150 result = INLINE_SYSCALL(socket, 3, domain, type, protocol); \
152 #define DO_CONNECT(result, sockfd, serv_addr, addrlen) \
154 if (USE_OLD_SOCKETCALL) { \
155 socketargs[0] = sockfd; \
156 socketargs[1] = (unsigned long int)serv_addr; \
157 socketargs[2] = addrlen; \
159 result = INLINE_SYSCALL(socketcall, 2, SOCKOP_connect, socketargs); \
161 result = INLINE_SYSCALL(connect, 3, sockfd, serv_addr, addrlen); \
165 # define _PATH_LOG "/dev/log"
168 static const char path_log
[] = _PATH_LOG
;
170 /* For building glibc with SSP switched on, define __progname to a
171 * constant if building for the run-time loader, to avoid pulling
172 * in more of libc.so into ld.so
175 static char *__progname
= "<rtld>";
177 extern char *__progname
;
181 /* Common handler code, used by stack_chk_fail and __stack_smash_handler
182 * Inlined to ensure no self-references to the handler within itself.
183 * Data static to avoid putting more than necessary on the stack,
184 * to aid core debugging.
186 __attribute__ ((__noreturn__
, __always_inline__
))
188 __hardened_gentoo_stack_chk_fail(char func
[], int damaged
)
190 #define MESSAGE_BUFSIZ 256
193 static char message
[MESSAGE_BUFSIZ
];
194 static const char msg_ssa
[] = ": stack smashing attack";
195 static const char msg_inf
[] = " in function ";
196 static const char msg_ssd
[] = "*** stack smashing detected ***: ";
197 static const char msg_terminated
[] = " - terminated\n";
198 static const char msg_report
[] = "Report to http://bugs.gentoo.org/\n";
199 static const char msg_unknown
[] = "<unknown>";
200 static int log_socket
, connect_result
;
201 static struct sockaddr_un sock
;
202 static unsigned long int socketargs
[4];
204 /* Build socket address
206 sock
.sun_family
= AF_UNIX
;
208 while ((path_log
[i
] != '\0') && (i
<(sizeof(sock
.sun_path
)-1))) {
209 sock
.sun_path
[i
] = path_log
[i
];
212 sock
.sun_path
[i
] = '\0';
214 /* Try SOCK_DGRAM connection to syslog */
216 DO_SOCKET(log_socket
, AF_UNIX
, SOCK_DGRAM
, 0);
217 if (log_socket
!= -1)
218 DO_CONNECT(connect_result
, log_socket
, &sock
, sizeof(sock
));
219 if (connect_result
== -1) {
220 if (log_socket
!= -1)
221 INLINE_SYSCALL(close
, 1, log_socket
);
222 /* Try SOCK_STREAM connection to syslog */
223 DO_SOCKET(log_socket
, AF_UNIX
, SOCK_STREAM
, 0);
224 if (log_socket
!= -1)
225 DO_CONNECT(connect_result
, log_socket
, &sock
, sizeof(sock
));
228 /* Build message. Messages are generated both in the old style and new style,
229 * so that log watchers that are configured for the old-style message continue
232 #define strconcat(str) \
233 {i=0; while ((str[i] != '\0') && ((i+plen)<(MESSAGE_BUFSIZ-1))) \
235 message[plen+i]=str[i];\
240 /* R.Henderson post-gcc-4 style message */
243 if (__progname
!= (char *)0)
244 strconcat(__progname
)
246 strconcat(msg_unknown
);
247 strconcat(msg_terminated
);
249 /* Write out error message to STDERR, to syslog if open */
250 INLINE_SYSCALL(write
, 3, STDERR_FILENO
, message
, plen
);
251 if (connect_result
!= -1)
252 INLINE_SYSCALL(write
, 3, log_socket
, message
, plen
);
254 /* Dr. Etoh pre-gcc-4 style message */
256 if (__progname
!= (char *)0)
257 strconcat(__progname
)
259 strconcat(msg_unknown
);
265 strconcat(msg_unknown
);
266 strconcat(msg_terminated
);
267 /* Write out error message to STDERR, to syslog if open */
268 INLINE_SYSCALL(write
, 3, STDERR_FILENO
, message
, plen
);
269 if (connect_result
!= -1)
270 INLINE_SYSCALL(write
, 3, log_socket
, message
, plen
);
272 /* Direct reports to bugs.gentoo.org */
274 strconcat(msg_report
);
275 message
[plen
++]='\0';
277 /* Write out error message to STDERR, to syslog if open */
278 INLINE_SYSCALL(write
, 3, STDERR_FILENO
, message
, plen
);
279 if (connect_result
!= -1)
280 INLINE_SYSCALL(write
, 3, log_socket
, message
, plen
);
282 if (log_socket
!= -1)
283 INLINE_SYSCALL(close
, 1, log_socket
);
286 pid
= INLINE_SYSCALL(getpid
, 0);
288 if (ENABLE_SSP_SMASH_DUMPS_CORE
) {
289 static struct sigaction default_abort_act
;
290 /* Remove any user-supplied handler for SIGABRT, before using it */
291 default_abort_act
.sa_handler
= SIG_DFL
;
292 default_abort_act
.sa_sigaction
= NULL
;
293 __sigfillset(&default_abort_act
.sa_mask
);
294 default_abort_act
.sa_flags
= 0;
295 if (DO_SIGACTION(SIGABRT
, &default_abort_act
, NULL
) == 0)
296 INLINE_SYSCALL(kill
, 2, pid
, SIGABRT
);
299 /* Note; actions cannot be added to SIGKILL */
300 INLINE_SYSCALL(kill
, 2, pid
, SIGKILL
);
302 /* In case the kill didn't work, exit anyway
303 * The loop prevents gcc thinking this routine returns
306 INLINE_SYSCALL(exit
, 0);
309 __attribute__ ((__noreturn__
))
310 void __stack_chk_fail(void)
312 __hardened_gentoo_stack_chk_fail(NULL
, 0);
315 #ifdef ENABLE_OLD_SSP_COMPAT
316 __attribute__ ((__noreturn__
))
317 void __stack_smash_handler(char func
[], int damaged
)
319 __hardened_gentoo_stack_chk_fail(func
, damaged
);