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