Open Simorfo opened 7 years ago
Sorry, this happens only in debug mode. In non-debug mode, dynamorio works fine.
With debug mode, I get a few other failed asserts
ASSERT(EXIT_IS_CALL(instr_exit_branch_type(next)) || (DYNAMO_OPTION(IAT_convert) && TEST(INSTR_IND_CALL_DIRECT, instr->flags)));
FRAG_ALSO(entry)
in vm_list_overlapsASSERT(res == RECREATE_SUCCESS_PC)
and ASSERT(translated_pc != NULL)
Sorry, this happens only in debug mode. In non-debug mode, dynamorio works fine.
You mean there's no possibility of a race in non-debug? Or it's just less likely due to spending less time processing exceptions and you just didn't observe it? What if you run the app in a loop 1000 iters?
In non-debug mode, I just run it 10 times and did not observe a race condition
With debug mode, I got a race every time.
Also, I tried to run it with option safe_translate_flushed I tried it because I managed to get test security-win32.selfmod-threads running fine with this option (and not fine without) But I get another bug with this sample before getting to the threads creation (one mutex gets locked twice)
With version 6.2.0-2 of DynamoRio The latest build does not solve the problem
On Windows 7, with a 32 bit application, themida-hostname.exe the classic hostname software packed with themida
I run it with (no client) C:\rio\bin32\drrun.exe -debug -- themida-hostname.exe
The expected output is a line with the hostname. Instead we get a crash with
ASSERT(!info.overlap || (f != NULL && TEST(FRAG_IS_TRACE, f->flags)));
The problem seems to come from two threads doing self modifications on the same memory page. With a race condition, we have two exceptions EXCEPTION_ACCESS_VIOLATION.
Both threads end up in function
handle_modified_code
First one goes normally, ending removing the interval from the exec list to continue write. But second one logs Region for 0x101a1f3 not exec, probably data on same page WARNING: region now writable: assuming another thread already flushed it going to flush again just to make sure ASSERT(!info.overlap || (f != NULL && TEST(FRAG_IS_TRACE, f->flags)));Condition
base_pc < (bb_pend + PAGE_SIZE) && (base_pc + size) > bb_pstart
was not true for the second thread because size was not expanded afterget_memory_info
to the exec area size.Returning NULL from
handle_modified_code
to re-execute the faulting write instead of asserting provides a correct behavior in this case.