1 /* Copyright (C) 2012-2024 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)
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.
49 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
55 #include "vtv_utils.h"
58 /* This is used to disable aborts for debugging purposes. */
59 bool vtv_no_abort
= false;
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
75 extern void __fortify_fail (const char *) __attribute__((noreturn
));
79 const unsigned long SET_HANDLE_HANDLE_BIT
= 0x2;
81 /* Instantiate the template classes (in vtv_set.h) for our particular
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
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)
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
);
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
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
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 */
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
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
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
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. */
192 vtv_fail (const char *msg
, void **data_set_ptr
, const void *vtbl_ptr
)
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
) :
203 buf_len
= strlen (buffer
);
204 /* Send this to stderr. */
205 write (2, buffer
, buf_len
);
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. */
219 __vtv_verify_fail (void **data_set_ptr
, const void *vtbl_ptr
)
222 snprintf (log_msg
, sizeof (log_msg
), "Looking for vtable %p in set %p.\n",
224 is_set_handle_handle (*data_set_ptr
) ?
225 ptr_from_set_handle_handle (*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
);