annotate libvtv/vtv_fail.cc @ 111:04ced10e8804

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