No subject


Sat Jul 26 02:57:16 CDT 2008


--- snip ---
0018: debug_process( pid=0019, attach=1 )
001a: *signal* signal=19
0018: debug_process() = 0
--- snip ---

Next, the father restores the overwritten sequence with original code and
resumes the child:

--- snip ---
001a: get_thread_context( handle=0xfffffffe, flags=00010007, suspend=1 )
001a: get_thread_context() = 0 { self=1, context=
..
0018: suspend_thread( handle=0x50 )
0018: suspend_thread() = 0 { count=0 }
0018: write_process_memory( handle=0x4c, addr=0x94ef73, data={55,8b} )
001a: *signal* signal=19
0018: write_process_memory() = 0
0018: new_thread( access=001f03ff, attributes=00000000, suspend=1,
request_fd=14 )
0018: *fd* 14 <- 71
0018: new_thread() = 0 { tid=001b, handle=0x5c }
...
0018: resume_thread( handle=0x5c )
001b: *wakeup* signaled=258 cookie=0x7ffd77b4
0018: resume_thread() = 0 { count=1 }
--- snip ---

The child begins to execute entry code, this is the problematic section
(explanation later):

--- snip ---
001a: open_mutex( access=001f0001, attributes=00000000, rootdir=0x24,
name=L"19::DA0D2092E0" )
001a: open_mutex() = OBJECT_NAME_NOT_FOUND { handle=(nil) }
001a: open_mutex( access=001f0001, attributes=00000000, rootdir=0x24,
name=L"19::DA0D2092E0" )
001a: open_mutex() = OBJECT_NAME_NOT_FOUND { handle=(nil) }
001a: set_thread_info( handle=0xfffffffe, mask=1, priority=1,
affinity=00000000, token=(nil) )
001a: set_thread_info() = 0
001a: create_mutex( access=001f0001, attributes=00000080, owned=0,
objattr={rootdir=0x24,sd={},name=L"19:DAF"} )
001a: create_mutex() = 0 { handle=0x40 }
--- snip ---

The father enters its debugger loop and receives first debug events:

--- snip ---
0018: get_process_info( handle=0x4c )
0018: get_process_info() = 0 { pid=0019, ppid=0017, exit_code=259, priority=2,
affinity=ffffffff, peb=0x7ffdf000, start_time=1c8efe021cc4f50 (-0.8118270),
end_time=0 }
0018: wait_debug_event( get_handle=1 )
0018: wait_debug_event() = 0 { pid=0019, tid=001a, wait=(nil),
event={create_process,file=0x54,process=0x44,thread=0x48,base=0x400000,offset=0,size=0,teb=0x7ffd8000,start=(nil),name=0x110618,unicode=1}
}
--- snip ---

After receiving the "create process" event, the father creates some mutexes
(the child will look for it):

--- snip ---
0018: create_mutex( access=001f0001, attributes=00000080, owned=0,
objattr={rootdir=0x14,sd={},name=L"19::DA0D2092E0"} )
0018: create_mutex() = 0 { handle=0x64 }
0018: resume_thread( handle=0x50 )
0018: resume_thread() = 0 { count=1 }
0018: create_mutex( access=001f0001, attributes=00000080, owned=0,
objattr={rootdir=0x14,sd={},name=L"DILLOCREATE"} )
0018: create_mutex() = 0 { handle=0x68 }
0018: close_handle( handle=0x68 )
0018: close_handle() = 0
0018: create_mutex( access=001f0001, attributes=00000080, owned=0,
objattr={rootdir=0x14,sd={},name=L"DILLOOEP"} )
0018: create_mutex() = 0 { handle=0x68 }
--- snip ---

Some time later in child process code:

--- snip ---
001a: open_mutex( access=001f0001, attributes=00000000, rootdir=0x24,
name=L"19:DAF" )
001a: open_mutex() = 0 { handle=0x74 }
..
001a: set_window_text( handle=0x10028, text=L"Error!" )
001a: set_window_text() = 0
--- snip ---

Well, what happens?
The mutexes are the critical point, they serve to synchronize father and child
startup phases.

Unfortunately there is a race condition which allows the child to create a
mutex which it is not allowed to (due to absence of certain father-created
mutexes) which leads to this error.

Remember the point when the father attached to the child and restores the
original entry point code?
As soon as the father resumes the execution of the child's main thread, the
child begins to execute further.
At the same time the father enters it's main debugging loop, waiting to receive
first debug events.
This is actually the race: the "process creation" event might be a bit too late
when the child already executed some chunk of code.

The problem can be prevented by not resuming child's main thread before
entering debugger event loop/creating mutexes.
Another solution whould be to guard the page at restored opcode location to let
any execution immediately cause page guard exception which would ideally
suspend the child thread again (like the protector does for the rest of code to
decrypt/encrypt code pages on the fly).
When the debugger loop is entered it would receive process creation and page
guard exception event serialized and coulde handle it appropriately.

Regards


-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list