http://bugs.winehq.org/show_bug.cgi?id=30543
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |focht@gmx.net Summary|K32GetModuleFileNameExW |Multiple apps |segfault |crash/terminate because | |K32GetModuleFileNameExW | |overflows supplied buffer
--- Comment #7 from Anastasius Focht focht@gmx.net 2012-05-01 07:01:11 CDT --- Hello,
I encountered this problem with another app which also indicates K32GetModuleFileNameExW() needs some more fixing.
Download: http://download.sonymediasoftware.com/current/cdarchitect52d-trial_enu.exe
(needs 'winetricks -q mfc42' prerequisite, ignore the other bugs from installer)
The app collects process module information on startup using EnumProcesses/EnumProcessModules/GetModuleFileNameExW sequence. It fails and terminates silently with 0xC0000409 (stack overflow). Winedbg doesn't have a chance to attach due to bug 24038
App code, showing the problem (annotated):
--- snip --- 005240F0 SUB ESP,234 005240F6 MOV EAX,DWORD PTR DS:[625C1C] ; global security cookie 005240FB XOR EAX,ESP 005240FD MOV DWORD PTR SS:[ESP+230],EAX ; store local canary on stack 00524104 MOV EAX,DWORD PTR SS:[ESP+238] 0052410B MOV ECX,DWORD PTR SS:[ESP+23C] ... 00524143 PUSH EBX 00524144 PUSH EDI 00524145 MOV EDI,DWORD PTR DS:[<&KERNEL32.GetProcAddress>] 0052414B PUSH OFFSET 005F65B4 ; Procname = "EnumProcesses" 00524150 PUSH EBP ; hModule 00524151 CALL EDI ; KERNEL32.GetProcAddress 00524153 PUSH OFFSET 005F65A0 ; "EnumProcessModules" 00524158 PUSH EBP 00524159 MOV DWORD PTR SS:[ESP+20],EAX ; KERNEL32.EnumProcesses 0052415D CALL EDI ; KERNEL32.GetProcAddress 0052415F PUSH OFFSET 005F6588 ; "GetModuleFileNameExW" 00524164 MOV EBX,EAX 00524166 PUSH EBP 00524167 MOV DWORD PTR SS:[ESP+38],EBX ; KERNEL32.EnumProcessModules 0052416B CALL EDI ; KERNEL32.GetProcAddress 0052416D CMP DWORD PTR SS:[ESP+18],ESI 00524171 MOV DWORD PTR SS:[ESP+28],EAX ; KERNEL32.GetModuleFileNameExW ... 00524197 MOV EDI,400 ... 005241D9 LEA EDX,[ESP+24] 005241DD PUSH EDX 005241DE PUSH EDI ; 0x400 005241DF PUSH ESI ; heap buffer (GlobalAlloc) 005241E0 CALL DWORD PTR SS:[ESP+24] ; KERNEL32.EnumProcesses 005241E4 TEST EAX,EAX ... 00524206 PUSH EAX ; ProcessID 00524207 PUSH 0 ; InheritHandle = FALSE 00524209 PUSH 410 ; Access = PROCESS_VM_READ|PROCESS_QUERY_INFORMATION 0052420E CALL DWORD PTR DS:[<&KERNEL32.OpenProcess>] ; KERNEL32.OpenProcess 00524214 MOV EBX,EAX ... 0052421E LEA ECX,[ESP+34] 00524222 PUSH ECX 00524223 PUSH 4 00524225 LEA EDX,[ESP+20] 00524229 PUSH EDX 0052422A PUSH EBX ; hProcess 0052422B CALL DWORD PTR SS:[ESP+40] ; KERNEL32.EnumProcessModules 0052422F TEST EAX,EAX ... 00524233 MOV ECX,DWORD PTR SS:[ESP+18] 00524237 PUSH 104 ; 0x104 (size of the filename buffer, in characters) 0052423C LEA EAX,[ESP+3C] 00524240 PUSH EAX ; stack buffer for filename 00524241 PUSH ECX ; hModule 00524242 PUSH EBX ; hProcess 00524243 CALL DWORD PTR SS:[ESP+38] ; KERNEL32.GetModuleFileNameExW 00524247 TEST EAX,EAX ; 0x20 ... 005242A0 MOV ECX,DWORD PTR SS:[ESP+238] ; get local canary back 005242A7 XOR EAX,EAX 005242A9 CMP DWORD PTR SS:[ESP+8],EAX ... <security cookie mismatch throw 0xC0000409 and terminate process> --- snip ---
The problem is that the local canary is partly overwritten by Wine after return from kernel32.GetModuleFileNameExW().
0033E370 - buffer start for filename 0033E578 - stack canary
0033E370 + 0x104*2 = 0033E578
Before the call:
$+0 = start of buffer for filename
--- snip --- $+204 00000023 $+208 C1D9AC35 $+20C 00524384 --- snip ---
After the call:
--- snip --- $+0 003A0043 C: $+4 0077005C \w $+8 006E0069 in $+C 006F0064 do $+10 00730077 ws $+14 0073005C \s $+18 00730079 ys $+1C 00650074 te $+20 0033006D m3 $+24 005C0032 2\ $+28 00650073 se $+2C 00760072 rv $+30 00630069 ic $+34 00730065 es $+38 0065002E .e $+3C 00650078 xe $+40 003B0000 .; ... <garbage data due to ReadProcessMemory reading more than needed> ... $+204 00000010 $+208 C1D90000 $+20C 00524384 --- snip ---
The canary was touched by Wine with following code (line 1268):
Source: http://source.winehq.org/git/wine.git/blob/d08f34cd8ecd883a0f0c6bd9b150d9240...
--- quote --- 1246 DWORD WINAPI K32GetModuleFileNameExW(HANDLE process, HMODULE module, 1247 LPWSTR file_name, DWORD size) 1248 { 1249 LDR_MODULE ldr_module; 1250 DWORD len; 1251 1252 if (!size) return 0; 1253 1254 if(!get_ldr_module(process, module, &ldr_module)) 1255 return 0; 1256 1257 len = ldr_module.FullDllName.Length / sizeof(WCHAR); 1258 if (size <= len) 1259 { 1260 len = size; 1261 size--; 1262 } 1263 1264 if (!ReadProcessMemory(process, ldr_module.FullDllName.Buffer, 1265 file_name, size * sizeof(WCHAR), NULL)) 1266 return 0; 1267 1268 file_name[size] = 0; 1269 return len; 1270 } --- quote ---
Alexandre partly fixed some overflow when the caller supplied buffer was too small with: http://source.winehq.org/git/wine.git/commitdiff/d08f34cd8ecd883a0f0c6bd9b15...
There is garbage written to the buffer following the module name if the supplied buffer size exceeds "ldr_module.FullDllName.Length". Not sure if this is intended...
At least line 1268 is wrong, it writes past the end of buffer, destroying the stack canary for the app. The module name/path which is much shorter than supplied buffer and is already NULL-terminated in between (see dump).
$ du -sh cdarchitect52d-trial_enu.exe 30M cdarchitect52d-trial_enu.exe
$ sha1sum cdarchitect52d-trial_enu.exe 045cfb932746810b2bfb52594f31926be11ebb73 cdarchitect52d-trial_enu.exe
$ wine --version wine-1.5.3-40-g9080f3c
Regards