[plcrashreporter] push by landon.j.fuller@gmail.com - Stub out in-process address validation using vm map lookup as a possib... on 2013-03-26 19:43 GMT

2 views
Skip to first unread message

codesite...@google.com

unread,
Mar 26, 2013, 3:44:06 PM3/26/13
to plcrashrepo...@googlegroups.com
Revision: 915f9818d356
Author: Landon Fuller <lan...@plausible.coop>
Date: Tue Mar 26 12:42:48 2013
Log: Stub out in-process address validation using vm map lookup as a
possible work-around for bugs in vm_remap() on iOS.

http://code.google.com/p/plcrashreporter/source/detail?r=915f9818d356

Modified:
/Source/PLCrashAsync.h
/Source/PLCrashAsyncMObject.c
/Source/PLCrashAsyncMachOImageTests.m

=======================================
--- /Source/PLCrashAsync.h Tue Jan 1 14:02:34 2013
+++ /Source/PLCrashAsync.h Tue Mar 26 12:42:48 2013
@@ -37,6 +37,14 @@
#include <TargetConditionals.h>
#include <mach/mach.h>

+#if 1 /* TODO: TARGET_OS_IPHONE */
+
+/** If defined, the target architecture has a broken vm_remap() or
mach_vm_remap() implementation that triggers
+ * kernel panics. */
+#define PL_HAVE_BROKEN_VM_REMAP 1
+
+#endif
+
#if TARGET_OS_IPHONE

/*
=======================================
--- /Source/PLCrashAsyncMObject.c Mon Feb 18 07:47:11 2013
+++ /Source/PLCrashAsyncMObject.c Tue Mar 26 12:42:48 2013
@@ -40,6 +40,72 @@
* @{
*/

+#ifdef PL_HAVE_BROKEN_VM_REMAP
+
+/**
+ * Verify the validity of the given @a address and @a length within the
current process. Note that this validity
+ * is only gauranteed insofar as the pages in question are not unmapped,
which may occur for any reason, including
+ * the case where the process' threads have not been suspended.
+ *
+ * @param address The target address to verify.
+ * @param length The total size of the range to be verified.
+ *
+ * @warning This function is provided as a work-around for bugs in
vm_remap() that have been reported
+ * in iOS 6. Should those bugs be isolated and fixed, this implementation
may be removed.
+ */
+static plcrash_error_t plcrash_async_mobject_vm_regions_valid
(pl_vm_address_t address, pl_vm_size_t length) {
+ kern_return_t kt;
+
+ if (length == 0)
+ return PLCRASH_ESUCCESS;
+
+ pl_vm_address_t start_address = address;
+
+ while (start_address < address+length) {
+ mach_msg_type_number_t info_count;
+ pl_vm_address_t region_base;
+ pl_vm_size_t region_size;
+ natural_t nesting_depth = 0;
+
+ region_base = start_address;
+
+ PLCF_DEBUG("Recursing vm region for address=0x%" PRIx64 " looking
for terminator=0x%" PRIx64, (uint64_t) region_base, (uint64_t)
(address+length));
+
+#ifdef PL_HAVE_MACH_VM
+ vm_region_submap_info_data_64_t info;
+ info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
+
+ kt = mach_vm_region_recurse(mach_task_self(), &region_base,
&region_size, &nesting_depth, (vm_region_recurse_info_t) &info,
&info_count);
+#else
+ vm_region_submap_info_data_t info;
+ info_count = VM_REGION_SUBMAP_INFO_COUNT;
+
+ kt = vm_region_recurse(mach_task_self(), &region_base,
&region_size, &nesting_depth, (vm_region_recurse_info_t) &info,
&info_count);
+#endif
+
+ if (kt != KERN_SUCCESS) {
+ PLCF_DEBUG("Failed to recurse vm region for address=0x%"
PRIx64" length=0x%" PRIx64 ": %x",
+ (uint64_t) region_base, (uint64_t) (region_size), kt);
+ return PLCRASH_EINTERNAL;
+ }
+
+ if ((info.protection & VM_PROT_READ) == 0) {
+ PLCF_DEBUG("Missing read permissions for address=0x%" PRIx64"
length=0x%" PRIx64 ": %x",
+ (uint64_t) region_base, (uint64_t) (region_size),
kt);
+ return PLCRASH_EACCESS;
+ }
+
+ PLCF_DEBUG("Found vm region for address=0x%" PRIx64" length=0x%"
PRIx64,
+ (uint64_t) region_base, (uint64_t) (region_size));
+
+ start_address = region_base + region_size;
+ }
+
+ return PLCRASH_ESUCCESS;
+}
+
+#endif
+
/**
* Initialize a new memory object reference, mapping @a task_addr from @a
task into the current process. The mapping
* will be copy-on-write, and will be checked to ensure a minimum
protection value of VM_PROT_READ.
@@ -55,6 +121,22 @@
* @warn Callers must call plcrash_async_mobject_free() on @a mobj, even
if plcrash_async_mobject_init() fails.
*/
plcrash_error_t plcrash_async_mobject_init (plcrash_async_mobject_t *mobj,
mach_port_t task, pl_vm_address_t task_addr, pl_vm_size_t length) {
+#ifdef PL_HAVE_BROKEN_VM_REMAP
+ if (plcrash_async_mobject_vm_regions_valid(task_addr, length) !=
PLCRASH_ESUCCESS)
+ return PLCRASH_ENOMEM;
+
+ /* This operation mode is unsupported when running out-of-process */
+ PLCF_ASSERT(task == mach_task_self());
+
+ mobj->vm_address = 0x0;
+ mobj->address = task_addr;
+ mobj->length = length;
+ mobj->vm_slide = 0;
+ mobj->task_address = task_addr;
+
+ return PLCRASH_ESUCCESS;
+
+#else
/* We must first initialize vm_address to 0x0. We'll check this in
_free() to determine whether calling vm_deallocate() is required */
mobj->vm_address = 0x0;

@@ -95,6 +177,7 @@
mobj->task_address = task_addr;

return PLCRASH_ESUCCESS;
+#endif /* !PL_HAVE_BROKEN_VM_REMAP */
}


=======================================
--- /Source/PLCrashAsyncMachOImageTests.m Tue Jan 1 14:02:34 2013
+++ /Source/PLCrashAsyncMachOImageTests.m Tue Mar 26 12:42:48 2013
@@ -194,7 +194,10 @@
uint8_t *mapped_data = plcrash_async_mobject_remap_address(&seg.mobj,
(pl_vm_address_t) data, segsize);
STAssertNotNULL(mapped_data, @"Could not get pointer for mapped data");

+#ifndef PL_HAVE_BROKEN_VM_REMAP
STAssertNotEquals(mapped_data, data, @"Should not be the same
pointer!");
+#endif
+
STAssertTrue(memcmp(data, mapped_data, segsize) == 0, @"The mapped
data is not equal");

/* Clean up */
@@ -225,8 +228,11 @@
/* Compare the contents */
uint8_t *mapped_data = plcrash_async_mobject_remap_address(&mobj,
(pl_vm_address_t) data, sectsize);
STAssertNotNULL(mapped_data, @"Could not get pointer for mapped data");
-
+
+#ifndef PL_HAVE_BROKEN_VM_REMAP
STAssertNotEquals(mapped_data, data, @"Should not be the same
pointer!");
+#endif
+
STAssertTrue(memcmp(data, mapped_data, sectsize) == 0, @"The mapped
data is not equal");

/* Clean up */
Reply all
Reply to author
Forward
0 new messages