111
|
1 /* Copyright (C) 2012-2017 Free Software Foundation, Inc.
|
|
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). The
|
|
28 compiler finds every virtual call, and inserts a verification call
|
|
29 before the virtual call. The verification call takes the actual
|
|
30 vtable pointer value in the object through which the virtual call
|
|
31 is being made, and compares the vtable pointer against a set of all
|
|
32 valid vtable pointers that the object could contain (this set is
|
|
33 based on the declared type of the object). If the pointer is in
|
|
34 the valid set, execution is allowed to continue; otherwise the
|
|
35 program is halted.
|
|
36
|
|
37 There are several pieces needed in order to make this work: 1. For
|
|
38 every virtual class in the program (i.e. a class that contains
|
|
39 virtual methods), we need to build the set of all possible valid
|
|
40 vtables that an object of that class could point to. This includes
|
|
41 vtables for any class(es) that inherit from the class under
|
|
42 consideration. 2. For every such data set we build up, we need a
|
|
43 way to find and reference the data set. This is complicated by the
|
|
44 fact that the real vtable addresses are not known until runtime,
|
|
45 when the program is loaded into memory, but we need to reference the
|
|
46 sets at compile time when we are inserting verification calls into
|
|
47 the program. 3. We need to find every virtual call in the program,
|
|
48 and insert the verification call (with the appropriate arguments)
|
|
49 before the virtual call. 4. We need some runtime library pieces:
|
|
50 the code to build up the data sets at runtime; the code to actually
|
|
51 perform the verification using the data sets; and some code to set
|
|
52 protections on the data sets, so they themselves do not become
|
|
53 hacker targets.
|
|
54
|
|
55 To find and reference the set of valid vtable pointers for any given
|
|
56 virtual class, we create a special global varible for each virtual
|
|
57 class. We refer to this as the "vtable map variable" for that
|
|
58 class. The vtable map variable has the type "void *", and is
|
|
59 initialized by the compiler to NULL. At runtime when the set of
|
|
60 valid vtable pointers for a virtual class, e.g. class Foo, is built,
|
|
61 the vtable map variable for class Foo is made to point to the set.
|
|
62 During compile time, when the compiler is inserting verification
|
|
63 calls into the program, it passes the vtable map variable for the
|
|
64 appropriate class to the verification call, so that at runtime the
|
|
65 verification call can find the appropriate data set.
|
|
66
|
|
67 The actual set of valid vtable pointers for a polymorphic class,
|
|
68 e.g. class Foo, cannot be built until runtime, when the vtables get
|
|
69 loaded into memory and their addresses are known. But the knowledge
|
|
70 about which vtables belong in which class' hierarchy is only known
|
|
71 at compile time. Therefore at compile time we collect class
|
|
72 hierarchy and vtable information about every virtual class, and we
|
|
73 generate calls to build up the data sets at runtime. To build the
|
|
74 data sets, we call one of the functions we add to the runtime
|
|
75 library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
|
|
76 a vtable map variable and the address of a vtable. If the vtable
|
|
77 map variable is currently NULL, it creates a new data set (hash
|
|
78 table), makes the vtable map variable point to the new data set, and
|
|
79 inserts the vtable address into the data set. If the vtable map
|
|
80 variable is not NULL, it just inserts the vtable address into the
|
|
81 data set. In order to make sure that our data sets are built before
|
|
82 any verification calls happen, we create a special constructor
|
|
83 initialization function for each compilation unit, give it a very
|
|
84 high initialization priority, and insert all of our calls to
|
|
85 __VLTRegisterPair into our special constructor initialization
|
|
86 function. */
|
|
87
|
|
88 /* This file contains the main externally visible runtime library
|
|
89 functions for vtable verification: __VLTChangePermission,
|
|
90 __VLTRegisterPair, and __VLTVerifyVtablePointer. It also contains
|
|
91 debug versions __VLTRegisterPairDebug and
|
|
92 __VLTVerifyVtablePointerDebug, which have extra parameters in order
|
|
93 to make it easier to debug verification failures.
|
|
94
|
|
95 The final piece of functionality implemented in this file is symbol
|
|
96 resolution for multiple instances of the same vtable map variable.
|
|
97 If the same virtual class is used in two different compilation
|
|
98 units, then each compilation unit will create a vtable map variable
|
|
99 for the class. We need all instances of the same vtable map
|
|
100 variable to point to the same (single) set of valid vtable
|
|
101 pointers for the class, so we wrote our own hashtable-based symbol
|
|
102 resolution for vtable map variables (with a tiny optimization in
|
|
103 the case where there is only one instance of the variable).
|
|
104
|
|
105 There are two other important pieces to the runtime for vtable
|
|
106 verification besides the main pieces that go into libstdc++.so: two
|
|
107 special tiny shared libraries, libvtv_init.so and libvtv_stubs.so.
|
|
108 libvtv_init.so is built from vtv_init.cc. It is designed to help
|
|
109 minimize the calls made to mprotect (see the comments in
|
|
110 vtv_init.cc for more details). Anything compiled with
|
|
111 "-fvtable-verify=std" must be linked with libvtv_init.so (the gcc
|
|
112 driver has been modified to do this). vtv_stubs.so is built from
|
|
113 vtv_stubs.cc. It replaces the main runtime functions
|
|
114 (__VLTChangePermissino, __VLTRegisterPair and
|
|
115 __VLTVerifyVtablePointer) with stub functions that do nothing. If
|
|
116 a programmer has a library that was built with verification, but
|
|
117 wishes to not have verification turned on, the programmer can link
|
|
118 in the vtv_stubs.so library. */
|
|
119
|
|
120 #include <stdlib.h>
|
|
121 #include <stdio.h>
|
|
122 #include <string.h>
|
|
123 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
124 #include <windows.h>
|
|
125 #include <winternl.h>
|
|
126 #include <psapi.h>
|
|
127 #else
|
|
128 #include <execinfo.h>
|
|
129 #endif
|
|
130
|
|
131 #include <unistd.h>
|
|
132 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
|
|
133 #include <sys/mman.h>
|
|
134 #include <link.h>
|
|
135 #endif
|
|
136 #include <errno.h>
|
|
137 #include <fcntl.h>
|
|
138 #include <limits.h>
|
|
139
|
|
140 /* For gthreads suppport */
|
|
141 #include <bits/c++config.h>
|
|
142 #include <ext/concurrence.h>
|
|
143
|
|
144 #include "vtv_utils.h"
|
|
145 #include "vtv_malloc.h"
|
|
146 #include "vtv_set.h"
|
|
147 #include "vtv_map.h"
|
|
148 #include "vtv_rts.h"
|
|
149 #include "vtv_fail.h"
|
|
150
|
|
151 #include "vtv-change-permission.h"
|
|
152
|
|
153 #ifdef HAVE_GETEXECNAME
|
|
154 const char *program_invocation_name;
|
|
155 #endif
|
|
156
|
|
157 #ifdef HAVE___FORTIFY_FAIL
|
|
158 extern "C" {
|
|
159
|
|
160 /* __fortify_fail is a function in glibc that calls __libc_message,
|
|
161 causing it to print out a program termination error message
|
|
162 (including the name of the binary being terminated), a stack
|
|
163 trace where the error occurred, and a memory map dump. Ideally
|
|
164 we would have called __libc_message directly, but that function
|
|
165 does not appear to be accessible to functions outside glibc,
|
|
166 whereas __fortify_fail is. We call __fortify_fail from
|
|
167 __vtv_really_fail. We looked at calling __libc_fatal, which is
|
|
168 externally accessible, but it does not do the back trace and
|
|
169 memory dump. */
|
|
170
|
|
171 extern void __fortify_fail (const char *) __attribute__((noreturn));
|
|
172
|
|
173 } /* extern "C" */
|
|
174 #else
|
|
175 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
176 // porting: fix link error to libc
|
|
177 void __fortify_fail (const char * msg){
|
|
178 OutputDebugString(msg);
|
|
179 abort();
|
|
180 }
|
|
181 #else
|
|
182 // FIXME: Provide backtrace via libbacktrace?
|
|
183 void __fortify_fail (const char *msg) {
|
|
184 write (2, msg, strlen (msg));
|
|
185 abort ();
|
|
186 }
|
|
187 #endif
|
|
188 #endif
|
|
189
|
|
190 /* The following variables are used only for debugging and performance
|
|
191 tuning purposes. Therefore they do not need to be "protected".
|
|
192 They cannot be used to attack the vtable verification system and if
|
|
193 they become corrupted it will not affect the correctness or
|
|
194 security of any of the rest of the vtable verification feature. */
|
|
195
|
|
196 unsigned int num_calls_to_regset = 0;
|
|
197 unsigned int num_calls_to_regpair = 0;
|
|
198 unsigned int num_calls_to_verify_vtable = 0;
|
|
199 unsigned long long regset_cycles = 0;
|
|
200 unsigned long long regpair_cycles = 0;
|
|
201 unsigned long long verify_vtable_cycles = 0;
|
|
202
|
|
203 /* Be careful about initialization of statics in this file. Some of
|
|
204 the routines below are called before any runtime initialization for
|
|
205 statics in this file will be done. For example, dont try to
|
|
206 initialize any of these statics with a runtime call (for ex:
|
|
207 sysconf). The initialization will happen after calls to the routines
|
|
208 to protect/unprotec the vtabla_map variables */
|
|
209
|
|
210 /* No need to mark the following variables with VTV_PROTECTED_VAR.
|
|
211 These are either const or are only used for debugging/tracing.
|
|
212 debugging/tracing will not be ON on production environments */
|
|
213
|
|
214 static const bool debug_hash = HASHTABLE_STATS;
|
|
215
|
|
216 #ifdef VTV_DEBUG
|
|
217 static const int debug_functions = 1;
|
|
218 static const int debug_init = 1;
|
|
219 static const int debug_verify_vtable = 1;
|
|
220 #else
|
|
221 static const int debug_functions = 0;
|
|
222 static const int debug_init = 0;
|
|
223 static const int debug_verify_vtable = 0;
|
|
224 #endif
|
|
225
|
|
226 /* Global file descriptor variables for logging, tracing and debugging. */
|
|
227
|
|
228 static int init_log_fd = -1;
|
|
229 static int verify_vtable_log_fd = -1;
|
|
230
|
|
231 /* This holds a formatted error logging message, to be written to the
|
|
232 vtable verify failures log. */
|
|
233 static char debug_log_message[1024];
|
|
234
|
|
235
|
|
236 #ifdef __GTHREAD_MUTEX_INIT
|
|
237 static __gthread_mutex_t change_permissions_lock = __GTHREAD_MUTEX_INIT;
|
|
238 #else
|
|
239 static __gthread_mutex_t change_permissions_lock;
|
|
240 #endif
|
|
241
|
|
242
|
|
243 #ifndef VTV_STATS
|
|
244 #define VTV_STATS 0
|
|
245 #endif
|
|
246
|
|
247 #if VTV_STATS
|
|
248
|
|
249 static inline unsigned long long
|
|
250 get_cycle_count (void)
|
|
251 {
|
|
252 return rdtsc();
|
|
253 }
|
|
254
|
|
255 static inline void
|
|
256 accumulate_cycle_count (unsigned long long *sum, unsigned long long start)
|
|
257 {
|
|
258 unsigned long long end = rdtsc();
|
|
259 *sum = *sum + (end - start);
|
|
260 }
|
|
261
|
|
262 static inline void
|
|
263 increment_num_calls (unsigned int *num_calls)
|
|
264 {
|
|
265 *num_calls = *num_calls + 1;
|
|
266 }
|
|
267
|
|
268 #else
|
|
269
|
|
270 static inline unsigned long long
|
|
271 get_cycle_count (void)
|
|
272 {
|
|
273 return (unsigned long long) 0;
|
|
274 }
|
|
275
|
|
276 static inline void
|
|
277 accumulate_cycle_count (unsigned long long *sum __attribute__((__unused__)),
|
|
278 unsigned long long start __attribute__((__unused__)))
|
|
279 {
|
|
280 /* Do nothing. */
|
|
281 }
|
|
282
|
|
283 static inline void
|
|
284 increment_num_calls (unsigned int *num_calls __attribute__((__unused__)))
|
|
285 {
|
|
286 /* Do nothing. */
|
|
287 }
|
|
288
|
|
289 #endif
|
|
290
|
|
291 /* Types needed by insert_only_hash_sets. */
|
|
292 typedef uintptr_t int_vptr;
|
|
293
|
|
294 /* The set of valid vtable pointers for each virtual class is stored
|
|
295 in a hash table. This is the hashing function used for the hash
|
|
296 table. For more information on the implementation of the hash
|
|
297 table, see the class insert_only_hash_sets in vtv_set.h. */
|
|
298
|
|
299 struct vptr_hash
|
|
300 {
|
|
301 /* Hash function, used to convert vtable pointer, V, (a memory
|
|
302 address) into an index into the hash table. */
|
|
303 size_t
|
|
304 operator() (int_vptr v) const
|
|
305 {
|
|
306 const uint32_t x = 0x7a35e4d9;
|
|
307 const int shift = (sizeof (v) == 8) ? 23 : 21;
|
|
308 v = x * v;
|
|
309 return v ^ (v >> shift);
|
|
310 }
|
|
311 };
|
|
312
|
|
313 /* This is the memory allocator used to create the hash table data
|
|
314 sets of valid vtable pointers. We use VTV_malloc in order to keep
|
|
315 track of which pages have been allocated, so we can update the
|
|
316 protections on those pages appropriately. See the class
|
|
317 insert_only_hash_sets in vtv_set.h for more information. */
|
|
318
|
|
319 struct vptr_set_alloc
|
|
320 {
|
|
321 /* Memory allocator operator. N is the number of bytes to be
|
|
322 allocated. */
|
|
323 void *
|
|
324 operator() (size_t n) const
|
|
325 {
|
|
326 return __vtv_malloc (n);
|
|
327 }
|
|
328 };
|
|
329
|
|
330 /* Instantiate the template classes (in vtv_set.h) for our particular
|
|
331 hash table needs. */
|
|
332 typedef insert_only_hash_sets<int_vptr, vptr_hash, vptr_set_alloc> vtv_sets;
|
|
333 typedef vtv_sets::insert_only_hash_set vtv_set;
|
|
334 typedef vtv_set * vtv_set_handle;
|
|
335 typedef vtv_set_handle * vtv_set_handle_handle;
|
|
336
|
|
337 /* Records for caching the section header information that we have
|
|
338 read out of the file(s) on disk (in dl_iterate_phdr_callback), to
|
|
339 avoid having to re-open and re-read the same file multiple
|
|
340 times. */
|
|
341
|
|
342 struct sect_hdr_data
|
|
343 {
|
|
344 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
345 uintptr_t dlpi_addr; /* The header address in the INFO record,
|
|
346 passed in from dl_iterate_phdr. */
|
|
347 uintptr_t mp_low; /* Start address of the .vtable_map_vars
|
|
348 section in memory. */
|
|
349 #else
|
|
350 ElfW (Addr) dlpi_addr; /* The header address in the INFO record,
|
|
351 passed in from dl_iterate_phdr. */
|
|
352 ElfW (Addr) mp_low; /* Start address of the .vtable_map_vars
|
|
353 section in memory. */
|
|
354 #endif
|
|
355 size_t mp_size; /* Size of the .vtable_map_vars section in
|
|
356 memory. */
|
|
357 };
|
|
358
|
|
359 /* Array for caching the section header information, read from file,
|
|
360 to avoid re-opening and re-reading the same file over-and-over
|
|
361 again. */
|
|
362
|
|
363 #define MAX_ENTRIES 250
|
|
364 static struct sect_hdr_data vtv_sect_info_cache[MAX_ENTRIES] VTV_PROTECTED_VAR;
|
|
365
|
|
366 unsigned int num_cache_entries VTV_PROTECTED_VAR = 0;
|
|
367
|
|
368 /* This function takes the LOAD_ADDR for an object opened by the
|
|
369 dynamic loader, and checks the array of cached file data to see if
|
|
370 there is an entry with the same addres. If it finds such an entry,
|
|
371 it returns the record for that entry; otherwise it returns
|
|
372 NULL. */
|
|
373
|
|
374 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
375 struct sect_hdr_data *
|
|
376 search_cached_file_data (uintptr_t load_addr)
|
|
377 #else
|
|
378 struct sect_hdr_data *
|
|
379 search_cached_file_data (ElfW (Addr) load_addr)
|
|
380 #endif
|
|
381 {
|
|
382 unsigned int i;
|
|
383 for (i = 0; i < num_cache_entries; ++i)
|
|
384 {
|
|
385 if (vtv_sect_info_cache[i].dlpi_addr == load_addr)
|
|
386 return &(vtv_sect_info_cache[i]);
|
|
387 }
|
|
388
|
|
389 return NULL;
|
|
390 }
|
|
391
|
|
392 /* This function tries to read COUNT bytes out of the file referred to
|
|
393 by FD into the buffer BUF. It returns the actual number of bytes
|
|
394 it succeeded in reading. */
|
|
395
|
|
396 static size_t
|
|
397 ReadPersistent (int fd, void *buf, size_t count)
|
|
398 {
|
|
399 char *buf0 = (char *) buf;
|
|
400 size_t num_bytes = 0;
|
|
401 while (num_bytes < count)
|
|
402 {
|
|
403 int len;
|
|
404 len = read (fd, buf0 + num_bytes, count - num_bytes);
|
|
405 if (len < 0)
|
|
406 return -1;
|
|
407 if (len == 0)
|
|
408 break;
|
|
409 num_bytes += len;
|
|
410 }
|
|
411
|
|
412 return num_bytes;
|
|
413 }
|
|
414
|
|
415 /* This function tries to read COUNT bytes, starting at OFFSET from
|
|
416 the file referred to by FD, and put them into BUF. It calls
|
|
417 ReadPersistent to help it do so. It returns the actual number of
|
|
418 bytes read, or -1 if it fails altogether. */
|
|
419
|
|
420 static size_t
|
|
421 ReadFromOffset (int fd, void *buf, const size_t count, const off_t offset)
|
|
422 {
|
|
423 off_t off = lseek (fd, offset, SEEK_SET);
|
|
424 if (off != (off_t) -1)
|
|
425 return ReadPersistent (fd, buf, count);
|
|
426 return -1;
|
|
427 }
|
|
428
|
|
429 /* The function takes a MESSAGE and attempts to write it to the vtable
|
|
430 memory protection log (for debugging purposes). If the file is not
|
|
431 open, it attempts to open the file first. */
|
|
432
|
|
433 static void
|
|
434 log_memory_protection_data (char *message)
|
|
435 {
|
|
436 static int log_fd = -1;
|
|
437
|
|
438 if (log_fd == -1)
|
|
439 log_fd = __vtv_open_log ("vtv_memory_protection_data.log");
|
|
440
|
|
441 __vtv_add_to_log (log_fd, "%s", message);
|
|
442 }
|
|
443
|
|
444 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
445 static void
|
|
446 read_section_offset_and_length (char *name,
|
|
447 uintptr_t addr,
|
|
448 const char *sect_name,
|
|
449 int mprotect_flags,
|
|
450 off_t *sect_offset,
|
|
451 WORD *sect_len)
|
|
452 {
|
|
453 bool found = false;
|
|
454 struct sect_hdr_data *cached_data = NULL;
|
|
455
|
|
456 /* Check to see if we already have the data for this file. */
|
|
457 cached_data = search_cached_file_data (addr);
|
|
458
|
|
459 if (cached_data)
|
|
460 {
|
|
461 *sect_offset = cached_data->mp_low;
|
|
462 *sect_len = cached_data->mp_size;
|
|
463 return;
|
|
464 }
|
|
465
|
|
466 // check for DOS Header magic bytes
|
|
467 if (*(WORD *)addr == 0x5A4D)
|
|
468 {
|
|
469 int name_len = strlen (sect_name);
|
|
470 int fd = -1;
|
|
471
|
|
472 /* Attempt to open the binary file on disk. */
|
|
473 if (strlen (name) == 0)
|
|
474 {
|
|
475 return;
|
|
476 }
|
|
477 else
|
|
478 fd = open (name, O_RDONLY | O_BINARY);
|
|
479
|
|
480 if (fd != -1)
|
|
481 {
|
|
482 /* Find the section header information in memory. */
|
|
483 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)addr;
|
|
484 PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((char *)addr
|
|
485 + pDosHeader->e_lfanew);
|
|
486 PIMAGE_FILE_HEADER pFileHeader = &pNtHeaders->FileHeader;
|
|
487
|
|
488 DWORD PointerToStringTable = pFileHeader->PointerToSymbolTable
|
|
489 + (pFileHeader->NumberOfSymbols*0x12);
|
|
490
|
|
491 PIMAGE_SECTION_HEADER sect_hdr =
|
|
492 (PIMAGE_SECTION_HEADER)((char *)&pNtHeaders->OptionalHeader
|
|
493 + pFileHeader->SizeOfOptionalHeader);
|
|
494
|
|
495 /* Loop through all the section headers, looking for one whose
|
|
496 name is ".vtable_map_vars". */
|
|
497
|
|
498 for (int i = 0; i < pFileHeader->NumberOfSections && !found; ++i)
|
|
499 {
|
|
500 char header_name[64];
|
|
501
|
|
502 /* Check if we have to get the section name from the COFF string
|
|
503 table. */
|
|
504 if (sect_hdr[i].Name[0] == '/')
|
|
505 {
|
|
506 if (atoi((const char*)sect_hdr[i].Name+1) == 0)
|
|
507 {
|
|
508 continue;
|
|
509 }
|
|
510
|
|
511 off_t name_offset = PointerToStringTable
|
|
512 + atoi((const char*)sect_hdr[i].Name+1);
|
|
513
|
|
514 size_t bytes_read = ReadFromOffset (fd, &header_name, 64,
|
|
515 name_offset);
|
|
516
|
|
517 VTV_ASSERT (bytes_read > 0);
|
|
518 }
|
|
519 else
|
|
520 {
|
|
521 memcpy (&header_name, sect_hdr[i].Name,
|
|
522 sizeof (sect_hdr[i].Name));
|
|
523 }
|
|
524
|
|
525 if (memcmp (header_name, sect_name, name_len) == 0)
|
|
526 {
|
|
527 /* We found the section; get its load offset and
|
|
528 size. */
|
|
529 *sect_offset = sect_hdr[i].VirtualAddress;
|
|
530 if (sect_hdr[i].Misc.VirtualSize % VTV_PAGE_SIZE != 0)
|
|
531 *sect_len = sect_hdr[i].Misc.VirtualSize + VTV_PAGE_SIZE
|
|
532 - (sect_hdr[i].Misc.VirtualSize % VTV_PAGE_SIZE);
|
|
533 else
|
|
534 *sect_len = sect_hdr[i].Misc.VirtualSize;
|
|
535 found = true;
|
|
536 }
|
|
537 }
|
|
538 close (fd);
|
|
539 }
|
|
540 }
|
|
541
|
|
542 if (*sect_offset != 0 && *sect_len != 0)
|
|
543 {
|
|
544 /* Calculate the page location in memory, making sure the
|
|
545 address is page-aligned. */
|
|
546 uintptr_t start_addr = addr + *sect_offset;
|
|
547 *sect_offset = start_addr & ~(VTV_PAGE_SIZE - 1);
|
|
548 *sect_len = *sect_len - 1;
|
|
549
|
|
550 /* Since we got this far, we must not have found these pages in
|
|
551 the cache, so add them to it. NOTE: We could get here either
|
|
552 while making everything read-only or while making everything
|
|
553 read-write. We will only update the cache if we get here on
|
|
554 a read-write (to make absolutely sure the cache is writable
|
|
555 -- also the read-write pass should come before the read-only
|
|
556 pass). */
|
|
557 if ((mprotect_flags & PROT_WRITE)
|
|
558 && num_cache_entries < MAX_ENTRIES)
|
|
559 {
|
|
560 vtv_sect_info_cache[num_cache_entries].dlpi_addr = addr;
|
|
561 vtv_sect_info_cache[num_cache_entries].mp_low = *sect_offset;
|
|
562 vtv_sect_info_cache[num_cache_entries].mp_size = *sect_len;
|
|
563 num_cache_entries++;
|
|
564 }
|
|
565 }
|
|
566 }
|
|
567 #else
|
|
568 static void
|
|
569 read_section_offset_and_length (struct dl_phdr_info *info,
|
|
570 const char *sect_name,
|
|
571 int mprotect_flags,
|
|
572 off_t *sect_offset,
|
|
573 ElfW (Word) *sect_len)
|
|
574 {
|
|
575 char program_name[PATH_MAX];
|
|
576 char *cptr;
|
|
577 bool found = false;
|
|
578 struct sect_hdr_data *cached_data = NULL;
|
|
579 const ElfW (Phdr) *phdr_info = info->dlpi_phdr;
|
|
580 const ElfW (Ehdr) *ehdr_info =
|
|
581 (const ElfW (Ehdr) *) (info->dlpi_addr + info->dlpi_phdr[0].p_vaddr
|
|
582 - info->dlpi_phdr[0].p_offset);
|
|
583
|
|
584
|
|
585 /* Get the name of the main executable. This may or may not include
|
|
586 arguments passed to the program. Find the first space, assume it
|
|
587 is the start of the argument list, and change it to a '\0'. */
|
|
588 #ifdef HAVE_GETEXECNAME
|
|
589 program_invocation_name = getexecname ();
|
|
590 #endif
|
|
591 snprintf (program_name, sizeof (program_name), program_invocation_name);
|
|
592
|
|
593 /* Check to see if we already have the data for this file. */
|
|
594 cached_data = search_cached_file_data (info->dlpi_addr);
|
|
595
|
|
596 if (cached_data)
|
|
597 {
|
|
598 *sect_offset = cached_data->mp_low;
|
|
599 *sect_len = cached_data->mp_size;
|
|
600 return;
|
|
601 }
|
|
602
|
|
603 /* Find the first non-escaped space in the program name and make it
|
|
604 the end of the string. */
|
|
605 cptr = strchr (program_name, ' ');
|
|
606 if (cptr != NULL && cptr[-1] != '\\')
|
|
607 cptr[0] = '\0';
|
|
608
|
|
609 if ((phdr_info->p_type == PT_PHDR || phdr_info->p_type == PT_LOAD)
|
|
610 && (ehdr_info->e_shoff && ehdr_info->e_shnum))
|
|
611 {
|
|
612 int name_len = strlen (sect_name);
|
|
613 int fd = -1;
|
|
614
|
|
615 /* Attempt to open the binary file on disk. */
|
|
616 if (strlen (info->dlpi_name) == 0)
|
|
617 {
|
|
618 /* If the constructor initialization function was put into
|
|
619 the preinit array, then this function will get called
|
|
620 while handling preinit array stuff, in which case
|
|
621 program_invocation_name has not been initialized. In
|
|
622 that case we can get the filename of the executable from
|
|
623 "/proc/self/exe". */
|
|
624 if (strlen (program_name) > 0)
|
|
625 {
|
|
626 if (phdr_info->p_type == PT_PHDR)
|
|
627 fd = open (program_name, O_RDONLY);
|
|
628 }
|
|
629 else
|
|
630 fd = open ("/proc/self/exe", O_RDONLY);
|
|
631 }
|
|
632 else
|
|
633 fd = open (info->dlpi_name, O_RDONLY);
|
|
634
|
|
635 if (fd != -1)
|
|
636 {
|
|
637 /* Find the section header information in the file. */
|
|
638 ElfW (Half) strtab_idx = ehdr_info->e_shstrndx;
|
|
639 ElfW (Shdr) shstrtab;
|
|
640 off_t shstrtab_offset = ehdr_info->e_shoff +
|
|
641 (ehdr_info->e_shentsize * strtab_idx);
|
|
642 size_t bytes_read = ReadFromOffset (fd, &shstrtab, sizeof (shstrtab),
|
|
643 shstrtab_offset);
|
|
644 VTV_ASSERT (bytes_read == sizeof (shstrtab));
|
|
645
|
|
646 ElfW (Shdr) sect_hdr;
|
|
647
|
|
648 /* This code will be needed once we have crated libvtv.so. */
|
|
649 bool is_libvtv = false;
|
|
650
|
|
651 /*
|
|
652 if (strstr (info->dlpi_name, "libvtv.so"))
|
|
653 is_libvtv = true;
|
|
654 */
|
|
655
|
|
656 /* Loop through all the section headers, looking for one whose
|
|
657 name is ".vtable_map_vars". */
|
|
658
|
|
659 for (int i = 0; i < ehdr_info->e_shnum && !found; ++i)
|
|
660 {
|
|
661 off_t offset = ehdr_info->e_shoff + (ehdr_info->e_shentsize * i);
|
|
662
|
|
663 bytes_read = ReadFromOffset (fd, §_hdr, sizeof (sect_hdr),
|
|
664 offset);
|
|
665
|
|
666 VTV_ASSERT (bytes_read == sizeof (sect_hdr));
|
|
667
|
|
668 char header_name[64];
|
|
669 off_t name_offset = shstrtab.sh_offset + sect_hdr.sh_name;
|
|
670
|
|
671 bytes_read = ReadFromOffset (fd, &header_name, 64, name_offset);
|
|
672
|
|
673 VTV_ASSERT (bytes_read > 0);
|
|
674
|
|
675 if (memcmp (header_name, sect_name, name_len) == 0)
|
|
676 {
|
|
677 /* We found the section; get its load offset and
|
|
678 size. */
|
|
679 *sect_offset = sect_hdr.sh_addr;
|
|
680 if (!is_libvtv)
|
|
681 {
|
|
682 VTV_ASSERT (sect_hdr.sh_size - VTV_PAGE_SIZE >= 0);
|
|
683 *sect_len = sect_hdr.sh_size - VTV_PAGE_SIZE;
|
|
684 }
|
|
685 else
|
|
686 *sect_len = sect_hdr.sh_size;
|
|
687 found = true;
|
|
688 }
|
|
689 }
|
|
690 close (fd);
|
|
691 }
|
|
692 }
|
|
693
|
|
694 if (*sect_offset != 0 && *sect_len != 0)
|
|
695 {
|
|
696 /* Calculate the page location in memory, making sure the
|
|
697 address is page-aligned. */
|
|
698 ElfW (Addr) start_addr = (const ElfW (Addr)) info->dlpi_addr
|
|
699 + *sect_offset;
|
|
700 *sect_offset = start_addr & ~(VTV_PAGE_SIZE - 1);
|
|
701 *sect_len = *sect_len - 1;
|
|
702
|
|
703 /* Since we got this far, we must not have found these pages in
|
|
704 the cache, so add them to it. NOTE: We could get here either
|
|
705 while making everything read-only or while making everything
|
|
706 read-write. We will only update the cache if we get here on
|
|
707 a read-write (to make absolutely sure the cache is writable
|
|
708 -- also the read-write pass should come before the read-only
|
|
709 pass). */
|
|
710 if ((mprotect_flags & PROT_WRITE)
|
|
711 && num_cache_entries < MAX_ENTRIES)
|
|
712 {
|
|
713 vtv_sect_info_cache[num_cache_entries].dlpi_addr = info->dlpi_addr;
|
|
714 vtv_sect_info_cache[num_cache_entries].mp_low = *sect_offset;
|
|
715 vtv_sect_info_cache[num_cache_entries].mp_size = *sect_len;
|
|
716 num_cache_entries++;
|
|
717 }
|
|
718 }
|
|
719 }
|
|
720 #endif
|
|
721
|
|
722 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
723 /* This function is used to iterate over all loaded modules and searches
|
|
724 for a section called ".vtable_map_vars". The only interaction with
|
|
725 the binary file on disk of the module is to read section names in the
|
|
726 COFF string table. If the module contains a ".vtable_map_vars" section,
|
|
727 read section offset and size from the section header of the loaded module.
|
|
728 Call 'mprotect' on those pages, setting the protection either to
|
|
729 read-only or read-write, depending on what's in data.
|
|
730 The calls to change the protection occur in vtv_unprotect_vtable_vars
|
|
731 and vtv_protect_vtable_vars. */
|
|
732
|
|
733 static int
|
|
734 iterate_modules (void *data)
|
|
735 {
|
|
736 int * mprotect_flags = (int *) data;
|
|
737 off_t map_sect_offset = 0;
|
|
738 WORD map_sect_len = 0;
|
|
739 char buffer[1024];
|
|
740 const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;
|
|
741 HMODULE hMods[1024];
|
|
742 HANDLE hProcess;
|
|
743 DWORD cbNeeded;
|
|
744
|
|
745 hProcess = GetCurrentProcess ();
|
|
746
|
|
747 if (NULL == hProcess)
|
|
748 return 0;
|
|
749
|
|
750 if (EnumProcessModules (hProcess, hMods, sizeof (hMods), &cbNeeded))
|
|
751 {
|
|
752 /* Iterate over all loaded modules. */
|
|
753 for (unsigned int i = 0; i < (cbNeeded / sizeof (HMODULE)); i++)
|
|
754 {
|
|
755 char szModName[MAX_PATH];
|
|
756
|
|
757 if (GetModuleFileNameExA (hProcess, hMods[i], szModName,
|
|
758 sizeof (szModName)))
|
|
759 {
|
|
760 map_sect_offset = 0;
|
|
761 map_sect_len = 0;
|
|
762 read_section_offset_and_length (szModName,
|
|
763 (uintptr_t) hMods[i],
|
|
764 map_sect_name,
|
|
765 *mprotect_flags,
|
|
766 &map_sect_offset,
|
|
767 &map_sect_len);
|
|
768
|
|
769 if (debug_functions)
|
|
770 {
|
|
771 snprintf (buffer, sizeof(buffer),
|
|
772 " Looking at load module %s to change permissions to %s\n",
|
|
773 szModName,
|
|
774 (*mprotect_flags & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
|
|
775 log_memory_protection_data (buffer);
|
|
776 }
|
|
777
|
|
778 /* See if we actually found the section. */
|
|
779 if (map_sect_offset && map_sect_len)
|
|
780 {
|
|
781 unsigned long long start;
|
|
782 int result;
|
|
783
|
|
784 if (debug_functions)
|
|
785 {
|
|
786 snprintf (buffer, sizeof (buffer),
|
|
787 " (%s): Protecting %p to %p\n",
|
|
788 szModName,
|
|
789 (void *) map_sect_offset,
|
|
790 (void *) (map_sect_offset + map_sect_len));
|
|
791 log_memory_protection_data (buffer);
|
|
792 }
|
|
793
|
|
794 /* Change the protections on the pages for the section. */
|
|
795
|
|
796 start = get_cycle_count ();
|
|
797 result = mprotect ((void *) map_sect_offset, map_sect_len,
|
|
798 *mprotect_flags);
|
|
799 accumulate_cycle_count (&mprotect_cycles, start);
|
|
800 if (result == -1)
|
|
801 {
|
|
802 if (debug_functions)
|
|
803 {
|
|
804 snprintf (buffer, sizeof (buffer),
|
|
805 "Failed call to mprotect for %s error: ",
|
|
806 (*mprotect_flags & PROT_WRITE) ?
|
|
807 "READ/WRITE" : "READ-ONLY");
|
|
808 log_memory_protection_data (buffer);
|
|
809 perror(NULL);
|
|
810 }
|
|
811 VTV_error();
|
|
812 }
|
|
813 else
|
|
814 {
|
|
815 if (debug_functions)
|
|
816 {
|
|
817 snprintf (buffer, sizeof (buffer),
|
|
818 "mprotect'ed range [%p, %p]\n",
|
|
819 (void *) map_sect_offset,
|
|
820 (char *) map_sect_offset + map_sect_len);
|
|
821 log_memory_protection_data (buffer);
|
|
822 }
|
|
823 }
|
|
824 increment_num_calls (&num_calls_to_mprotect);
|
|
825 num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1)
|
|
826 / VTV_PAGE_SIZE;
|
|
827 continue;
|
|
828 }
|
|
829 }
|
|
830 }
|
|
831 }
|
|
832
|
|
833 CloseHandle(hProcess);
|
|
834
|
|
835 return 0;
|
|
836 }
|
|
837 #else
|
|
838 /* This is the callback function used by dl_iterate_phdr (which is
|
|
839 called from vtv_unprotect_vtable_vars and vtv_protect_vtable_vars).
|
|
840 It attempts to find the binary file on disk for the INFO record
|
|
841 that dl_iterate_phdr passes in; open the binary file, and read its
|
|
842 section header information. If the file contains a
|
|
843 ".vtable_map_vars" section, read the section offset and size. Use
|
|
844 the section offset and size, in conjunction with the data in INFO
|
|
845 to locate the pages in memory where the section is. Call
|
|
846 'mprotect' on those pages, setting the protection either to
|
|
847 read-only or read-write, depending on what's in DATA. */
|
|
848
|
|
849 static int
|
|
850 dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t, void *data)
|
|
851 {
|
|
852 int * mprotect_flags = (int *) data;
|
|
853 off_t map_sect_offset = 0;
|
|
854 ElfW (Word) map_sect_len = 0;
|
|
855 char buffer[1024];
|
|
856 char program_name[1024];
|
|
857 const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;
|
|
858
|
|
859 /* Check to see if this is the record for the Linux Virtual Dynamic
|
|
860 Shared Object (linux-vdso.so.1), which exists only in memory (and
|
|
861 therefore cannot be read from disk). */
|
|
862
|
|
863 if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
|
|
864 return 0;
|
|
865
|
|
866 if (strlen (info->dlpi_name) == 0
|
|
867 && info->dlpi_addr != 0)
|
|
868 return 0;
|
|
869
|
|
870 /* Get the name of the main executable. This may or may not include
|
|
871 arguments passed to the program. Find the first space, assume it
|
|
872 is the start of the argument list, and change it to a '\0'. */
|
|
873 #ifdef HAVE_GETEXECNAME
|
|
874 program_invocation_name = getexecname ();
|
|
875 #endif
|
|
876 snprintf (program_name, sizeof (program_name), program_invocation_name);
|
|
877
|
|
878 read_section_offset_and_length (info, map_sect_name, *mprotect_flags,
|
|
879 &map_sect_offset, &map_sect_len);
|
|
880
|
|
881 if (debug_functions)
|
|
882 {
|
|
883 snprintf (buffer, sizeof(buffer),
|
|
884 " Looking at load module %s to change permissions to %s\n",
|
|
885 ((strlen (info->dlpi_name) == 0) ? program_name
|
|
886 : info->dlpi_name),
|
|
887 (*mprotect_flags & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
|
|
888 log_memory_protection_data (buffer);
|
|
889 }
|
|
890
|
|
891 /* See if we actually found the section. */
|
|
892 if (map_sect_offset && map_sect_len)
|
|
893 {
|
|
894 unsigned long long start;
|
|
895 int result;
|
|
896
|
|
897 if (debug_functions)
|
|
898 {
|
|
899 snprintf (buffer, sizeof (buffer),
|
|
900 " (%s): Protecting %p to %p\n",
|
|
901 ((strlen (info->dlpi_name) == 0) ? program_name
|
|
902 : info->dlpi_name),
|
|
903 (void *) map_sect_offset,
|
|
904 (void *) (map_sect_offset + map_sect_len));
|
|
905 log_memory_protection_data (buffer);
|
|
906 }
|
|
907
|
|
908 /* Change the protections on the pages for the section. */
|
|
909
|
|
910 start = get_cycle_count ();
|
|
911 result = mprotect ((void *) map_sect_offset, map_sect_len,
|
|
912 *mprotect_flags);
|
|
913 accumulate_cycle_count (&mprotect_cycles, start);
|
|
914 if (result == -1)
|
|
915 {
|
|
916 if (debug_functions)
|
|
917 {
|
|
918 snprintf (buffer, sizeof (buffer),
|
|
919 "Failed call to mprotect for %s error: ",
|
|
920 (*mprotect_flags & PROT_WRITE) ?
|
|
921 "READ/WRITE" : "READ-ONLY");
|
|
922 log_memory_protection_data (buffer);
|
|
923 perror(NULL);
|
|
924 }
|
|
925 VTV_error();
|
|
926 }
|
|
927 else
|
|
928 {
|
|
929 if (debug_functions)
|
|
930 {
|
|
931 snprintf (buffer, sizeof (buffer),
|
|
932 "mprotect'ed range [%p, %p]\n",
|
|
933 (void *) map_sect_offset,
|
|
934 (char *) map_sect_offset + map_sect_len);
|
|
935 log_memory_protection_data (buffer);
|
|
936 }
|
|
937 }
|
|
938 increment_num_calls (&num_calls_to_mprotect);
|
|
939 num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1) / VTV_PAGE_SIZE;
|
|
940 }
|
|
941
|
|
942 return 0;
|
|
943 }
|
|
944 #endif
|
|
945
|
|
946 /* This function explicitly changes the protection (read-only or read-write)
|
|
947 on the vtv_sect_info_cache, which is used for speeding up look ups in the
|
|
948 function dl_iterate_phdr_callback. This data structure needs to be
|
|
949 explicitly made read-write before any calls to dl_iterate_phdr_callback,
|
|
950 because otherwise it may still be read-only when dl_iterate_phdr_callback
|
|
951 attempts to write to it.
|
|
952
|
|
953 More detailed explanation: dl_iterate_phdr_callback finds all the
|
|
954 .vtable_map_vars sections in all loaded objects (including the main program)
|
|
955 and (depending on where it was called from) either makes all the pages in the
|
|
956 sections read-write or read-only. The vtv_sect_info_cache should be in the
|
|
957 .vtable_map_vars section for libstdc++.so, which means that normally it would
|
|
958 be read-only until libstdc++.so is processed by dl_iterate_phdr_callback
|
|
959 (on the read-write pass), after which it will be writable. But if any loaded
|
|
960 object gets processed before libstdc++.so, it will attempt to update the
|
|
961 data cache, which will still be read-only, and cause a seg fault. Hence
|
|
962 we need a special function, called before dl_iterate_phdr_callback, that
|
|
963 will make the data cache writable. */
|
|
964
|
|
965 static void
|
|
966 change_protections_on_phdr_cache (int protection_flag)
|
|
967 {
|
|
968 char * low_address = (char *) &(vtv_sect_info_cache);
|
|
969 size_t cache_size = MAX_ENTRIES * sizeof (struct sect_hdr_data);
|
|
970
|
|
971 low_address = (char *) ((uintptr_t) low_address & ~(VTV_PAGE_SIZE - 1));
|
|
972
|
|
973 if (mprotect ((void *) low_address, cache_size, protection_flag) == -1)
|
|
974 VTV_error ();
|
|
975 }
|
|
976
|
|
977 /* Unprotect all the vtable map vars and other side data that is used
|
|
978 to keep the core hash_map data. All of these data have been put
|
|
979 into relro sections */
|
|
980
|
|
981 static void
|
|
982 vtv_unprotect_vtable_vars (void)
|
|
983 {
|
|
984 int mprotect_flags;
|
|
985
|
|
986 mprotect_flags = PROT_READ | PROT_WRITE;
|
|
987 change_protections_on_phdr_cache (mprotect_flags);
|
|
988 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
989 iterate_modules ((void *) &mprotect_flags);
|
|
990 #else
|
|
991 dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mprotect_flags);
|
|
992 #endif
|
|
993 }
|
|
994
|
|
995 /* Protect all the vtable map vars and other side data that is used
|
|
996 to keep the core hash_map data. All of these data have been put
|
|
997 into relro sections */
|
|
998
|
|
999 static void
|
|
1000 vtv_protect_vtable_vars (void)
|
|
1001 {
|
|
1002 int mprotect_flags;
|
|
1003
|
|
1004 mprotect_flags = PROT_READ;
|
|
1005 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
1006 iterate_modules ((void *) &mprotect_flags);
|
|
1007 #else
|
|
1008 dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mprotect_flags);
|
|
1009 #endif
|
|
1010 change_protections_on_phdr_cache (mprotect_flags);
|
|
1011 }
|
|
1012
|
|
1013 #ifndef __GTHREAD_MUTEX_INIT
|
|
1014 static void
|
|
1015 initialize_change_permissions_mutexes ()
|
|
1016 {
|
|
1017 __GTHREAD_MUTEX_INIT_FUNCTION (&change_permissions_lock);
|
|
1018 }
|
|
1019 #endif
|
|
1020
|
|
1021 /* Variables needed for getting the statistics about the hashtable set. */
|
|
1022 #if HASHTABLE_STATS
|
|
1023 _AtomicStatCounter stat_contains = 0;
|
|
1024 _AtomicStatCounter stat_insert = 0;
|
|
1025 _AtomicStatCounter stat_resize = 0;
|
|
1026 _AtomicStatCounter stat_create = 0;
|
|
1027 _AtomicStatCounter stat_probes_in_non_trivial_set = 0;
|
|
1028 _AtomicStatCounter stat_contains_size0 = 0;
|
|
1029 _AtomicStatCounter stat_contains_size1 = 0;
|
|
1030 _AtomicStatCounter stat_contains_size2 = 0;
|
|
1031 _AtomicStatCounter stat_contains_size3 = 0;
|
|
1032 _AtomicStatCounter stat_contains_size4 = 0;
|
|
1033 _AtomicStatCounter stat_contains_size5 = 0;
|
|
1034 _AtomicStatCounter stat_contains_size6 = 0;
|
|
1035 _AtomicStatCounter stat_contains_size7 = 0;
|
|
1036 _AtomicStatCounter stat_contains_size8 = 0;
|
|
1037 _AtomicStatCounter stat_contains_size9 = 0;
|
|
1038 _AtomicStatCounter stat_contains_size10 = 0;
|
|
1039 _AtomicStatCounter stat_contains_size11 = 0;
|
|
1040 _AtomicStatCounter stat_contains_size12 = 0;
|
|
1041 _AtomicStatCounter stat_contains_size13_or_more = 0;
|
|
1042 _AtomicStatCounter stat_contains_sizes = 0;
|
|
1043 _AtomicStatCounter stat_grow_from_size0_to_1 = 0;
|
|
1044 _AtomicStatCounter stat_grow_from_size1_to_2 = 0;
|
|
1045 _AtomicStatCounter stat_double_the_number_of_buckets = 0;
|
|
1046 _AtomicStatCounter stat_insert_found_hash_collision = 0;
|
|
1047 _AtomicStatCounter stat_contains_in_non_trivial_set = 0;
|
|
1048 _AtomicStatCounter stat_insert_key_that_was_already_present = 0;
|
|
1049 #endif
|
|
1050 /* Record statistics about the hash table sets, for debugging. */
|
|
1051
|
|
1052 static void
|
|
1053 log_set_stats (void)
|
|
1054 {
|
|
1055 #if HASHTABLE_STATS
|
|
1056 if (set_log_fd == -1)
|
|
1057 set_log_fd = __vtv_open_log ("vtv_set_stats.log");
|
|
1058
|
|
1059 __vtv_add_to_log (set_log_fd, "---\n%s\n",
|
|
1060 insert_only_hash_tables_stats().c_str());
|
|
1061 #endif
|
|
1062 }
|
|
1063
|
|
1064 /* Change the permissions on all the pages we have allocated for the
|
|
1065 data sets and all the ".vtable_map_var" sections in memory (which
|
|
1066 contain our vtable map variables). PERM indicates whether to make
|
|
1067 the permissions read-only or read-write. */
|
|
1068
|
|
1069 extern "C" /* This is only being applied to __VLTChangePermission*/
|
|
1070 void
|
|
1071 __VLTChangePermission (int perm)
|
|
1072 {
|
|
1073 if (debug_functions)
|
|
1074 {
|
|
1075 if (perm == __VLTP_READ_WRITE)
|
|
1076 fprintf (stdout, "Changing VLT permissions to Read-Write.\n");
|
|
1077 else if (perm == __VLTP_READ_ONLY)
|
|
1078 fprintf (stdout, "Changing VLT permissions to Read-Only.\n");
|
|
1079
|
|
1080 else
|
|
1081 fprintf (stdout, "Unrecognized permissions value: %d\n", perm);
|
|
1082 }
|
|
1083
|
|
1084 #ifndef __GTHREAD_MUTEX_INIT
|
|
1085 static __gthread_once_t mutex_once VTV_PROTECTED_VAR = __GTHREAD_ONCE_INIT;
|
|
1086
|
|
1087 __gthread_once (&mutex_once, initialize_change_permissions_mutexes);
|
|
1088 #endif
|
|
1089
|
|
1090 /* Ordering of these unprotect/protect calls is very important.
|
|
1091 You first need to unprotect all the map vars and side
|
|
1092 structures before you do anything with the core data
|
|
1093 structures (hash_maps) */
|
|
1094
|
|
1095 if (perm == __VLTP_READ_WRITE)
|
|
1096 {
|
|
1097 /* TODO: Need to revisit this code for dlopen. It most probably
|
|
1098 is not unlocking the protected vtable vars after for load
|
|
1099 module that is not the first load module. */
|
|
1100 __gthread_mutex_lock (&change_permissions_lock);
|
|
1101
|
|
1102 vtv_unprotect_vtable_vars ();
|
|
1103 __vtv_malloc_init ();
|
|
1104 __vtv_malloc_unprotect ();
|
|
1105
|
|
1106 }
|
|
1107 else if (perm == __VLTP_READ_ONLY)
|
|
1108 {
|
|
1109 if (debug_hash)
|
|
1110 log_set_stats();
|
|
1111
|
|
1112 __vtv_malloc_protect ();
|
|
1113 vtv_protect_vtable_vars ();
|
|
1114
|
|
1115 __gthread_mutex_unlock (&change_permissions_lock);
|
|
1116 }
|
|
1117 }
|
|
1118
|
|
1119 /* This is the memory allocator used to create the hash table that
|
|
1120 maps from vtable map variable name to the data set that vtable map
|
|
1121 variable should point to. This is part of our vtable map variable
|
|
1122 symbol resolution, which is necessary because the same vtable map
|
|
1123 variable may be created by multiple compilation units and we need a
|
|
1124 method to make sure that all vtable map variables for a particular
|
|
1125 class point to the same data set at runtime. */
|
|
1126
|
|
1127 struct insert_only_hash_map_allocator
|
|
1128 {
|
|
1129 /* N is the number of bytes to allocate. */
|
|
1130 void *
|
|
1131 alloc (size_t n) const
|
|
1132 {
|
|
1133 return __vtv_malloc (n);
|
|
1134 }
|
|
1135
|
|
1136 /* P points to the memory to be deallocated; N is the number of
|
|
1137 bytes to deallocate. */
|
|
1138 void
|
|
1139 dealloc (void *p, size_t) const
|
|
1140 {
|
|
1141 __vtv_free (p);
|
|
1142 }
|
|
1143 };
|
|
1144
|
|
1145 /* Explicitly instantiate this class since this file is compiled with
|
|
1146 -fno-implicit-templates. These are for the hash table that is used
|
|
1147 to do vtable map variable symbol resolution. */
|
|
1148 template class insert_only_hash_map <vtv_set_handle *,
|
|
1149 insert_only_hash_map_allocator >;
|
|
1150 typedef insert_only_hash_map <vtv_set_handle *,
|
|
1151 insert_only_hash_map_allocator > s2s;
|
|
1152 typedef const s2s::key_type vtv_symbol_key;
|
|
1153
|
|
1154 static s2s * vtv_symbol_unification_map VTV_PROTECTED_VAR = NULL;
|
|
1155
|
|
1156 const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
|
|
1157
|
|
1158 /* In the case where a vtable map variable is the only instance of the
|
|
1159 variable we have seen, it points directly to the set of valid
|
|
1160 vtable pointers. All subsequent instances of the 'same' vtable map
|
|
1161 variable point to the first vtable map variable. This function,
|
|
1162 given a vtable map variable PTR, checks a bit to see whether it's
|
|
1163 pointing directly to the data set or to the first vtable map
|
|
1164 variable. */
|
|
1165
|
|
1166 static inline bool
|
|
1167 is_set_handle_handle (void * ptr)
|
|
1168 {
|
|
1169 return ((uintptr_t) ptr & SET_HANDLE_HANDLE_BIT)
|
|
1170 == SET_HANDLE_HANDLE_BIT;
|
|
1171 }
|
|
1172
|
|
1173 /* Returns the actual pointer value of a vtable map variable, PTR (see
|
|
1174 comments for is_set_handle_handle for more details). */
|
|
1175
|
|
1176 static inline vtv_set_handle *
|
|
1177 ptr_from_set_handle_handle (void * ptr)
|
|
1178 {
|
|
1179 return (vtv_set_handle *) ((uintptr_t) ptr & ~SET_HANDLE_HANDLE_BIT);
|
|
1180 }
|
|
1181
|
|
1182 /* Given a vtable map variable, PTR, this function sets the bit that
|
|
1183 says this is the second (or later) instance of a vtable map
|
|
1184 variable. */
|
|
1185
|
|
1186 static inline vtv_set_handle_handle
|
|
1187 set_handle_handle (vtv_set_handle * ptr)
|
|
1188 {
|
|
1189 return (vtv_set_handle_handle) ((uintptr_t) ptr | SET_HANDLE_HANDLE_BIT);
|
|
1190 }
|
|
1191
|
|
1192 static inline void
|
|
1193 register_set_common (void **set_handle_ptr, size_t num_args,
|
|
1194 void **vtable_ptr_array, bool debug)
|
|
1195 {
|
|
1196 /* Now figure out what pointer to use for the set pointer, for the
|
|
1197 inserts. */
|
|
1198 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1199
|
|
1200 if (debug)
|
|
1201 VTV_DEBUG_ASSERT (vtv_symbol_unification_map != NULL);
|
|
1202
|
|
1203 if (!is_set_handle_handle (*set_handle_ptr))
|
|
1204 handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1205 else
|
|
1206 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
|
|
1207
|
|
1208 /* Now we've got the set and it's initialized, add the vtable
|
|
1209 pointers. */
|
|
1210 for (size_t index = 0; index < num_args; ++index)
|
|
1211 {
|
|
1212 int_vptr vtbl_ptr = (int_vptr) vtable_ptr_array[index];
|
|
1213 vtv_sets::insert (vtbl_ptr, handle_ptr);
|
|
1214 }
|
|
1215 }
|
|
1216
|
|
1217 static inline void
|
|
1218 register_pair_common (void **set_handle_ptr, const void *vtable_ptr,
|
|
1219 const char *set_symbol_name, const char *vtable_name,
|
|
1220 bool debug)
|
|
1221 {
|
|
1222 /* Now we've got the set and it's initialized, add the vtable
|
|
1223 pointer (assuming that it's not NULL...It may be NULL, as we may
|
|
1224 have called this function merely to initialize the set
|
|
1225 pointer). */
|
|
1226 int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
|
|
1227 if (vtbl_ptr)
|
|
1228 {
|
|
1229 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1230 if (debug)
|
|
1231 VTV_DEBUG_ASSERT (vtv_symbol_unification_map != NULL);
|
|
1232 if (!is_set_handle_handle (*set_handle_ptr))
|
|
1233 handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1234 else
|
|
1235 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
|
|
1236
|
|
1237 vtv_sets::insert (vtbl_ptr, handle_ptr);
|
|
1238 }
|
|
1239
|
|
1240 if (debug && debug_init)
|
|
1241 {
|
|
1242 if (init_log_fd == -1)
|
|
1243 init_log_fd = __vtv_open_log("vtv_init.log");
|
|
1244
|
|
1245 __vtv_add_to_log(init_log_fd,
|
|
1246 "Registered %s : %s (%p) 2 level deref = %s\n",
|
|
1247 set_symbol_name, vtable_name, vtbl_ptr,
|
|
1248 is_set_handle_handle(*set_handle_ptr) ? "yes" : "no" );
|
|
1249 }
|
|
1250 }
|
|
1251
|
|
1252 /* This routine initializes a set handle to a vtable set. It makes
|
|
1253 sure that there is only one set handle for a particular set by
|
|
1254 using a map from set name to pointer to set handle. Since there
|
|
1255 will be multiple copies of the pointer to the set handle (one per
|
|
1256 compilation unit that uses it), it makes sure to initialize all the
|
|
1257 pointers to the set handle so that the set handle is unique. To
|
|
1258 make this a little more efficient and avoid a level of indirection
|
|
1259 in some cases, the first pointer to handle for a particular handle
|
|
1260 becomes the handle itself and the other pointers will point to the
|
|
1261 set handle. This is the debug version of this function, so it
|
|
1262 outputs extra debugging messages and logging. SET_HANDLE_PTR is
|
|
1263 the address of the vtable map variable, SET_SYMBOL_KEY is the hash
|
|
1264 table key (containing the name of the map variable and the hash
|
|
1265 value) and SIZE_HINT is a guess for the best initial size for the
|
|
1266 set of vtable pointers that SET_HANDLE_POINTER will point to. */
|
|
1267
|
|
1268 static inline void
|
|
1269 init_set_symbol_debug (void **set_handle_ptr, const void *set_symbol_key,
|
|
1270 size_t size_hint)
|
|
1271 {
|
|
1272 VTV_DEBUG_ASSERT (set_handle_ptr);
|
|
1273
|
|
1274 if (vtv_symbol_unification_map == NULL)
|
|
1275 {
|
|
1276 /* TODO: For now we have chosen 1024, but we need to come up with a
|
|
1277 better initial size for this. */
|
|
1278 vtv_symbol_unification_map = s2s::create (1024);
|
|
1279 VTV_DEBUG_ASSERT(vtv_symbol_unification_map);
|
|
1280 }
|
|
1281
|
|
1282 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1283 vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
|
|
1284
|
|
1285 const s2s::value_type * map_value_ptr =
|
|
1286 vtv_symbol_unification_map->get (symbol_key_ptr);
|
|
1287 char buffer[200];
|
|
1288 if (map_value_ptr == NULL)
|
|
1289 {
|
|
1290 if (*handle_ptr != NULL)
|
|
1291 {
|
|
1292 snprintf (buffer, sizeof (buffer),
|
|
1293 "*** Found non-NULL local set ptr %p missing for symbol"
|
|
1294 " %.*s",
|
|
1295 *handle_ptr, symbol_key_ptr->n, symbol_key_ptr->bytes);
|
|
1296 __vtv_log_verification_failure (buffer, true);
|
|
1297 VTV_DEBUG_ASSERT (0);
|
|
1298 }
|
|
1299 }
|
|
1300 else if (*handle_ptr != NULL &&
|
|
1301 (handle_ptr != *map_value_ptr &&
|
|
1302 ptr_from_set_handle_handle (*handle_ptr) != *map_value_ptr))
|
|
1303 {
|
|
1304 VTV_DEBUG_ASSERT (*map_value_ptr != NULL);
|
|
1305 snprintf (buffer, sizeof(buffer),
|
|
1306 "*** Found diffence between local set ptr %p and set ptr %p"
|
|
1307 "for symbol %.*s",
|
|
1308 *handle_ptr, *map_value_ptr,
|
|
1309 symbol_key_ptr->n, symbol_key_ptr->bytes);
|
|
1310 __vtv_log_verification_failure (buffer, true);
|
|
1311 VTV_DEBUG_ASSERT (0);
|
|
1312 }
|
|
1313 else if (*handle_ptr == NULL)
|
|
1314 {
|
|
1315 /* Execution should not reach this point. */
|
|
1316 }
|
|
1317
|
|
1318 if (*handle_ptr != NULL)
|
|
1319 {
|
|
1320 if (!is_set_handle_handle (*set_handle_ptr))
|
|
1321 handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1322 else
|
|
1323 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
|
|
1324 vtv_sets::resize (size_hint, handle_ptr);
|
|
1325 return;
|
|
1326 }
|
|
1327
|
|
1328 VTV_DEBUG_ASSERT (*handle_ptr == NULL);
|
|
1329 if (map_value_ptr != NULL)
|
|
1330 {
|
|
1331 if (*map_value_ptr == handle_ptr)
|
|
1332 vtv_sets::resize (size_hint, *map_value_ptr);
|
|
1333 else
|
|
1334 {
|
|
1335 /* The one level handle to the set already exists. So, we
|
|
1336 are adding one level of indirection here and we will
|
|
1337 store a pointer to the one level handle here. */
|
|
1338
|
|
1339 vtv_set_handle_handle * handle_handle_ptr =
|
|
1340 (vtv_set_handle_handle *)handle_ptr;
|
|
1341 *handle_handle_ptr = set_handle_handle(*map_value_ptr);
|
|
1342 VTV_DEBUG_ASSERT(*handle_handle_ptr != NULL);
|
|
1343
|
|
1344 /* The handle can itself be NULL if the set has only
|
|
1345 been initiazlied with size hint == 1. */
|
|
1346 vtv_sets::resize (size_hint, *map_value_ptr);
|
|
1347 }
|
|
1348 }
|
|
1349 else
|
|
1350 {
|
|
1351 /* We will create a new set. So, in this case handle_ptr is the
|
|
1352 one level pointer to the set handle. Create copy of map name
|
|
1353 in case the memory where this comes from gets unmapped by
|
|
1354 dlclose. */
|
|
1355 size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
|
|
1356 void *map_key = __vtv_malloc (map_key_len);
|
|
1357
|
|
1358 memcpy (map_key, symbol_key_ptr, map_key_len);
|
|
1359
|
|
1360 s2s::value_type *value_ptr;
|
|
1361 vtv_symbol_unification_map =
|
|
1362 vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
|
|
1363 &value_ptr);
|
|
1364 *value_ptr = handle_ptr;
|
|
1365
|
|
1366 /* TODO: We should verify the return value. */
|
|
1367 vtv_sets::create (size_hint, handle_ptr);
|
|
1368 VTV_DEBUG_ASSERT (size_hint <= 1 || *handle_ptr != NULL);
|
|
1369 }
|
|
1370
|
|
1371 if (debug_init)
|
|
1372 {
|
|
1373 if (init_log_fd == -1)
|
|
1374 init_log_fd = __vtv_open_log ("vtv_init.log");
|
|
1375
|
|
1376 __vtv_add_to_log (init_log_fd,
|
|
1377 "Init handle:%p for symbol:%.*s hash:%u size_hint:%lu"
|
|
1378 "number of symbols:%lu \n",
|
|
1379 set_handle_ptr, symbol_key_ptr->n,
|
|
1380 symbol_key_ptr->bytes, symbol_key_ptr->hash, size_hint,
|
|
1381 vtv_symbol_unification_map->size ());
|
|
1382 }
|
|
1383 }
|
|
1384
|
|
1385
|
|
1386 /* This routine initializes a set handle to a vtable set. It makes
|
|
1387 sure that there is only one set handle for a particular set by
|
|
1388 using a map from set name to pointer to set handle. Since there
|
|
1389 will be multiple copies of the pointer to the set handle (one per
|
|
1390 compilation unit that uses it), it makes sure to initialize all the
|
|
1391 pointers to the set handle so that the set handle is unique. To
|
|
1392 make this a little more efficient and avoid a level of indirection
|
|
1393 in some cases, the first pointer to handle for a particular handle
|
|
1394 becomes the handle itself and the other pointers will point to the
|
|
1395 set handle. This is the debug version of this function, so it
|
|
1396 outputs extra debugging messages and logging. SET_HANDLE_PTR is
|
|
1397 the address of the vtable map variable, SET_SYMBOL_KEY is the hash
|
|
1398 table key (containing the name of the map variable and the hash
|
|
1399 value) and SIZE_HINT is a guess for the best initial size for the
|
|
1400 set of vtable pointers that SET_HANDLE_POINTER will point to. */
|
|
1401
|
|
1402 void
|
|
1403 __VLTRegisterSetDebug (void **set_handle_ptr, const void *set_symbol_key,
|
|
1404 size_t size_hint, size_t num_args,
|
|
1405 void **vtable_ptr_array)
|
|
1406 {
|
|
1407 unsigned long long start = get_cycle_count ();
|
|
1408 increment_num_calls (&num_calls_to_regset);
|
|
1409
|
|
1410 VTV_DEBUG_ASSERT(set_handle_ptr != NULL);
|
|
1411 init_set_symbol_debug (set_handle_ptr, set_symbol_key, size_hint);
|
|
1412
|
|
1413 register_set_common (set_handle_ptr, num_args, vtable_ptr_array, true);
|
|
1414
|
|
1415 accumulate_cycle_count (®set_cycles, start);
|
|
1416 }
|
|
1417
|
|
1418 /* This function takes a the address of a vtable map variable
|
|
1419 (SET_HANDLE_PTR), a VTABLE_PTR to add to the data set, the name of
|
|
1420 the vtable map variable (SET_SYMBOL_NAME) and the name of the
|
|
1421 vtable (VTABLE_NAME) being pointed to. If the vtable map variable
|
|
1422 is NULL it creates a new data set and initializes the variable,
|
|
1423 otherwise it uses our symbol unification to find the right data
|
|
1424 set; in either case it then adds the vtable pointer to the set.
|
|
1425 The other two parameters are used for debugging information. */
|
|
1426
|
|
1427 void
|
|
1428 __VLTRegisterPairDebug (void **set_handle_ptr, const void *set_symbol_key,
|
|
1429 size_t size_hint, const void *vtable_ptr,
|
|
1430 const char *set_symbol_name, const char *vtable_name)
|
|
1431 {
|
|
1432 unsigned long long start = get_cycle_count ();
|
|
1433 increment_num_calls (&num_calls_to_regpair);
|
|
1434
|
|
1435 VTV_DEBUG_ASSERT(set_handle_ptr != NULL);
|
|
1436 init_set_symbol_debug (set_handle_ptr, set_symbol_key, size_hint);
|
|
1437
|
|
1438 register_pair_common (set_handle_ptr, vtable_ptr, set_symbol_name, vtable_name,
|
|
1439 true);
|
|
1440
|
|
1441 accumulate_cycle_count (®pair_cycles, start);
|
|
1442 }
|
|
1443
|
|
1444
|
|
1445 /* This is the debug version of the verification function. It takes
|
|
1446 the address of a vtable map variable (SET_HANDLE_PTR) and a
|
|
1447 VTABLE_PTR to validate, as well as the name of the vtable map
|
|
1448 variable (SET_SYMBOL_NAME) and VTABLE_NAME, which are used for
|
|
1449 debugging messages. It checks to see if VTABLE_PTR is in the set
|
|
1450 pointed to by SET_HANDLE_PTR. If so, it returns VTABLE_PTR,
|
|
1451 otherwise it calls __vtv_verify_fail, which usually logs error
|
|
1452 messages and calls abort. */
|
|
1453
|
|
1454 const void *
|
|
1455 __VLTVerifyVtablePointerDebug (void **set_handle_ptr, const void *vtable_ptr,
|
|
1456 const char *set_symbol_name,
|
|
1457 const char *vtable_name)
|
|
1458 {
|
|
1459 unsigned long long start = get_cycle_count ();
|
|
1460 VTV_DEBUG_ASSERT (set_handle_ptr != NULL && *set_handle_ptr != NULL);
|
|
1461 int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
|
|
1462
|
|
1463 increment_num_calls (&num_calls_to_verify_vtable);
|
|
1464 vtv_set_handle *handle_ptr;
|
|
1465 if (!is_set_handle_handle (*set_handle_ptr))
|
|
1466 handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1467 else
|
|
1468 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
|
|
1469
|
|
1470 if (vtv_sets::contains (vtbl_ptr, handle_ptr))
|
|
1471 {
|
|
1472 if (debug_verify_vtable)
|
|
1473 {
|
|
1474 if (verify_vtable_log_fd == -1)
|
|
1475 __vtv_open_log ("vtv_verify_vtable.log");
|
|
1476 __vtv_add_to_log (verify_vtable_log_fd,
|
|
1477 "Verified %s %s value = %p\n",
|
|
1478 set_symbol_name, vtable_name, vtable_ptr);
|
|
1479 }
|
|
1480 }
|
|
1481 else
|
|
1482 {
|
|
1483 /* We failed to find the vtable pointer in the set of valid
|
|
1484 pointers. Log the error data and call the failure
|
|
1485 function. */
|
|
1486 snprintf (debug_log_message, sizeof (debug_log_message),
|
|
1487 "Looking for %s in %s\n", vtable_name, set_symbol_name);
|
|
1488 __vtv_verify_fail_debug (set_handle_ptr, vtable_ptr, debug_log_message);
|
|
1489
|
|
1490 /* Normally __vtv_verify_fail_debug will call abort, so we won't
|
|
1491 execute the return below. If we get this far, the assumption
|
|
1492 is that the programmer has replaced __vtv_verify_fail_debug
|
|
1493 with some kind of secondary verification AND this secondary
|
|
1494 verification succeeded, so the vtable pointer is valid. */
|
|
1495 }
|
|
1496 accumulate_cycle_count (&verify_vtable_cycles, start);
|
|
1497
|
|
1498 return vtable_ptr;
|
|
1499 }
|
|
1500
|
|
1501 /* This routine initializes a set handle to a vtable set. It makes
|
|
1502 sure that there is only one set handle for a particular set by
|
|
1503 using a map from set name to pointer to set handle. Since there
|
|
1504 will be multiple copies of the pointer to the set handle (one per
|
|
1505 compilation unit that uses it), it makes sure to initialize all the
|
|
1506 pointers to the set handle so that the set handle is unique. To
|
|
1507 make this a little more efficient and avoid a level of indirection
|
|
1508 in some cases, the first pointer to handle for a particular handle
|
|
1509 becomes the handle itself and the other pointers will point to the
|
|
1510 set handle. SET_HANDLE_PTR is the address of the vtable map
|
|
1511 variable, SET_SYMBOL_KEY is the hash table key (containing the name
|
|
1512 of the map variable and the hash value) and SIZE_HINT is a guess
|
|
1513 for the best initial size for the set of vtable pointers that
|
|
1514 SET_HANDLE_POINTER will point to.*/
|
|
1515
|
|
1516 static inline void
|
|
1517 init_set_symbol (void **set_handle_ptr, const void *set_symbol_key,
|
|
1518 size_t size_hint)
|
|
1519 {
|
|
1520 vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1521
|
|
1522 if (*handle_ptr != NULL)
|
|
1523 {
|
|
1524 if (!is_set_handle_handle (*set_handle_ptr))
|
|
1525 handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1526 else
|
|
1527 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
|
|
1528 vtv_sets::resize (size_hint, handle_ptr);
|
|
1529 return;
|
|
1530 }
|
|
1531
|
|
1532 if (vtv_symbol_unification_map == NULL)
|
|
1533 vtv_symbol_unification_map = s2s::create (1024);
|
|
1534
|
|
1535 vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
|
|
1536 const s2s::value_type *map_value_ptr =
|
|
1537 vtv_symbol_unification_map->get (symbol_key_ptr);
|
|
1538
|
|
1539 if (map_value_ptr != NULL)
|
|
1540 {
|
|
1541 if (*map_value_ptr == handle_ptr)
|
|
1542 vtv_sets::resize (size_hint, *map_value_ptr);
|
|
1543 else
|
|
1544 {
|
|
1545 /* The one level handle to the set already exists. So, we
|
|
1546 are adding one level of indirection here and we will
|
|
1547 store a pointer to the one level pointer here. */
|
|
1548 vtv_set_handle_handle *handle_handle_ptr =
|
|
1549 (vtv_set_handle_handle *) handle_ptr;
|
|
1550 *handle_handle_ptr = set_handle_handle (*map_value_ptr);
|
|
1551 vtv_sets::resize (size_hint, *map_value_ptr);
|
|
1552 }
|
|
1553 }
|
|
1554 else
|
|
1555 {
|
|
1556 /* We will create a new set. So, in this case handle_ptr is the
|
|
1557 one level pointer to the set handle. Create copy of map name
|
|
1558 in case the memory where this comes from gets unmapped by
|
|
1559 dlclose. */
|
|
1560 size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
|
|
1561 void * map_key = __vtv_malloc (map_key_len);
|
|
1562 memcpy (map_key, symbol_key_ptr, map_key_len);
|
|
1563
|
|
1564 s2s::value_type * value_ptr;
|
|
1565 vtv_symbol_unification_map =
|
|
1566 vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
|
|
1567 &value_ptr);
|
|
1568
|
|
1569 *value_ptr = handle_ptr;
|
|
1570
|
|
1571 /* TODO: We should verify the return value. */
|
|
1572 vtv_sets::create (size_hint, handle_ptr);
|
|
1573 }
|
|
1574 }
|
|
1575
|
|
1576 /* This routine initializes a set handle to a vtable set. It makes
|
|
1577 sure that there is only one set handle for a particular set by
|
|
1578 using a map from set name to pointer to set handle. Since there
|
|
1579 will be multiple copies of the pointer to the set handle (one per
|
|
1580 compilation unit that uses it), it makes sure to initialize all the
|
|
1581 pointers to the set handle so that the set handle is unique. To
|
|
1582 make this a little more efficient and avoid a level of indirection
|
|
1583 in some cases, the first pointer to handle for a particular handle
|
|
1584 becomes the handle itself and the other pointers will point to the
|
|
1585 set handle. SET_HANDLE_PTR is the address of the vtable map
|
|
1586 variable, SET_SYMBOL_KEY is the hash table key (containing the name
|
|
1587 of the map variable and the hash value) and SIZE_HINT is a guess
|
|
1588 for the best initial size for the set of vtable pointers that
|
|
1589 SET_HANDLE_POINTER will point to.*/
|
|
1590
|
|
1591
|
|
1592 void
|
|
1593 __VLTRegisterSet (void **set_handle_ptr, const void *set_symbol_key,
|
|
1594 size_t size_hint, size_t num_args, void **vtable_ptr_array)
|
|
1595 {
|
|
1596 unsigned long long start = get_cycle_count ();
|
|
1597 increment_num_calls (&num_calls_to_regset);
|
|
1598
|
|
1599 init_set_symbol (set_handle_ptr, set_symbol_key, size_hint);
|
|
1600 register_set_common (set_handle_ptr, num_args, vtable_ptr_array, false);
|
|
1601
|
|
1602 accumulate_cycle_count (®set_cycles, start);
|
|
1603 }
|
|
1604
|
|
1605
|
|
1606
|
|
1607 /* This function takes a the address of a vtable map variable
|
|
1608 (SET_HANDLE_PTR) and a VTABLE_PTR. If the vtable map variable is
|
|
1609 NULL it creates a new data set and initializes the variable,
|
|
1610 otherwise it uses our symbol unification to find the right data
|
|
1611 set; in either case it then adds the vtable pointer to the set. */
|
|
1612
|
|
1613 void
|
|
1614 __VLTRegisterPair (void **set_handle_ptr, const void *set_symbol_key,
|
|
1615 size_t size_hint, const void *vtable_ptr)
|
|
1616 {
|
|
1617 unsigned long long start = get_cycle_count ();
|
|
1618 increment_num_calls (&num_calls_to_regpair);
|
|
1619
|
|
1620 init_set_symbol (set_handle_ptr, set_symbol_key, size_hint);
|
|
1621 register_pair_common (set_handle_ptr, vtable_ptr, NULL, NULL, false);
|
|
1622
|
|
1623 accumulate_cycle_count (®pair_cycles, start);
|
|
1624 }
|
|
1625
|
|
1626 /* This is the main verification function. It takes the address of a
|
|
1627 vtable map variable (SET_HANDLE_PTR) and a VTABLE_PTR to validate.
|
|
1628 It checks to see if VTABLE_PTR is in the set pointed to by
|
|
1629 SET_HANDLE_PTR. If so, it returns VTABLE_PTR, otherwise it calls
|
|
1630 __vtv_verify_fail, which usually logs error messages and calls
|
|
1631 abort. Since this function gets called VERY frequently, it is
|
|
1632 important for it to be as efficient as possible. */
|
|
1633
|
|
1634 const void *
|
|
1635 __VLTVerifyVtablePointer (void ** set_handle_ptr, const void * vtable_ptr)
|
|
1636 {
|
|
1637 unsigned long long start = get_cycle_count ();
|
|
1638 int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
|
|
1639
|
|
1640 vtv_set_handle *handle_ptr;
|
|
1641 increment_num_calls (&num_calls_to_verify_vtable);
|
|
1642 if (!is_set_handle_handle (*set_handle_ptr))
|
|
1643 handle_ptr = (vtv_set_handle *) set_handle_ptr;
|
|
1644 else
|
|
1645 handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
|
|
1646
|
|
1647 if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
|
|
1648 {
|
|
1649 __vtv_verify_fail ((void **) handle_ptr, vtable_ptr);
|
|
1650 /* Normally __vtv_verify_fail will call abort, so we won't
|
|
1651 execute the return below. If we get this far, the assumption
|
|
1652 is that the programmer has replaced __vtv_verify_fail with
|
|
1653 some kind of secondary verification AND this secondary
|
|
1654 verification succeeded, so the vtable pointer is valid. */
|
|
1655 }
|
|
1656 accumulate_cycle_count (&verify_vtable_cycles, start);
|
|
1657
|
|
1658 return vtable_ptr;
|
|
1659 }
|
|
1660
|
|
1661 static int page_count_2 = 0;
|
|
1662
|
|
1663 #if !defined (__CYGWIN__) && !defined (__MINGW32__)
|
|
1664 static int
|
|
1665 dl_iterate_phdr_count_pages (struct dl_phdr_info *info,
|
|
1666 size_t unused __attribute__ ((__unused__)),
|
|
1667 void *data)
|
|
1668 {
|
|
1669 int *mprotect_flags = (int *) data;
|
|
1670 off_t map_sect_offset = 0;
|
|
1671 ElfW (Word) map_sect_len = 0;
|
|
1672 const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;
|
|
1673
|
|
1674 /* Check to see if this is the record for the Linux Virtual Dynamic
|
|
1675 Shared Object (linux-vdso.so.1), which exists only in memory (and
|
|
1676 therefore cannot be read from disk). */
|
|
1677
|
|
1678 if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
|
|
1679 return 0;
|
|
1680
|
|
1681 if (strlen (info->dlpi_name) == 0
|
|
1682 && info->dlpi_addr != 0)
|
|
1683 return 0;
|
|
1684
|
|
1685 read_section_offset_and_length (info, map_sect_name, *mprotect_flags,
|
|
1686 &map_sect_offset, &map_sect_len);
|
|
1687
|
|
1688 /* See if we actually found the section. */
|
|
1689 if (map_sect_len)
|
|
1690 page_count_2 += (map_sect_len + VTV_PAGE_SIZE - 1) / VTV_PAGE_SIZE;
|
|
1691
|
|
1692 return 0;
|
|
1693 }
|
|
1694 #endif
|
|
1695
|
|
1696 static void
|
|
1697 count_all_pages (void)
|
|
1698 {
|
|
1699 int mprotect_flags;
|
|
1700
|
|
1701 mprotect_flags = PROT_READ;
|
|
1702 page_count_2 = 0;
|
|
1703
|
|
1704 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
1705 iterate_modules ((void *) &mprotect_flags);
|
|
1706 #else
|
|
1707 dl_iterate_phdr (dl_iterate_phdr_count_pages, (void *) &mprotect_flags);
|
|
1708 #endif
|
|
1709 page_count_2 += __vtv_count_mmapped_pages ();
|
|
1710 }
|
|
1711
|
|
1712 void
|
|
1713 __VLTDumpStats (void)
|
|
1714 {
|
|
1715 int log_fd = __vtv_open_log ("vtv-runtime-stats.log");
|
|
1716
|
|
1717 if (log_fd != -1)
|
|
1718 {
|
|
1719 count_all_pages ();
|
|
1720 __vtv_add_to_log (log_fd,
|
|
1721 "Calls: mprotect (%d) regset (%d) regpair (%d)"
|
|
1722 " verify_vtable (%d)\n",
|
|
1723 num_calls_to_mprotect, num_calls_to_regset,
|
|
1724 num_calls_to_regpair, num_calls_to_verify_vtable);
|
|
1725 __vtv_add_to_log (log_fd,
|
|
1726 "Cycles: mprotect (%lld) regset (%lld) "
|
|
1727 "regpair (%lld) verify_vtable (%lld)\n",
|
|
1728 mprotect_cycles, regset_cycles, regpair_cycles,
|
|
1729 verify_vtable_cycles);
|
|
1730 __vtv_add_to_log (log_fd,
|
|
1731 "Pages protected (1): %d\n", num_pages_protected);
|
|
1732 __vtv_add_to_log (log_fd, "Pages protected (2): %d\n", page_count_2);
|
|
1733
|
|
1734 close (log_fd);
|
|
1735 }
|
|
1736 }
|
|
1737
|
|
1738 /* This function is called from __VLTVerifyVtablePointerDebug; it
|
|
1739 sends as much debugging information as it can to the error log
|
|
1740 file, then calls __vtv_verify_fail. SET_HANDLE_PTR is the pointer
|
|
1741 to the set of valid vtable pointers, VTBL_PTR is the pointer that
|
|
1742 was not found in the set, and DEBUG_MSG is the message to be
|
|
1743 written to the log file before failing. n */
|
|
1744
|
|
1745 void
|
|
1746 __vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr,
|
|
1747 const char *debug_msg)
|
|
1748 {
|
|
1749 __vtv_log_verification_failure (debug_msg, false);
|
|
1750
|
|
1751 /* Call the public interface in case it has been overwritten by
|
|
1752 user. */
|
|
1753 __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
|
|
1754
|
|
1755 __vtv_log_verification_failure ("Returned from __vtv_verify_fail."
|
|
1756 " Secondary verification succeeded.\n", false);
|
|
1757 }
|
|
1758
|
|
1759 /* This function calls __fortify_fail with a FAILURE_MSG and then
|
|
1760 calls abort. */
|
|
1761
|
|
1762 void
|
|
1763 __vtv_really_fail (const char *failure_msg)
|
|
1764 {
|
|
1765 __fortify_fail (failure_msg);
|
|
1766
|
|
1767 /* We should never get this far; __fortify_fail calls __libc_message
|
|
1768 which prints out a back trace and a memory dump and then is
|
|
1769 supposed to call abort, but let's play it safe anyway and call abort
|
|
1770 ourselves. */
|
|
1771 abort ();
|
|
1772 }
|
|
1773
|
|
1774 /* This function takes an error MSG, a vtable map variable
|
|
1775 (DATA_SET_PTR) and a vtable pointer (VTBL_PTR). It is called when
|
|
1776 an attempt to verify VTBL_PTR with the set pointed to by
|
|
1777 DATA_SET_PTR failed. It outputs a failure message with the
|
|
1778 addresses involved, and calls __vtv_really_fail. */
|
|
1779
|
|
1780 static void
|
|
1781 vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
|
|
1782 {
|
|
1783 char buffer[128];
|
|
1784 int buf_len;
|
|
1785 const char *format_str =
|
|
1786 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
|
|
1787
|
|
1788 snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr,
|
|
1789 is_set_handle_handle(*data_set_ptr) ?
|
|
1790 ptr_from_set_handle_handle (*data_set_ptr) :
|
|
1791 *data_set_ptr);
|
|
1792 buf_len = strlen (buffer);
|
|
1793 /* Send this to to stderr. */
|
|
1794 write (2, buffer, buf_len);
|
|
1795
|
|
1796 #ifndef VTV_NO_ABORT
|
|
1797 __vtv_really_fail (msg);
|
|
1798 #endif
|
|
1799 }
|
|
1800
|
|
1801 /* Send information about what we were trying to do when verification
|
|
1802 failed to the error log, then call vtv_fail. This function can be
|
|
1803 overwritten/replaced by the user, to implement a secondary
|
|
1804 verification function instead. DATA_SET_PTR is the vtable map
|
|
1805 variable used for the failed verification, and VTBL_PTR is the
|
|
1806 vtable pointer that was not found in the set. */
|
|
1807
|
|
1808 void
|
|
1809 __vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
|
|
1810 {
|
|
1811 char log_msg[256];
|
|
1812 snprintf (log_msg, sizeof (log_msg), "Looking for vtable %p in set %p.\n",
|
|
1813 vtbl_ptr,
|
|
1814 is_set_handle_handle (*data_set_ptr) ?
|
|
1815 ptr_from_set_handle_handle (*data_set_ptr) :
|
|
1816 *data_set_ptr);
|
|
1817 __vtv_log_verification_failure (log_msg, false);
|
|
1818
|
|
1819 const char *format_str =
|
|
1820 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
|
|
1821 snprintf (log_msg, sizeof (log_msg), format_str, vtbl_ptr, *data_set_ptr);
|
|
1822 __vtv_log_verification_failure (log_msg, false);
|
|
1823 __vtv_log_verification_failure (" Backtrace: \n", true);
|
|
1824
|
|
1825 const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
|
|
1826 vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
|
|
1827 }
|