summaryrefslogtreecommitdiff
path: root/libstdc++-v3/libsupc++/vtv_rts.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/libsupc++/vtv_rts.cc')
-rw-r--r--libstdc++-v3/libsupc++/vtv_rts.cc270
1 files changed, 186 insertions, 84 deletions
diff --git a/libstdc++-v3/libsupc++/vtv_rts.cc b/libstdc++-v3/libsupc++/vtv_rts.cc
index eb82eb42c8e..cb2b8d27b10 100644
--- a/libstdc++-v3/libsupc++/vtv_rts.cc
+++ b/libstdc++-v3/libsupc++/vtv_rts.cc
@@ -143,7 +143,22 @@
#include "../../include/vtv-change-permission.h"
-bool vtv_debug = false;
+extern "C" {
+
+ /* __fortify_fail is a function in glibc that calls __libc_message,
+ causing it to print out a program termination error message
+ (including the name of the binary being terminated), a stack
+ trace where the error occurred, and a memory map dump. Ideally
+ we would have called __libc_message directly, but that function
+ does not appear to be accessible to functions outside glibc,
+ whereas __fortify_fail is. We call __fortify_fail from
+ __vtv_really_fail. We looked at calling __libc_fatal, which is
+ externally accessible, but it does not do the back trace and
+ memory dump. */
+
+ extern void __fortify_fail (const char *) __attribute__((noreturn));
+
+} /* extern "C" */
/* The following variables are used only for debugging and performance
tuning purposes. Therefore they do not need to be "protected".
@@ -174,12 +189,16 @@ static const int debug_functions = 0;
static const int debug_init = 0;
static const int debug_verify_vtable = 0;
+#ifdef VTV_DEBUG
+static const int debug_functions = 1;
+static const int debug_init = 1;
+static const int debug_verify_vtable = 1;
+#endif
/* Global file descriptor variables for logging, tracing and debugging. */
static int init_log_fd = -1;
static int verify_vtable_log_fd = -1;
-static int vtv_failures_log_fd = -1;
/* This holds a formatted error logging message, to be written to the
vtable verify failures log. */
@@ -193,6 +212,10 @@ static __gthread_mutex_t change_permissions_lock;
#endif
+#ifndef VTV_STATS
+#define VTV_STATS 0
+#endif
+
#if VTV_STATS
static inline unsigned long long
@@ -272,7 +295,7 @@ struct vptr_set_alloc
void *
operator() (size_t n) const
{
- return VTV_malloc (n);
+ return __vtv_malloc (n);
}
};
@@ -373,9 +396,9 @@ log_memory_protection_data (char *message)
static int log_fd = -1;
if (log_fd == -1)
- log_fd = vtv_open_log ("vtv_memory_protection_data_%d.log");
+ log_fd = __vtv_open_log ("vtv_memory_protection_data_%d.log");
- vtv_add_to_log (log_fd, "%s", message);
+ __vtv_add_to_log (log_fd, "%s", message);
}
static void
@@ -444,7 +467,6 @@ read_section_offset_and_length (struct dl_phdr_info *info,
if (fd != -1)
{
-
/* Find the section header information in the file. */
ElfW (Half) strtab_idx = ehdr_info->e_shstrndx;
ElfW (Shdr) shstrtab;
@@ -456,6 +478,14 @@ read_section_offset_and_length (struct dl_phdr_info *info,
ElfW (Shdr) sect_hdr;
+ /* This code will be needed once we have crated libvtv.so. */
+ bool is_libvtv = false;
+
+ /*
+ if (strstr (info->dlpi_name, "libvtv.so"))
+ is_libvtv = true;
+ */
+
/* Loop through all the section headers, looking for one whose
name is ".vtable_map_vars". */
@@ -480,7 +510,10 @@ read_section_offset_and_length (struct dl_phdr_info *info,
/* We found the section; get its load offset and
size. */
*sect_offset = sect_hdr.sh_addr;
- *sect_len = sect_hdr.sh_size - VTV_PAGE_SIZE;
+ if (!is_libvtv)
+ *sect_len = sect_hdr.sh_size - VTV_PAGE_SIZE;
+ else
+ *sect_len = sect_hdr.sh_size;
found = true;
}
}
@@ -516,7 +549,7 @@ read_section_offset_and_length (struct dl_phdr_info *info,
}
/* This is the callback function used by dl_iterate_phdr (which is
- called from VTV_unprotect_vtable_vars and VTV_protect_vtable_vars).
+ called from vtv_unprotect_vtable_vars and vtv_protect_vtable_vars).
It attempts to find the binary file on disk for the INFO record
that dl_iterate_phdr passes in; open the binary file, and read its
section header information. If the file contains a
@@ -613,7 +646,8 @@ dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t unused, void *data)
}
}
increment_num_calls (&num_calls_to_mprotect);
- num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1) / VTV_PAGE_SIZE;
+ /* num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1) / VTV_PAGE_SIZE; */
+ num_pages_protected += (map_sect_len + 4096 - 1) / 4096;
}
return 0;
@@ -641,10 +675,12 @@ dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t unused, void *data)
static void
change_protections_on_phdr_cache (int protection_flag)
{
- ElfW (Addr) low_address = (ElfW (Addr)) &(vtv_sect_info_cache);
+ char * low_address = (char *) &(vtv_sect_info_cache);
size_t cache_size = MAX_ENTRIES * sizeof (struct sect_hdr_data);
- low_address = low_address & ~(VTV_PAGE_SIZE -1);
+ low_address = (char *) ((unsigned long) low_address & ~(VTV_PAGE_SIZE - 1));
+ size_t protection_size =
+ (char *) &vtv_sect_info_cache - low_address + cache_size;
if (mprotect ((void *) low_address, cache_size, protection_flag) == -1)
VTV_error ();
@@ -655,7 +691,7 @@ change_protections_on_phdr_cache (int protection_flag)
into relro sections */
static void
-VTV_unprotect_vtable_vars (void)
+vtv_unprotect_vtable_vars (void)
{
int mprotect_flags;
@@ -669,7 +705,7 @@ VTV_unprotect_vtable_vars (void)
into relro sections */
static void
-VTV_protect_vtable_vars (void)
+vtv_protect_vtable_vars (void)
{
int mprotect_flags;
@@ -722,10 +758,10 @@ log_set_stats (void)
{
#if HASHTABLE_STATS
if (set_log_fd == -1)
- set_log_fd = vtv_open_log ("vtv_set_stats.log");
+ set_log_fd = __vtv_open_log ("vtv_set_stats.log");
- vtv_add_to_log (set_log_fd, "---\n%s\n",
- insert_only_hash_tables_stats().c_str());
+ __vtv_add_to_log (set_log_fd, "---\n%s\n",
+ insert_only_hash_tables_stats().c_str());
#endif
}
@@ -767,9 +803,9 @@ __VLTChangePermission (int perm)
module that is not the first load module. */
__gthread_mutex_lock (&change_permissions_lock);
- VTV_unprotect_vtable_vars ();
- VTV_malloc_init ();
- VTV_malloc_unprotect ();
+ vtv_unprotect_vtable_vars ();
+ __vtv_malloc_init ();
+ __vtv_malloc_unprotect ();
}
else if (perm == __VLTP_READ_ONLY)
@@ -777,8 +813,8 @@ __VLTChangePermission (int perm)
if (debug_hash)
log_set_stats();
- VTV_malloc_protect ();
- VTV_protect_vtable_vars ();
+ __vtv_malloc_protect ();
+ vtv_protect_vtable_vars ();
__gthread_mutex_unlock (&change_permissions_lock);
}
@@ -798,7 +834,7 @@ struct insert_only_hash_map_allocator
void *
alloc (size_t n) const
{
- return VTV_malloc (n);
+ return __vtv_malloc (n);
}
/* P points to the memory to be deallocated; N is the number of
@@ -806,7 +842,7 @@ struct insert_only_hash_map_allocator
void
dealloc (void *p, size_t n) const
{
- VTV_free (p);
+ __vtv_free (p);
}
};
@@ -857,31 +893,6 @@ set_handle_handle (vtv_set_handle * ptr)
return (vtv_set_handle_handle) ((unsigned long) ptr | SET_HANDLE_HANDLE_BIT);
}
-/* Open error logging file, if not already open, and write vtable
- verification failure messages (LOG_MSG) to the log file. Also
- generate a backtrace in the log file, if GENERATE_BACKTRACE is
- set. */
-
-static void
-log_error_message (const char *log_msg, bool generate_backtrace)
-{
- if (vtv_failures_log_fd == -1)
- vtv_failures_log_fd = vtv_open_log ("vtable_verification_failures.log");
-
- if (vtv_failures_log_fd == -1)
- return;
-
- vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg);
-
- if (generate_backtrace)
- {
-#define STACK_DEPTH 20
- void *callers[STACK_DEPTH];
- int actual_depth = backtrace (callers, STACK_DEPTH);
- backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd);
- }
-}
-
static inline void
register_set_common (void **set_handle_ptr, size_t num_args,
void **vtable_ptr_array, bool debug)
@@ -933,12 +944,12 @@ register_pair_common (void **set_handle_ptr, const void *vtable_ptr,
if (debug && debug_init)
{
if (init_log_fd == -1)
- init_log_fd = vtv_open_log("vtv_init.log");
+ init_log_fd = __vtv_open_log("vtv_init.log");
- vtv_add_to_log(init_log_fd,
- "Registered %s : %s (%p) 2 level deref = %s\n",
- set_symbol_name, vtable_name, vtbl_ptr,
- is_set_handle_handle(*set_handle_ptr) ? "yes" : "no" );
+ __vtv_add_to_log(init_log_fd,
+ "Registered %s : %s (%p) 2 level deref = %s\n",
+ set_symbol_name, vtable_name, vtbl_ptr,
+ is_set_handle_handle(*set_handle_ptr) ? "yes" : "no" );
}
}
@@ -986,7 +997,7 @@ init_set_symbol_debug (void **set_handle_ptr, const void *set_symbol_key,
"*** Found non-NULL local set ptr %p missing for symbol"
" %.*s",
*handle_ptr, symbol_key_ptr->n, symbol_key_ptr->bytes);
- log_error_message (buffer, true);
+ __vtv_log_verification_failure (buffer, true);
VTV_DEBUG_ASSERT (0);
}
}
@@ -1000,7 +1011,7 @@ init_set_symbol_debug (void **set_handle_ptr, const void *set_symbol_key,
"for symbol %.*s",
*handle_ptr, *map_value_ptr,
symbol_key_ptr->n, symbol_key_ptr->bytes);
- log_error_message (buffer, true);
+ __vtv_log_verification_failure (buffer, true);
VTV_DEBUG_ASSERT (0);
}
else if (*handle_ptr == NULL)
@@ -1046,7 +1057,7 @@ init_set_symbol_debug (void **set_handle_ptr, const void *set_symbol_key,
in case the memory where this comes from gets unmapped by
dlclose. */
size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
- void *map_key = VTV_malloc (map_key_len);
+ void *map_key = __vtv_malloc (map_key_len);
memcpy (map_key, symbol_key_ptr, map_key_len);
@@ -1064,14 +1075,14 @@ init_set_symbol_debug (void **set_handle_ptr, const void *set_symbol_key,
if (debug_init)
{
if (init_log_fd == -1)
- init_log_fd = vtv_open_log ("vtv_init.log");
-
- vtv_add_to_log (init_log_fd,
- "Init handle:%p for symbol:%.*s hash:%u size_hint:%lu"
- "number of symbols:%lu \n",
- set_handle_ptr, symbol_key_ptr->n,
- symbol_key_ptr->bytes, symbol_key_ptr->hash, size_hint,
- vtv_symbol_unification_map->size ());
+ init_log_fd = __vtv_open_log ("vtv_init.log");
+
+ __vtv_add_to_log (init_log_fd,
+ "Init handle:%p for symbol:%.*s hash:%u size_hint:%lu"
+ "number of symbols:%lu \n",
+ set_handle_ptr, symbol_key_ptr->n,
+ symbol_key_ptr->bytes, symbol_key_ptr->hash, size_hint,
+ vtv_symbol_unification_map->size ());
}
}
@@ -1165,10 +1176,10 @@ __VLTVerifyVtablePointerDebug (void **set_handle_ptr, const void *vtable_ptr,
if (debug_verify_vtable)
{
if (verify_vtable_log_fd == -1)
- vtv_open_log ("vtv_verify_vtable.log");
- vtv_add_to_log (verify_vtable_log_fd,
- "Verified %s %s value = %p\n",
- set_symbol_name, vtable_name, vtable_ptr);
+ __vtv_open_log ("vtv_verify_vtable.log");
+ __vtv_add_to_log (verify_vtable_log_fd,
+ "Verified %s %s value = %p\n",
+ set_symbol_name, vtable_name, vtable_ptr);
}
}
else
@@ -1251,7 +1262,7 @@ init_set_symbol (void **set_handle_ptr, const void *set_symbol_key,
in case the memory where this comes from gets unmapped by
dlclose. */
size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
- void * map_key = VTV_malloc (map_key_len);
+ void * map_key = __vtv_malloc (map_key_len);
memcpy (map_key, symbol_key_ptr, map_key_len);
s2s::value_type * value_ptr;
@@ -1393,31 +1404,122 @@ count_all_pages (void)
page_count_2 = 0;
dl_iterate_phdr (dl_iterate_phdr_count_pages, (void *) &mprotect_flags);
- page_count_2 += VTV_count_mmapped_pages ();
+ page_count_2 += __vtv_count_mmapped_pages ();
}
void
__VLTDumpStats (void)
{
- int log_fd = vtv_open_log ("vtv-runtime-stats.log");
+ int log_fd = __vtv_open_log ("vtv-runtime-stats.log");
if (log_fd != -1)
{
count_all_pages ();
- vtv_add_to_log (log_fd,
- "Calls: mprotect (%d) regset (%d) regpair (%d)"
- " verify_vtable (%d)\n",
- num_calls_to_mprotect, num_calls_to_regset,
- num_calls_to_regpair, num_calls_to_verify_vtable);
- vtv_add_to_log (log_fd,
- "Cycles: mprotect (%lld) regset (%lld) "
- "regpair (%lld) verify_vtable (%lld)\n",
- mprotect_cycles, regset_cycles, regpair_cycles,
- verify_vtable_cycles);
- vtv_add_to_log (log_fd,
- "Pages protected (1): %d\n", num_pages_protected);
- vtv_add_to_log (log_fd, "Pages protected (2): %d\n", page_count_2);
+ __vtv_add_to_log (log_fd,
+ "Calls: mprotect (%d) regset (%d) regpair (%d)"
+ " verify_vtable (%d)\n",
+ num_calls_to_mprotect, num_calls_to_regset,
+ num_calls_to_regpair, num_calls_to_verify_vtable);
+ __vtv_add_to_log (log_fd,
+ "Cycles: mprotect (%lld) regset (%lld) "
+ "regpair (%lld) verify_vtable (%lld)\n",
+ mprotect_cycles, regset_cycles, regpair_cycles,
+ verify_vtable_cycles);
+ __vtv_add_to_log (log_fd,
+ "Pages protected (1): %d\n", num_pages_protected);
+ __vtv_add_to_log (log_fd, "Pages protected (2): %d\n", page_count_2);
close (log_fd);
}
}
+
+/* This function is called from __VLTVerifyVtablePointerDebug; it
+ sends as much debugging information as it can to the error log
+ file, then calls __vtv_verify_fail. SET_HANDLE_PTR is the pointer
+ to the set of valid vtable pointers, VTBL_PTR is the pointer that
+ was not found in the set, and DEBUG_MSG is the message to be
+ written to the log file before failing. n */
+
+void
+__vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr,
+ const char *debug_msg)
+{
+ __vtv_log_verification_failure (debug_msg, false);
+
+ /* Call the public interface in case it has been overwritten by
+ user. */
+ __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
+
+ __vtv_log_verification_failure ("Returned from __vtv_verify_fail."
+ " Secondary verification succeeded.\n", false);
+}
+
+/* This function calls __fortify_fail with a FAILURE_MSG and then
+ calls abort. */
+
+void
+__vtv_really_fail (const char *failure_msg)
+{
+ __fortify_fail (failure_msg);
+
+ /* We should never get this far; __fortify_fail calls __libc_message
+ which prints out a back trace and a memory dump and then is
+ supposed to call abort, but let's play it safe anyway and call abort
+ ourselves. */
+ abort ();
+}
+
+/* This function takes an error MSG, a vtable map variable
+ (DATA_SET_PTR) and a vtable pointer (VTBL_PTR). It is called when
+ an attempt to verify VTBL_PTR with the set pointed to by
+ DATA_SET_PTR failed. It outputs a failure message with the
+ addresses involved, and calls __vtv_really_fail. */
+
+static void
+vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
+{
+ char buffer[128];
+ int buf_len;
+ const char *format_str =
+ "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
+
+ snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr,
+ is_set_handle_handle(*data_set_ptr) ?
+ ptr_from_set_handle_handle (*data_set_ptr) :
+ *data_set_ptr);
+ buf_len = strlen (buffer);
+ /* Send this to to stderr. */
+ write (2, buffer, buf_len);
+
+#ifndef VTV_NO_ABORT
+ __vtv_really_fail (msg);
+#endif
+}
+
+/* Send information about what we were trying to do when verification
+ failed to the error log, then call vtv_fail. This function can be
+ overwritten/replaced by the user, to implement a secondary
+ verification function instead. DATA_SET_PTR is the vtable map
+ variable used for the failed verification, and VTBL_PTR is the
+ vtable pointer that was not found in the set. */
+
+void
+__vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
+{
+ char log_msg[256];
+ snprintf (log_msg, sizeof (log_msg), "Looking for vtable %p in set %p.\n",
+ vtbl_ptr,
+ is_set_handle_handle (*data_set_ptr) ?
+ ptr_from_set_handle_handle (*data_set_ptr) :
+ *data_set_ptr);
+ __vtv_log_verification_failure (log_msg, false);
+
+ const char *format_str =
+ "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
+ snprintf (log_msg, sizeof (log_msg), format_str, vtbl_ptr, *data_set_ptr);
+ __vtv_log_verification_failure (log_msg, false);
+ __vtv_log_verification_failure (" Backtrace: \n", true);
+
+ const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
+ vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
+}