[Bug 44460] New: Wine' s loader should prevent multiple executable mappings of images (dlls) backed by the same physical file (long path vs. short path)
wine-bugs at winehq.org
wine-bugs at winehq.org
Thu Feb 1 15:58:57 CST 2018
https://bugs.winehq.org/show_bug.cgi?id=44460
Bug ID: 44460
Summary: Wine's loader should prevent multiple executable
mappings of images (dlls) backed by the same physical
file (long path vs. short path)
Product: Wine
Version: 3.0
Hardware: x86-64
OS: Linux
Status: NEW
Severity: normal
Priority: P2
Component: ntdll
Assignee: wine-bugs at winehq.org
Reporter: focht at gmx.net
Distribution: ---
Hello folks,
split out from bug 35106 because there are multiple issues and this one affects
a different area: Wine loader.
Currently, loading a dll with default load flags one time with long path name
and the other time with short path name (= same physical file) results in two
different mappings of the dll which creates problems with apps expecting unique
instance data.
In short: Wine's loader currently lacks a more elaborate identity check to
prevent this case.
CMS DVR (video surveillance app) v1.0.0.8 uses multiple MFC-based ActiveX/COM
servers.
Taking the first one 'WndManager.ocx' as example:
--- snip ---
-=[ ProtectionID v0.6.9.0 DECEMBER]=-
(c) 2003-2017 CDKiLLER & TippeX
Build 24/12/17-21:05:42
Ready...
Scanning -> C:\Program Files\CMS\WndManager.ocx
File Type : 32-Bit Dll (Subsystem : Win GUI / 2), Size : 266240 (041000h)
Byte(s) | Machine: 0x14C (I386)
Compilation TimeStamp : 0x4B583655 -> Thu 21st Jan 2010 11:11:17 (GMT)
[TimeStamp] 0x4B583655 -> Thu 21st Jan 2010 11:11:17 (GMT) | PE Header | - |
Offset: 0x000000F8 | VA: 0x100000F8 | -
[TimeStamp] 0x4B583655 -> Thu 21st Jan 2010 11:11:17 (GMT) | Export | - |
Offset: 0x00020A74 | VA: 0x10020A74 | -
[LoadConfig] CodeIntegrity -> Flags 0xA3F0 | Catalog 0x46 (70) | Catalog Offset
0x2000001 | Reserved 0x46A4A0
[LoadConfig] GuardAddressTakenIatEntryTable 0x8000011 | Count 0x46A558
(4629848)
[LoadConfig] GuardLongJumpTargetTable 0x8000001 | Count 0x46A5F8 (4630008)
[LoadConfig] HybridMetadataPointer 0x8000011 | DynamicValueRelocTable 0x46A66C
[LoadConfig] FailFastIndirectProc 0x8000011 | FailFastPointer 0x46C360
[LoadConfig] UnknownZero1 0x8000011
[File Heuristics] -> Flag #1 : 00000000000000000000010100000000 (0x00000500)
[Entrypoint Section Entropy] : 5.56 (section #0) ".text " | Size : 0x1B276
(111222) byte(s)
[DllCharacteristics] -> Flag : (0x0000) -> NONE
[SectionCount] 5 (0x5) | ImageSize 0x44000 (278528) byte(s)
[Export] 100% of function(s) (4 of 4) are in file | 0 are forwarded | 4 code |
0 data | 0 uninit data | 0 unknown |
[VersionInfo] Product Name : VideoWindow ActiveX Control Module
[VersionInfo] Product Version : 1. 0. 0. 4
[VersionInfo] File Description : VideoWindow ActiveX Control Module
[VersionInfo] File Version : 1. 0. 0. 4
[VersionInfo] Original FileName : VideoWindow.OCX
[VersionInfo] Internal Name : VideoWindow
[VersionInfo] Legal Copyrights : Copyright (C) 2006
[ModuleReport] [IAT] Modules -> MFC42.DLL | MSVCRT.dll | KERNEL32.dll |
USER32.dll | GDI32.dll | COMCTL32.dll | ole32.dll | OLEPRO32.DLL | OLEAUT32.dll
[!] File appears to have no protection or is using an unknown protection
- Scan Took : 0.224 Second(s) [0000000E0h (224) tick(s)] [246 of 580 scan(s)
done]
--- snip ---
The app explicitly loads its ActiveX/OCX to register these inproc servers
(registry):
--- snip ---
$ pwd
/home/focht/.wine/drive_c/Program Files/CMS
...
002d:Call KERNEL32.LoadLibraryA(01421b78 "C:\\Program
Files\\CMS\\WndManager.ocx") ret=00404efc
...
002d:Call PE DLL (proc=0x154b467,module=0x1530000
L"WndManager.ocx",reason=PROCESS_ATTACH,res=(nil))
...
002d:Ret PE DLL (proc=0x154b467,module=0x1530000
L"WndManager.ocx",reason=PROCESS_ATTACH,res=(nil)) retval=1
002d:Ret KERNEL32.LoadLibraryA() retval=01530000 ret=00404efc
002d:Call KERNEL32.GetProcAddress(01530000,0050d090 "DllRegisterServer")
ret=00404fa9
002d:Ret KERNEL32.GetProcAddress() retval=01580022 ret=00404fa9
002d:CALL VIDEOWINDOW.OCX.DllRegisterServer(<unknown, check return>)
ret=00404fb3
...
002d:CALL MFC42.1212(<unknown, check return>) ret=01545e8f
002d:Call KERNEL32.LoadLibraryA(5f49ed88 "ole32.dll") ret=5f405b81
002d:Ret KERNEL32.LoadLibraryA() retval=7e580000 ret=5f405b81
...
002d:Call KERNEL32.GetProcAddress(7e580000,5f4c5ace "StringFromGUID2")
ret=5f405b3f
002d:Ret KERNEL32.GetProcAddress() retval=7e58ba80 ret=5f405b3f
002d:Call ole32.StringFromGUID2(01553df0,0032bf28,00000027) ret=5f4392e7
002d:Ret ole32.StringFromGUID2() retval=00000027 ret=5f4392e7
002d:Call KERNEL32.lstrlenW(0032bf28 L"{2FBB7C49-53D0-4FFF-B3A0-B3880750976A}")
ret=5f43931c
002d:Ret KERNEL32.lstrlenW() retval=00000026 ret=5f43931c
002d:Call KERNEL32.WideCharToMultiByte(00000000,00000000,0032bf28
L"{2FBB7C49-53D0-4FFF-B3A0-B3880750976A}",ffffffff,0032bdc8,0000004e,00000000,00000000)
ret=5f439345
002d:Ret KERNEL32.WideCharToMultiByte() retval=00000027 ret=5f439345
002d:Call KERNEL32.GetModuleFileNameA(01530000,0032bcb4,00000104) ret=5f411dc5
002d:Ret KERNEL32.GetModuleFileNameA() retval=00000023 ret=5f411dc5
002d:Call msvcrt.memcpy(00fd04a0,5f4d1c58,00000001) ret=5f402437
002d:Ret msvcrt.memcpy() retval=00fd04a0 ret=5f402437
002d:Call KERNEL32.GetShortPathNameA(0032bcb4 "C:\\Program
Files\\CMS\\WndManager.ocx",00fd04a0,00000104) ret=5f411ddd
002d:Ret KERNEL32.GetShortPathNameA() retval=0000001c ret=5f411ddd
002d:Call KERNEL32.lstrlenA(00fd04a0 "C:\\PROG~FBU\\CMS\\WNDM~VNJ.OCX")
ret=5f40248f
002d:Ret KERNEL32.lstrlenA() retval=0000001c ret=5f40248f
002d:Call KERNEL32.FindResourceA(01530000,00000001,00000006) ret=5f403a4e
002d:Ret KERNEL32.FindResourceA() retval=01556f98 ret=5f403a4e
002d:Call user32.LoadStringA(01530000,00000002,0032bcb8,00000100) ret=5f403a5e
002d:Ret user32.LoadStringA() retval=00000019 ret=5f403a5e
002d:Call KERNEL32.lstrlenA(0032bcb8 "VideoWindow Property Page") ret=5f4038d7
002d:Ret KERNEL32.lstrlenA() retval=00000019 ret=5f4038d7
002d:Call msvcrt.memcpy(00fce610,0032bcb8,00000019) ret=5f403905
002d:Ret msvcrt.memcpy() retval=00fce610 ret=5f403905
...
002d:Call KERNEL32.GetProcAddress(7e9d0000,5f4c549a "RegCreateKeyA")
ret=5f405b3f
002d:Ret KERNEL32.GetProcAddress() retval=7e9dcd60 ret=5f405b3f
002d:Call advapi32.RegCreateKeyA(80000000,0032be24
"CLSID\\{2FBB7C49-53D0-4FFF-B3A0-B3880750976A}",0032bfa8) ret=5f4393b1
002d:Ret advapi32.RegCreateKeyA() retval=00000000 ret=5f4393b1
...
--- snip ---
The interesting part is that all inproc server paths are created with short
path name in registry (see 'GetShortPathNameA' calls).
I found little information on the "why". This seems to be MFC built-in/enforced
behaviour, for example mentioned here:
https://jeffpar.github.io/kbarchive/kb/179/Q179690/
--- quote ---
MFC uses short file names for registration.
--- quote ---
Later the same ActiveX/inproc server was loaded using 'ole32.CoGetClassObject'
which used the short path name from registry data but still referred to the
same physical file.
To my surprise it was mapped a second time at a different base address
0x2ab0000 (relocated), resulting in another set of instance data.
--- snip ---
...
002d:Call ole32.CoGetClassObject(0032a304,00000003,00000000,0050bddc,00329fa0)
ret=004b34b4
002d:Call
KERNEL32.FindActCtxSectionGuid(00000001,00000000,00000004,0032a304,00329e40)
ret=7e59e1f6
002d:Ret KERNEL32.FindActCtxSectionGuid() retval=00000000 ret=7e59e1f6
002d:Call ntdll.RtlInitUnicodeString(00329cd4,7e665600
L"\\Registry\\Machine\\Software\\Classes") ret=7e598c09
002d:Ret ntdll.RtlInitUnicodeString() retval=00329cd4 ret=7e598c09
002d:Call
ntdll.NtCreateKey(00329cf4,02000000,00329cdc,00000000,00000000,00000000,00000000)
ret=7e598a08
002d:Ret ntdll.NtCreateKey() retval=00000000 ret=7e598a08
002d:Call ntdll.RtlInitUnicodeString(00329d70,00329dc2
L"CLSID\\{6AD651C3-AB21-4FCB-90D8-FB1396B04A07}") ret=7e598e9a
002d:Ret ntdll.RtlInitUnicodeString() retval=00329d70 ret=7e598e9a
002d:Call ntdll.NtOpenKey(00329dbc,00020019,00329d78) ret=7e598eaf
002d:Ret ntdll.NtOpenKey() retval=00000000 ret=7e598eaf
002d:Call ntdll.RtlNtStatusToDosError(00000000) ret=7e598ebb
002d:Ret ntdll.RtlNtStatusToDosError() retval=00000000 ret=7e598ebb
002d:Call ntdll.RtlInitUnicodeString(00329d70,7e666c48 L"InprocServer32")
ret=7e598e9a
002d:Ret ntdll.RtlInitUnicodeString() retval=00329d70 ret=7e598e9a
002d:Call ntdll.NtOpenKey(00329e84,00020019,00329d78) ret=7e598eaf
002d:Ret ntdll.NtOpenKey() retval=00000000 ret=7e598eaf
002d:Call ntdll.RtlNtStatusToDosError(00000000) ret=7e598ebb
002d:Ret ntdll.RtlNtStatusToDosError() retval=00000000 ret=7e598ebb
002d:Call advapi32.RegCloseKey(00000170) ret=7e59cf21
002d:Ret advapi32.RegCloseKey() retval=00000000 ret=7e59cf21
002d:Call advapi32.RegQueryValueExW(00000174,7e666bd0
L"ThreadingModel",00000000,00329ba0,00329ba8,00329ba4) ret=7e59dd41
002d:Ret advapi32.RegQueryValueExW() retval=00000000 ret=7e59dd41
002d:Call
advapi32.RegQueryValueExW(00000174,00000000,00000000,00329bac,0032999c,00329ba8)
ret=7e59b18a
002d:Ret advapi32.RegQueryValueExW() retval=00000000 ret=7e59b18a
...
002d:Call KERNEL32.LoadLibraryExW(00329bee
L"C:\\PROG~FBU\\CMS\\WNDM~VNJ.OCX",00000000,00000008) ret=7e598ff2
...
002d:Call PE DLL (proc=0x2acb467,module=0x2ab0000
L"WNDM~VNJ.OCX",reason=PROCESS_ATTACH,res=(nil))
002d:Call KERNEL32.LocalAlloc(00000000,00002000) ret=02acb1be
...
--- snip ---
Winedbg:
--- snip ---
Wine-dbg>bt
Backtrace:
=>0 0x7b463443 MODULE_get_dll_load_path(module="C:\PROG~FBU\CMS\WNDM~VNJ.OCX",
safe_mode=0xffffffff)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/module.c:974] in
kernel32 (0x00329ba8)
1 0x7b463df7 LoadLibraryExW+0x73(libnameW=<couldn't compute location>,
hfile=<couldn't compute location>, flags=<couldn't compute location>)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/module.c:1272] in
kernel32 (0x00329bd8)
2 0x7e5a6ff2
COMPOBJ_DllList_Add+0x8d(library_name="C:\PROG~FBU\CMS\WNDM~VNJ.OCX",
ret=0x1c7dcf8)
[/home/focht/projects/wine/wine.repo/src/dlls/ole32/compobj.c:521] in ole32
(0x00329c48)
3 0x7e5a8fe1 apartment_getclassobject+0x1d3(apt=0x1f7ed08,
dllpath="C:\PROG~FBU\CMS\WNDM~VNJ.OCX", apartment_threaded=0x1,
rclsid=0x32a3c4, riid=0x50bddc, ppv=0x32a060)
[/home/focht/projects/wine/wine.repo/src/dlls/ole32/compobj.c:1366] in ole32
(0x00329cb8)
4 0x7e5abfbb get_inproc_class_object+0x1e1(apt=0x1f7ed08, regdata=0x329f8c,
rclsid=0x32a3c4, riid=0x50bddc, hostifnecessary=0x1, ppv=0x32a060)
[/home/focht/projects/wine/wine.repo/src/dlls/ole32/compobj.c:2954] in ole32
(0x00329f18)
5 0x7e5ac42d CoGetClassObject+0x457(rclsid=<couldn't compute location>,
dwClsContext=<couldn't compute location>, pServerInfo=<couldn't compute
location>, iid=<couldn't compute location>, ppv=<couldn't compute location>)
[/home/focht/projects/wine/wine.repo/src/dlls/ole32/compobj.c:3094] in ole32
(0x0032a018)
6 0x004b34b4 in cms (+0xb34b3) (0x0032a044)
7 0x004b4d92 in cms (+0xb4d91) (0x0032a0e8)
8 0x004b48d4 in cms (+0xb48d3) (0x0032a158)
9 0x004b344b in cms (+0xb344a) (0x0032a1c8)
10 0x004aeace in cms (+0xaeacd) (0x0032a224)
11 0x004aebb1 in cms (+0xaebb0) (0x0032a298)
12 0x004aef64 in cms (+0xaef63) (0x0032a2f0)
13 0x004abc5d in cms (+0xabc5c) (0x0032a38c)
14 0x0032a3b0 (0x0032a38c)
...
--- snip ---
Another session, showing the same dll present two times:
--- snip ---
Wine-dbg>info share
Module Address Debug info Name (100 modules)
PE 340000- 36f000 Export h264play
PE 370000- 380000 Export dlldeinterlace
PE 380000- 391000 Export streamreader
PE 3a0000- 3ab000 Export password
PE 400000- 5c7000 Export cms
PE 5d0000- 659000 Export playback
PE 660000- 736000 Export configmodule
PE 740000- 7ae000 Export localrecord
PE 1480000- 14c4000 Export wndmanager
PE 14d0000- 1571000 Export mapctrl
PE 2380000- 23c4000 Deferred wndm~vnj
PE 10000000-10083000 Export netsdk
PE 5f400000-5f4f2000 Export mfc42
ELF 7a800000-7a949000 Dwarf opengl32<elf>
\-PE 7a840000-7a949000 \ opengl32
ELF 7b400000-7b7f0000 Dwarf kernel32<elf>
\-PE 7b420000-7b7f0000 \ kernel32
ELF 7bc00000-7bd0a000 Dwarf ntdll<elf>
\-PE 7bc30000-7bd0a000 \ ntdll
ELF 7c000000-7c004000 Dwarf <wine-loader>
...
--- snip ---
wndmanager -> 0x1480000 (by long path name "C:\\Program
Files\\CMS\\WndManager.ocx"))
wndm~vnj -> 0x2380000 (by short path name "C:\\PROG~FBU\\CMS\\WNDM~VNJ.OCX")
To avoid this, Wine loader 'load_native_dll' function needs to implement
additional checks after creating the file-backed section view, before doing
anything further (reloc fixups, allocating module entry, ...).
Essentially walk the current module list and for each entry:
* basic (quick) check: time/date stamp and image size against NT file header
data from the newly created section view (NOTE: 'alloc_module' currently
doesn't copy 'TimeDateStamp' from 'FileHeader.TimeDateStamp' which is needed
for comparison)
* memory compare IMAGE_NT_HEADERS
* use NtAreMappedFilesTheSame() to check if the views from the image sections
are backed by the same physical file
If these conditions are met, the existing module entry shall be used and the
new mapping must be destroyed (NtUnmapViewOfSection).
I've already tested this using an own prototype. It seems to work fine without
breaking other apps.
NOTE: It doesn't prevent the crash reported in bug 35106 (another issue,
unrelated to loader) but makes Wine more compliant with Windows OS loader
behaviour.
$ sha1sum General_CMS_Eng_V1.0.0.8.T.20101202.exe
902e9408ebfc295ce2477fe3d9ca05e8a7588589
General_CMS_Eng_V1.0.0.8.T.20101202.exe
$ du -sh General_CMS_Eng_V1.0.0.8.T.20101202.exe
4.7M General_CMS_Eng_V1.0.0.8.T.20101202.exe
$ wine --version
wine-3.0-260-gdf715e5a9a
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