From 52e14d17ace64ef2dd9df182a892fe76ac74305c Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 19 Oct 2021 05:23:04 +0000 Subject: [PATCH] Add basic use-after-free checking in limited places. Sadly this appears to have exposed some missing allocation wraps, which prevents us from applying this in more locations. --- gen_type_mapping.py | 12 +++++++++--- java_strings.py | 21 ++++++++++++++++++++- typescript_strings.py | 11 +++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/gen_type_mapping.py b/gen_type_mapping.py index 250619d3..e6585f97 100644 --- a/gen_type_mapping.py +++ b/gen_type_mapping.py @@ -299,7 +299,9 @@ class TypeMappingGenerator: arg_conv_cleanup = None, ret_conv = (ty_info.c_ty + " " + ty_info.var_name + "_conv = " + ret_pfx, ret_sfx + ";"), ret_conv_name = ty_info.var_name + "_conv", to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None) - base_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv = *(" + ty_info.rust_obj + "*)(((uint64_t)" + ty_info.var_name + ") & ~1);" + base_conv = "void* " + ty_info.var_name + "_ptr = (void*)(((uint64_t)" + ty_info.var_name + ") & ~1);\n" + base_conv += "CHECK_ACCESS(" + ty_info.var_name + "_ptr);\n" + base_conv += ty_info.rust_obj + " " + ty_info.var_name + "_conv = *(" + ty_info.rust_obj + "*)(" + ty_info.var_name + "_ptr);" if ty_info.rust_obj in self.trait_structs: ret_conv = (ty_info.rust_obj + "* " + ty_info.var_name + "_ret =MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n*" + ty_info.var_name + "_ret = ", ";") if holds_ref: @@ -432,7 +434,9 @@ class TypeMappingGenerator: from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr & ~1", from_hu_sfx)) elif ty_info.rust_obj in self.trait_structs: if ty_info.nonnull_ptr: - arg_conv = ty_info.rust_obj + "* " + ty_info.var_name + "_conv = (" + ty_info.rust_obj + "*)(((uint64_t)" + ty_info.var_name + ") & ~1);" + arg_conv = "void* " + ty_info.var_name + "_ptr = (void*)(((uint64_t)" + ty_info.var_name + ") & ~1);\n" + arg_conv += "if (!(" + ty_info.var_name + " & 1)) { CHECK_ACCESS(" + ty_info.var_name + "_ptr); }\n" + arg_conv += ty_info.rust_obj + "* " + ty_info.var_name + "_conv = (" + ty_info.rust_obj + "*)" + ty_info.var_name + "_ptr;" arg_conv_name = ty_info.var_name + "_conv" else: # We map Option as *mut Trait, which we can differentiate from &Trait by the NONNULL_PTR annotation. @@ -440,7 +444,9 @@ class TypeMappingGenerator: arg_conv = ty_info.rust_obj + " *" + ty_info.var_name + "_conv_ptr = NULL;\n" arg_conv += "if (" + ty_info.var_name + " != 0) {\n" arg_conv += "\t" + ty_info.rust_obj + " " + ty_info.var_name + "_conv;\n" - arg_conv += "\t" + ty_info.var_name + "_conv = *(" + ty_info.rust_obj + "*)(((uint64_t)" + ty_info.var_name + ") & ~1);" + arg_conv += "void* " + ty_info.var_name + "_ptr = (void*)(((uint64_t)" + ty_info.var_name + ") & ~1);\n" + arg_conv += "CHECK_ACCESS(" + ty_info.var_name + "_ptr);\n" + arg_conv += "\t" + ty_info.var_name + "_conv = *(" + ty_info.rust_obj + "*)" + ty_info.var_name + "_ptr;" arg_conv += self.consts.trait_struct_inc_refcnt(ty_info).replace("\n", "\n\t") arg_conv += "\n\t" + ty_info.var_name + "_conv_ptr = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n" arg_conv += "\t*" + ty_info.var_name + "_conv_ptr = " + ty_info.var_name + "_conv;\n" diff --git a/java_strings.py b/java_strings.py index 1e7ba997..1d28d0d1 100644 --- a/java_strings.py +++ b/java_strings.py @@ -162,6 +162,7 @@ void __attribute__((constructor)) spawn_stderr_redirection() { if not DEBUG or sys.platform == "darwin": self.c_file_pfx = self.c_file_pfx + """#define MALLOC(a, _) malloc(a) #define FREE(p) if ((uint64_t)(p) > 1024) { free(p); } +#define CHECK_ACCESS(p) """ if not DEBUG: self.c_file_pfx += """#define DO_ASSERT(a) (void)(a) @@ -282,7 +283,7 @@ static void alloc_freed(void* ptr) { while (it->ptr != ptr) { p = it; it = it->next; if (it == NULL) { - DEBUG_PRINT("Tried to free unknown pointer %p at:\\n", ptr); + DEBUG_PRINT("ERROR: Tried to free unknown pointer %p at:\\n", ptr); void* bt[BT_MAX]; int bt_len = backtrace(bt, BT_MAX); backtrace_symbols_fd(bt, bt_len, STDERR_FILENO); @@ -318,6 +319,24 @@ void __wrap_free(void* ptr) { __real_free(ptr); } +static void CHECK_ACCESS(void* ptr) { + DO_ASSERT(!pthread_mutex_lock(&allocation_mtx)); + allocation* it = allocation_ll; + while (it->ptr != ptr) { + it = it->next; + if (it == NULL) { + DEBUG_PRINT("ERROR: Tried to access unknown pointer %p at:\\n", ptr); + void* bt[BT_MAX]; + int bt_len = backtrace(bt, BT_MAX); + backtrace_symbols_fd(bt, bt_len, STDERR_FILENO); + DEBUG_PRINT("\\n\\n"); + DO_ASSERT(!pthread_mutex_unlock(&allocation_mtx)); + return; // addrsan should catch and print more info than we have + } + } + DO_ASSERT(!pthread_mutex_unlock(&allocation_mtx)); +} + void* __real_realloc(void* ptr, size_t newlen); void* __wrap_realloc(void* ptr, size_t len) { if (ptr != NULL) alloc_freed(ptr); diff --git a/typescript_strings.py b/typescript_strings.py index 84b27c57..d1449c22 100644 --- a/typescript_strings.py +++ b/typescript_strings.py @@ -123,6 +123,7 @@ void free(void *ptr); #define FREE(p) if ((unsigned long)(p) > 1024) { free(p); } #define DO_ASSERT(a) (void)(a) #define CHECK(a) +#define CHECK_ACCESS(p) """ else: self.c_file_pfx = self.c_file_pfx + """ @@ -179,6 +180,16 @@ static void FREE(void* ptr) { __real_free(ptr); } +static void CHECK_ACCESS(void* ptr) { + allocation* it = allocation_ll; + while (it->ptr != ptr) { + it = it->next; + if (it == NULL) { + return; // addrsan should catch malloc-unknown and print more info than we have + } + } +} + void* __wrap_malloc(size_t len) { void* res = __real_malloc(len); new_allocation(res, "malloc call"); -- 2.30.2