[Bug 50108] New: Multiple applications using native API sandboxing / virtualization crash when being relay traced (Adobe Reader 11)
WineHQ Bugzilla
wine-bugs at winehq.org
Mon Nov 9 14:38:11 CST 2020
https://bugs.winehq.org/show_bug.cgi?id=50108
Bug ID: 50108
Summary: Multiple applications using native API sandboxing /
virtualization crash when being relay traced (Adobe
Reader 11)
Product: Wine
Version: 5.21
Hardware: x86
OS: Linux
Status: NEW
Severity: normal
Priority: P2
Component: tools
Assignee: wine-bugs at winehq.org
Reporter: focht at gmx.net
Distribution: ---
Hello folks,
encountered while revisiting some Adobe bugs with native API sandboxing enabled
(default).
Native API sandboxing works as designed under normal conditions, see my
no-relay references later.
Relay debugging is a developer / triager use-case.
Stable download link via Internet Archive:
https://web.archive.org/web/20200522053748/http://ardownload.adobe.com/pub/adobe/reader/win/11.x/11.0.04/en_US/AdbeRdr11004_en_US.exe
Acrobat Reader creates a sandboxed process (initially suspended) which crashes
in entry point when being relay traced.
--- snip ---
$ pwd
/home/focht/.wine/drive_c/Program Files (x86)/Adobe/Reader 11.0/Reader
$ WINEDEBUG=+seh,+relay,+server,+ntdll wine ./AcroRd32.exe >>log.txt 2>&1
...
0024:Call KERNEL32.CreateProcessAsUserW(00000100,0198e508 L"C:\\Program Files
(x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe",0198e618 L"\"C:\\Program Files
(x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe\" --channel=32.1.1899522388
--type=renderer",00000000,00000000,00000000,0100040c,00df6f68,00000000,0031f644,0031f694)
ret=0042b162
...
0130: init_process_done( gui=1, module=00400000, ldt_copy=f7d5d9c0,
entry=00401039 )
0024: *wakeup* signaled=0
0130: init_process_done() = 0 { suspend=1 }
...
0024:Ret KERNEL32.CreateProcessAsUserW() retval=00000001 ret=0042b162
...
0130:Call ntdll.RtlInitNlsTables(011d0000,011f0000,00fed810,7b081484)
ret=7b01d500
0130:Ret ntdll.RtlInitNlsTables() retval=7b081484 ret=7b01d500
0130:Call ntdll.RtlResetRtlTranslations(7b081484) ret=7b01d50b
0130:Ret ntdll.RtlResetRtlTranslations() retval=00000400 ret=7b01d50b
0130:Call ntdll.RtlInitUnicodeString(0031eb78,7b069b30 L"\\Registry\\Machine")
ret=7b0387b3
0130:Ret ntdll.RtlInitUnicodeString() retval=00000024 ret=7b0387b3
0130:trace:seh:dispatch_exception code=c0000096 flags=0 addr=00A8C960
ip=00a8c960 tid=0130
0130:trace:seh:dispatch_exception eax=7bc6c000 ebx=0031eb80 ecx=0031eb50
edx=02000000 esi=00000000 edi=00000000
0130:trace:seh:dispatch_exception ebp=0031eb04 esp=0031ea64 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010202
0130:trace:seh:call_stack_handlers calling handler at 0040C7F0 code=c0000096
flags=0
0130:trace:seh:call_stack_handlers handler at 0040C7F0 returned 1
0130:trace:seh:call_stack_handlers calling handler at 7BC513A0 code=c0000096
flags=0
0130:trace:seh:__regs_RtlUnwind code=c0000096 flags=2
0130:trace:seh:__regs_RtlUnwind eax=00000000 ebx=0031eed8 ecx=0031e8a8
edx=0031eed8 esi=00000001 edi=00000000
0130:trace:seh:__regs_RtlUnwind ebp=0031e508 esp=0031e500 eip=7bc512a6 cs=0023
ds=002b fs=0063 gs=006b flags=00000206
0130:trace:seh:__regs_RtlUnwind calling handler at 7BC460F0 code=c0000096
flags=2
0130:trace:seh:__regs_RtlUnwind handler at 7BC460F0 returned 1
0130:trace:seh:__regs_RtlUnwind calling handler at 0040C7F0 code=c0000096
flags=2
0130:trace:seh:__regs_RtlUnwind handler at 0040C7F0 returned 1
0130: select( flags=3, cookie=0031d88c, timeout=0, size=0, prev_apc=0000,
result={}, data={}, context={} )
0130: select() = TIMEOUT { call={APC_NONE}, apc_handle=0000, context={} }
0130:exception c0000096 in PE entry point
(proc=7B0272D0,module=7B000000,reason=PROCESS_ATTACH,res=0031FD24)
0130:Ret PE DLL (proc=7B0272D0,module=7B000000
L"kernelbase.dll",reason=PROCESS_ATTACH,res=0031FD24) retval=0
0130:Call PE DLL (proc=7B0272D0,module=7B000000
L"kernelbase.dll",reason=PROCESS_DETACH,res=0031FD24)
0130:Ret PE DLL (proc=7B0272D0,module=7B000000
L"kernelbase.dll",reason=PROCESS_DETACH,res=0031FD24) retval=1
0130:err:module:LdrInitializeThunk "kernelbase.dll" failed to initialize,
aborting
0130:err:module:LdrInitializeThunk Initializing dlls for L"C:\\Program Files
(x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe" failed, status c0000096
0130: terminate_process( handle=ffffffff, exit_code=-1073741674 )
0130: terminate_process() = 0 { self=1 }
0130: *killed* exit_code=-1073741674
--- snip ---
The crash is in kernelbase:init_locale() which calls RegCreateKeyExW ->
NtCreateKey()
NtCreateKey() happens to be the first of the hooked native API functions being
called.
Wine source:
https://source.winehq.org/git/wine.git/blob/70d77a439ab58dcf56664d1545aa0c4cd3edb31e:/dlls/kernelbase/locale.c#l699
--- snip ---
699 /***********************************************************************
700 * init_locale
701 */
702 void init_locale(void)
703 {
704 UINT ansi_cp = 0, oem_cp = 0;
705 USHORT *ansi_ptr, *oem_ptr;
706 void *sort_ptr;
707 LCID lcid = GetUserDefaultLCID();
708 WCHAR bufferW[80];
709 DYNAMIC_TIME_ZONE_INFORMATION timezone;
710 GEOID geoid = GEOID_NOT_AVAILABLE;
711 DWORD count, dispos, i;
712 SIZE_T size;
713 HKEY hkey;
714
715 kernel32_handle = GetModuleHandleW( L"kernel32.dll" );
716
717 GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE |
LOCALE_RETURN_NUMBER,
718 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR) );
719 GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE |
LOCALE_RETURN_NUMBER,
720 (WCHAR *)&mac_cp, sizeof(mac_cp)/sizeof(WCHAR) );
721 GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTCODEPAGE |
LOCALE_RETURN_NUMBER,
722 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR) );
723
724 NtGetNlsSectionPtr( 9, 0, NULL, &sort_ptr, &size );
725 NtGetNlsSectionPtr( 12, NormalizationC, NULL, (void **)&norm_info,
&size );
726 init_sortkeys( sort_ptr );
727
728 if (!ansi_cp || NtGetNlsSectionPtr( 11, ansi_cp, NULL, (void
**)&ansi_ptr, &size ))
729 NtGetNlsSectionPtr( 11, 1252, NULL, (void **)&ansi_ptr, &size );
730 if (!oem_cp || NtGetNlsSectionPtr( 11, oem_cp, 0, (void **)&oem_ptr,
&size ))
731 NtGetNlsSectionPtr( 11, 437, NULL, (void **)&oem_ptr, &size );
732 NtCurrentTeb()->Peb->AnsiCodePageData = ansi_ptr;
733 NtCurrentTeb()->Peb->OemCodePageData = oem_ptr;
734 NtCurrentTeb()->Peb->UnicodeCaseTableData = sort.casemap;
735 RtlInitNlsTables( ansi_ptr, oem_ptr, sort.casemap, &nls_info );
736 RtlResetRtlTranslations( &nls_info );
737
738 RegCreateKeyExW( HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Control\\Nls",
739 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &nls_key, NULL );
...
--- snip ---
Entry point code of <ntdll.NtCreateKey> is read two times:
--- snip ---
0024:Call
KERNEL32.ReadProcessMemory(0000010c,7bc036ac,0031f7d0,00000018,0031f7cc)
ret=004614db
...
0024: read_process_memory( handle=010c, addr=7bc036ac )
0130: *signal* signal=19
0024: read_process_memory() = 0 {
data={8b,ff,55,8b,ec,5d,68,83,00,07,00,b8,00,c0,c6,7b,50,ff,50,04,c2,1c,00,90}
}
...
0024:Ret KERNEL32.ReadProcessMemory() retval=00000001 ret=004614db
0024:Call
KERNEL32.ReadProcessMemory(0000010c,7bc036ac,0031f7d4,00000010,0031f7d0)
ret=004617e7
0024: read_process_memory( handle=010c, addr=7bc036ac )
0130: *signal* signal=19
0024: read_process_memory() = 0 {
data={8b,ff,55,8b,ec,5d,68,83,00,07,00,b8,00,c0,c6,7b} }
...
0024:Ret KERNEL32.ReadProcessMemory() retval=00000001 ret=004617e7
--- snip ---
* 0x18 bytes = pre-analysis
* 0x10 bytes = unknown native API entry signature -> defaults to syscall style
The <ntdll.NtCreateKey> relay entry disassembly:
--- snip ---
7BC036AC | 8BFF | mov edi,edi | hotpatch prolog
start
7BC036AE | 55 | push ebp |
7BC036AF | 8BEC | mov ebp,esp |
7BC036B1 | 5D | pop ebp | hotpatch prolog
end
7BC036B2 | 68 83000700 | push 70083 |
7BC036B7 | B8 00C0C67B | mov eax,ntdll.7BC6C000 |
7BC036BC | 50 | push eax | not copied
7BC036BD | FF50 04 | call dword ptr ds:[eax+4] | not copied
7BC036C0 | C2 1C00 | ret 1C | not copied
7BC036C3 | 90 | nop |
--- snip ---
Wine source, emitting relay entry:
https://source.winehq.org/git/wine.git/blob/70d77a439ab58dcf56664d1545aa0c4cd3edb31e:/tools/winebuild/spec32.c#l212
--- snip ---
212 /*******************************************************************
213 * output_relay_debug
214 *
215 * Output entry points for relay debugging
216 */
217 static void output_relay_debug( DLLSPEC *spec )
218 {
...
244 output( "\t.text\n" );
245 output( "__wine_spec_relay_entry_points:\n" );
246 output( "\tnop\n" ); /* to avoid 0 offset */
247
248 for (i = spec->base; i <= spec->limit; i++)
249 {
250 ORDDEF *odp = spec->ordinals[i];
251
252 if (!needs_relay( odp )) continue;
253
254 switch (target_cpu)
255 {
256 case CPU_x86:
257 output( "\t.align %d\n", get_alignment(4) );
258 output( "\t.long 0x90909090,0x90909090\n" );
259 output( ".L__wine_spec_relay_entry_point_%d:\n", i );
260 output_cfi( ".cfi_startproc" );
261 output( "\t.byte 0x8b,0xff,0x55,0x8b,0xec,0x5d\n" ); /*
hotpatch prolog */
262 if (odp->flags & (FLAG_THISCALL | FLAG_FASTCALL)) /* add the
register arguments */
263 {
264 output( "\tpopl %%eax\n" );
265 if ((odp->flags & FLAG_FASTCALL) && get_args_size( odp ) >
4) output( "\tpushl %%edx\n" );
266 output( "\tpushl %%ecx\n" );
267 output( "\tpushl %%eax\n" );
268 }
269 output( "\tpushl $%u\n", (odp->u.func.args_str_offset << 16) |
(i - spec->base) );
270 output_cfi( ".cfi_adjust_cfa_offset 4" );
271
272 if (UsePIC)
273 {
274 output( "\tcall %s\n",
asm_name("__wine_spec_get_pc_thunk_eax") );
275 output( "1:\tleal
.L__wine_spec_relay_descr-1b(%%eax),%%eax\n" );
276 needs_get_pc_thunk = 1;
277 }
278 else output( "\tmovl $.L__wine_spec_relay_descr,%%eax\n" );
279 output( "\tpushl %%eax\n" );
280 output_cfi( ".cfi_adjust_cfa_offset 4" );
281
282 output( "\tcall *4(%%eax)\n" );
283 output_cfi( ".cfi_adjust_cfa_offset -8" );
284 if (odp->type == TYPE_STDCALL)
285 output( "\tret $%u\n", get_args_size( odp ));
286 else
287 output( "\tret\n" );
288 output_cfi( ".cfi_endproc" );
289 break;
--- snip ---
For reference, <ntdll.NtCreateKey> without relay trace (syscall style,fits into
16 bytes):
--- snip ---
7BC0B9B0 | B8 1C000000 | mov eax,1C |
7BC0B9B5 | BA D0C5C07B | mov edx,ntdll.7BC0C5D0 |
7BC0B9BA | FFD2 | call edx |
7BC0B9BC | C2 1C00 | ret 1C |
7BC0B9BF | 90 | nop |
...
7BC0C5D0 | FF25 18C0C67B | jmp dword ptr ds:[<__wine_syscall_dispatcher>]
|
--- snip ---
The parent process writes a copy of the original native API entry and
trampoline code into child process (sandbox) address space:
--- snip ---
0024:Call
KERNEL32.WriteProcessMemory(0000010c,00a8c950,019da140,00000036,0031f7cc)
ret=00430409
...
0024: write_process_memory( handle=010c, addr=00a8c950,
data={8b,ff,55,8b,ec,5d,68,83,00,07,00,b8,00,c0,c6,7b,6c,00,00,00,00,00,00,00,83,ec,08,52,8b,54,24,0c,89,54,24,08,c7,44,24,0c,50,c9,a8,00,c7,44,24,04,70,8a,41,00,5a,c3}
)
0130: *signal* signal=19
0024: write_process_memory() = 0
...
0024:Ret KERNEL32.WriteProcessMemory() retval=00000001 ret=00430409
--- snip ---
--- snip ---
00A8C950 | 8BFF | mov edi,edi | org
copy of
00A8C952 | 55 | push ebp |
NtCreateKey
00A8C953 | 8BEC | mov ebp,esp |
relay entry
00A8C955 | 5D | pop ebp |
00A8C956 | 68 83000700 | push 70083 |
00A8C95B | B8 00C0C67B | mov eax,ntdll.7BC6C000 |
00A8C960 | 6C | insb |
*boom*
00A8C962 | 0000 | add byte ptr ds:[eax],al |
00A8C964 | 0000 | add byte ptr ds:[eax],al |
00A8C966 | 0000 | add byte ptr ds:[eax],al |
00A8C967 | 00
00A8C968 | 83EC 08 | sub esp,8 |
trampoline
00A8C96C | 52 | push edx |
00A8C970 | 8B5424 0C | mov edx,dword ptr ss:[esp+C] |
00A8C974 | 895424 08 | mov dword ptr ss:[esp+8],edx |
00A8C978 | C74424 0C 50C9A800 | mov dword ptr ss:[esp+C],A8C950 |
NtCreateKey
00A8C980 | C74424 04 708A4100 | mov dword ptr ss:[esp+4],acrord32.418A70 | hook
impl.
00A8C988 | 5A | pop edx |
00A8C989 | C3 | ret |
--- snip ---
and patches original <ntdll.NtCreateKey> relay entry:
--- snip ---
0024:Call
KERNEL32.WriteProcessMemory(0000010c,7bc036ac,0031f7d4,0000000c,0031f798)
ret=004304ed
...
0024: write_process_memory( handle=010c, addr=7bc036ac,
data={b8,ff,55,8b,ec,ba,68,c9,a8,00,ff,e2} )
0130: *signal* signal=19
0024: write_process_memory() = 0
...
0024:Ret KERNEL32.WriteProcessMemory() retval=00000001 ret=004304ed
--- snip ---
Patched <ntdll.NtCreateKey> relay entry:
--- snip ---
7BC036AC | B8 FF558BEC | mov eax,EC8B55FF |
garbage #sysc
7BC036B1 | BA 68C9A800 | mov edx,A8C968 |
trampoline
7BC036B6 | FFE2 | jmp edx |
--- snip ---
It crashes when the hook calls the original relay entry code which was only
partially copied.
For reference how it looks like without relay - working as intended:
--- snip ---
00576950 | B8 1C000000 | mov eax,1C | org
copy of
00576955 | BA D0C5C07B | mov edx,ntdll.7BC0C5D0 |
NtCreateKey
0057695A | FFD2 | call edx |
entry
0057695C | C2 1C00 | ret 1C |
0057695F | 90 | nop |
00576960 | 6C | insb | fill
00576961 | 0000 | add byte ptr ds:[eax],al |
00576963 | 0000 | add byte ptr ds:[eax],al |
00576965 | 0000 | add byte ptr ds:[eax],al |
00576967 | 00
00576968 | 83EC 08 | sub esp,8 |
trampoline
0057696C | 52 | push edx |
00576970 | 895424 08 | mov dword ptr ss:[esp+8],edx |
00576974 | C74424 0C 50695700 | mov dword ptr ss:[esp+C],576950 |
NtCreateKey
0057697C | C74424 04 708A4100 | mov dword ptr ss:[esp+4],acrord32.418A70 | hook
impl.
00576984 | 5A | pop edx |
00576985 | C3 | ret |
--- snip ---
Patched <ntdll.NtCreateKey> entry:
--- snip ---
7BC0B9B0 | B8 1C000000 | mov eax,1C | org
#sysc
7BC0B9B5 | BA 68695700 | mov edx,576968 |
trampoline
7BC0B9BA | FFE2 | jmp edx
7BC0B9BC | C2 1C00 | retn 1C
7BC0B9BF | 90 | nop
--- snip ---
Yes, I know it's possible to disable relay thunks for native API (RelayExclude
-> ntdll.*), even for a sub-set (the ones being hooked) to avoid crashes.
Maybe something can be done without resorting to that functionality. If it's
not worth to do extra handling for NT syscall relay thunks then you might
resolve this one as 'WONTFIX'.
$ sha1sum AdbeRdr11004_en_US.exe
9c295c16d374735bf292ef6c630c9ab392c22500 AdbeRdr11004_en_US.exe
$ du -sh AdbeRdr11004_en_US.exe
49M AdbeRdr11004_en_US.exe
$ wine --version
wine-5.21
Regards
--
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