]> git.ipfire.org Git - thirdparty/gcc.git/blame - libvtv/vtv_fail.cc
[Ada] Use new API when creating a special SPARK heap entity
[thirdparty/gcc.git] / libvtv / vtv_fail.cc
CommitLineData
8d9254fc 1/* Copyright (C) 2012-2020 Free Software Foundation, Inc.
2077db1b
CT
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>
f7f049fa
CT
48
49#if !defined (__CYGWIN__) && !defined (__MINGW32__)
2077db1b 50#include <execinfo.h>
f7f049fa
CT
51#endif
52
2077db1b
CT
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. */
59bool vtv_no_abort = false;
60
61
62extern "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
79const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
80
81/* Instantiate the template classes (in vtv_set.h) for our particular
82 hash table needs. */
83typedef void * vtv_set_handle;
84typedef vtv_set_handle * vtv_set_handle_handle;
85
86static 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
93static void
94log_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];
f7f049fa 108#if !defined (__CYGWIN__) && !defined (__MINGW32__)
2077db1b
CT
109 int actual_depth = backtrace (callers, STACK_DEPTH);
110 backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd);
f7f049fa 111#endif
2077db1b
CT
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
123static inline bool
124is_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
133static inline vtv_set_handle *
134ptr_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
143static inline vtv_set_handle_handle
144set_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
156void
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
173void
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
191static void
192vtv_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
218void
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