http://bugs.winehq.org/show_bug.cgi?id=23283
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |focht@gmx.net
--- Comment #2 from Anastasius Focht focht@gmx.net 2010-06-20 15:26:34 --- Hello,
Wine bug unearthed by an "ElsterFormular" application bug ;-)
Prerequisites: vcrun6 and some (free) pdf reader application to use "print preview" (app internally exports/generates .pdf).
--- quote --- wine: Unhandled exception 0xc0000409 at address 0x42f6e2 (thread 001c), starting debugger... --- quote ---
This exception is caused by the app's internal runtime detecting a stack corruption (it uses stack security cookies). Basically after calling shell32.FindExecutableW() the stack got corrupted. For the interested how stack cookies work: http://msdn.microsoft.com/en-us/library/aa290051.aspx
Annotated app callstack before entering shell32.FindExecutableW():
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
--- snip app stack --- 003396BC 041CA512 lpFile = "C:\users\focht\Application Data\elsterformular\pica\tmp\100620205722_ElsterPrintPreview.pdf" 003396C0 00000000 lpDirectory = NULL 003396C4 0033970C lpResult = 0033970C ... ; lpResult buffer starts here 0033970C 00000000 ... ; stack security cookie 0033980C 5A6E2810 ; points to next SEH record 00339810 00339868 ; structured exception handler 00339814 00444702 00339818 00000007 ; return to caller 0033981C 004167C0 ... --- snip app stack ---
dlls/shell32/shlexec.c:FindExecutableW -> SHELL_FindExecutable()
SHELL_FindExecutableByOperation() is used to determine the executable to be launched with certain registered filetype (.pdf extension registered):
--- snip dlls/shell32/shlexec.c --- static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, LPWSTR lpResult, int resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args) {
... if (*filetype) { /* pass the operation string to SHELL_FindExecutableByOperation() */ retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, command, sizeof(command));
if (retval > 32) { DWORD finishedLen; SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen); if (finishedLen > resultLen) ERR("Argify buffer not large enough.. truncated\n"); ... --- snip dlls/shell32/shlexec.c ---
Resulting in -> ""C:\Program Files\Tracker Software\PDF Viewer\PDFXCview.exe" "%1"" (the pdf viewer I installed for this purpose). Replacing "%1" -> "C:\users\focht\Application Data\elsterformular\pica\tmp\100620205722_ElsterPrintPreview.pdf"
What happens is that the output buffer (lpResult) of FindExecutableW() caller will actually contain two strings in argv-style: executable and file name up to MAX_PATH. This is wrong - the app buffer should never get the %1 (filename) parameter (even if it's "invisible" due to null terminator in between) - it only requested executable name - an unfortunate side effect of Wine's code sharing at this place.
I already mentioned this Wine bug was unearthed by an application bug. As you can see in annotated stack snippet, the application didn't bother to provide what Microsoft suggests for lpResult: MAX_PATH length (http://msdn.microsoft.com/en-us/library/bb776419.aspx). Even if Wine fixes the problem by only copying executable path - if the pdf executable path is long enough, it will most likely also corrupt the stack on Windows.
Someone should tell these guys how to write "secure" software: https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/738-BSI.html
But what can you expect from people that use german identifiers all over the place for their classes, functions, variables and the like .. that's pure coding horror (never heard of industry standards?). Run the app with WINEDEBUG=+debugstr and see what I mean ...
Regards