PR target/85317
[official-gcc.git] / libvtv / vtv_fail.cc
blob5150e9d1946e6b23bda3808830f0f25c4f3a8aa7
1 /* Copyright (C) 2012-2018 Free Software Foundation, Inc.
3 This file is part of GCC.
5 GCC is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
10 GCC is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
22 <http://www.gnu.org/licenses/>. */
24 /* This file is part of the vtable security feature implementation.
25 The vtable security feature is designed to detect when a virtual
26 call is about to be made through an invalid vtable pointer
27 (possibly due to data corruption or malicious attacks).
29 This file also contains the failure functions that get called when
30 a vtable pointer is not found in the data set. Two particularly
31 important functions are __vtv_verify_fail and __vtv_really_fail.
32 They are both externally visible. __vtv_verify_fail is defined in
33 such a way that it can be replaced by a programmer, if desired. It
34 is the function that __VLTVerifyVtablePointer calls if it can't
35 find the pointer in the data set. Allowing the programmer to
36 overwrite this function means that he/she can do some alternate
37 verification, including NOT failing in certain specific cases, if
38 desired. This may be the case if the programmer has to deal wtih
39 unverified third party software, for example. __vtv_really_fail is
40 available for the programmer to call from his version of
41 __vtv_verify_fail, if he decides the failure is real.
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
49 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
50 #include <execinfo.h>
51 #endif
53 #include <unistd.h>
55 #include "vtv_utils.h"
56 #include "vtv_fail.h"
58 /* This is used to disable aborts for debugging purposes. */
59 bool vtv_no_abort = false;
62 extern "C" {
64 /* __fortify_fail is a function in glibc that calls __libc_message,
65 causing it to print out a program termination error message
66 (including the name of the binary being terminated), a stack
67 trace where the error occurred, and a memory map dump. Ideally
68 we would have called __libc_message directly, but that function
69 does not appear to be accessible to functions outside glibc,
70 whereas __fortify_fail is. We call __fortify_fail from
71 __vtv_really_fail. We looked at calling __libc_fatal, which is
72 externally accessible, but it does not do the back trace and
73 memory dump. */
75 extern void __fortify_fail (const char *) __attribute__((noreturn));
77 } /* extern "C" */
79 const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
81 /* Instantiate the template classes (in vtv_set.h) for our particular
82 hash table needs. */
83 typedef void * vtv_set_handle;
84 typedef vtv_set_handle * vtv_set_handle_handle;
86 static int vtv_failures_log_fd = -1;
88 /* Open error logging file, if not already open, and write vtable
89 verification failure messages (LOG_MSG) to the log file. Also
90 generate a backtrace in the log file, if GENERATE_BACKTRACE is
91 set. */
93 static void
94 log_error_message (const char *log_msg, bool generate_backtrace)
96 if (vtv_failures_log_fd == -1)
97 vtv_failures_log_fd = vtv_open_log ("vtable_verification_failures.log");
99 if (vtv_failures_log_fd == -1)
100 return;
102 vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg);
104 if (generate_backtrace)
106 #define STACK_DEPTH 20
107 void *callers[STACK_DEPTH];
108 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
109 int actual_depth = backtrace (callers, STACK_DEPTH);
110 backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd);
111 #endif
115 /* In the case where a vtable map variable is the only instance of the
116 variable we have seen, it points directly to the set of valid
117 vtable pointers. All subsequent instances of the 'same' vtable map
118 variable point to the first vtable map variable. This function,
119 given a vtable map variable PTR, checks a bit to see whether it's
120 pointing directly to the data set or to the first vtable map
121 variable. */
123 static inline bool
124 is_set_handle_handle (void * ptr)
126 return ((unsigned long) ptr & SET_HANDLE_HANDLE_BIT)
127 == SET_HANDLE_HANDLE_BIT;
130 /* Returns the actual pointer value of a vtable map variable, PTR (see
131 comments for is_set_handle_handle for more details). */
133 static inline vtv_set_handle *
134 ptr_from_set_handle_handle (void * ptr)
136 return (vtv_set_handle *) ((unsigned long) ptr & ~SET_HANDLE_HANDLE_BIT);
139 /* Given a vtable map variable, PTR, this function sets the bit that
140 says this is the second (or later) instance of a vtable map
141 variable. */
143 static inline vtv_set_handle_handle
144 set_handle_handle (vtv_set_handle * ptr)
146 return (vtv_set_handle_handle) ((unsigned long) ptr | SET_HANDLE_HANDLE_BIT);
149 /* This function is called from __VLTVerifyVtablePointerDebug; it
150 sends as much debugging information as it can to the error log
151 file, then calls __vtv_verify_fail. SET_HANDLE_PTR is the pointer
152 to the set of valid vtable pointers, VTBL_PTR is the pointer that
153 was not found in the set, and DEBUG_MSG is the message to be
154 written to the log file before failing. n */
156 void
157 __vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr,
158 const char *debug_msg)
160 log_error_message (debug_msg, false);
162 /* Call the public interface in case it has been overwritten by
163 user. */
164 __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
166 log_error_message ("Returned from __vtv_verify_fail."
167 " Secondary verification succeeded.\n", false);
170 /* This function calls __fortify_fail with a FAILURE_MSG and then
171 calls abort. */
173 void
174 __vtv_really_fail (const char *failure_msg)
176 __fortify_fail (failure_msg);
178 /* We should never get this far; __fortify_fail calls __libc_message
179 which prints out a back trace and a memory dump and then is
180 supposed to call abort, but let's play it safe anyway and call abort
181 ourselves. */
182 abort ();
185 /* This function takes an error MSG, a vtable map variable
186 (DATA_SET_PTR) and a vtable pointer (VTBL_PTR). It is called when
187 an attempt to verify VTBL_PTR with the set pointed to by
188 DATA_SET_PTR failed. It outputs a failure message with the
189 addresses involved, and calls __vtv_really_fail. */
191 static void
192 vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
194 char buffer[128];
195 int buf_len;
196 const char *format_str =
197 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
199 snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr,
200 is_set_handle_handle(*data_set_ptr) ?
201 ptr_from_set_handle_handle (*data_set_ptr) :
202 *data_set_ptr);
203 buf_len = strlen (buffer);
204 /* Send this to to stderr. */
205 write (2, buffer, buf_len);
207 if (!vtv_no_abort)
208 __vtv_really_fail (msg);
211 /* Send information about what we were trying to do when verification
212 failed to the error log, then call vtv_fail. This function can be
213 overwritten/replaced by the user, to implement a secondary
214 verification function instead. DATA_SET_PTR is the vtable map
215 variable used for the failed verification, and VTBL_PTR is the
216 vtable pointer that was not found in the set. */
218 void
219 __vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
221 char log_msg[256];
222 snprintf (log_msg, sizeof (log_msg), "Looking for vtable %p in set %p.\n",
223 vtbl_ptr,
224 is_set_handle_handle (*data_set_ptr) ?
225 ptr_from_set_handle_handle (*data_set_ptr) :
226 *data_set_ptr);
227 log_error_message (log_msg, false);
229 const char *format_str =
230 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
231 snprintf (log_msg, sizeof (log_msg), format_str, vtbl_ptr, *data_set_ptr);
232 log_error_message (log_msg, false);
233 log_error_message (" Backtrace: \n", true);
235 const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
236 vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);