145
|
1 /* Copyright (C) 2012-2020 Free Software Foundation, Inc.
|
111
|
2
|
|
3 This file is part of GCC.
|
|
4
|
|
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.
|
|
9
|
|
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.
|
|
14
|
|
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.
|
|
18
|
|
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/>. */
|
|
23
|
|
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).
|
|
28
|
|
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.
|
|
42
|
|
43 */
|
|
44
|
|
45 #include <stdlib.h>
|
|
46 #include <stdio.h>
|
|
47 #include <string.h>
|
|
48
|
|
49 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
|
|
50 #include <execinfo.h>
|
|
51 #endif
|
|
52
|
|
53 #include <unistd.h>
|
|
54
|
|
55 #include "vtv_utils.h"
|
|
56 #include "vtv_fail.h"
|
|
57
|
|
58 /* This is used to disable aborts for debugging purposes. */
|
|
59 bool vtv_no_abort = false;
|
|
60
|
|
61
|
|
62 extern "C" {
|
|
63
|
|
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. */
|
|
74
|
|
75 extern void __fortify_fail (const char *) __attribute__((noreturn));
|
|
76
|
|
77 } /* extern "C" */
|
|
78
|
|
79 const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
|
|
80
|
|
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;
|
|
85
|
|
86 static int vtv_failures_log_fd = -1;
|
|
87
|
|
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. */
|
|
92
|
|
93 static void
|
|
94 log_error_message (const char *log_msg, bool generate_backtrace)
|
|
95 {
|
|
96 if (vtv_failures_log_fd == -1)
|
|
97 vtv_failures_log_fd = vtv_open_log ("vtable_verification_failures.log");
|
|
98
|
|
99 if (vtv_failures_log_fd == -1)
|
|
100 return;
|
|
101
|
|
102 vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg);
|
|
103
|
|
104 if (generate_backtrace)
|
|
105 {
|
|
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
|
|
112 }
|
|
113 }
|
|
114
|
|
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. */
|
|
122
|
|
123 static inline bool
|
|
124 is_set_handle_handle (void * ptr)
|
|
125 {
|
|
126 return ((unsigned long) ptr & SET_HANDLE_HANDLE_BIT)
|
|
127 == SET_HANDLE_HANDLE_BIT;
|
|
128 }
|
|
129
|
|
130 /* Returns the actual pointer value of a vtable map variable, PTR (see
|
|
131 comments for is_set_handle_handle for more details). */
|
|
132
|
|
133 static inline vtv_set_handle *
|
|
134 ptr_from_set_handle_handle (void * ptr)
|
|
135 {
|
|
136 return (vtv_set_handle *) ((unsigned long) ptr & ~SET_HANDLE_HANDLE_BIT);
|
|
137 }
|
|
138
|
|
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. */
|
|
142
|
|
143 static inline vtv_set_handle_handle
|
|
144 set_handle_handle (vtv_set_handle * ptr)
|
|
145 {
|
|
146 return (vtv_set_handle_handle) ((unsigned long) ptr | SET_HANDLE_HANDLE_BIT);
|
|
147 }
|
|
148
|
|
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 */
|
|
155
|
|
156 void
|
|
157 __vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr,
|
|
158 const char *debug_msg)
|
|
159 {
|
|
160 log_error_message (debug_msg, false);
|
|
161
|
|
162 /* Call the public interface in case it has been overwritten by
|
|
163 user. */
|
|
164 __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
|
|
165
|
|
166 log_error_message ("Returned from __vtv_verify_fail."
|
|
167 " Secondary verification succeeded.\n", false);
|
|
168 }
|
|
169
|
|
170 /* This function calls __fortify_fail with a FAILURE_MSG and then
|
|
171 calls abort. */
|
|
172
|
|
173 void
|
|
174 __vtv_really_fail (const char *failure_msg)
|
|
175 {
|
|
176 __fortify_fail (failure_msg);
|
|
177
|
|
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 ();
|
|
183 }
|
|
184
|
|
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. */
|
|
190
|
|
191 static void
|
|
192 vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
|
|
193 {
|
|
194 char buffer[128];
|
|
195 int buf_len;
|
|
196 const char *format_str =
|
|
197 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
|
|
198
|
|
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);
|
|
206
|
|
207 if (!vtv_no_abort)
|
|
208 __vtv_really_fail (msg);
|
|
209 }
|
|
210
|
|
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. */
|
|
217
|
|
218 void
|
|
219 __vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
|
|
220 {
|
|
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);
|
|
228
|
|
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);
|
|
234
|
|
235 const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
|
|
236 vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
|
|
237 }
|
|
238
|