https://bugs.winehq.org/show_bug.cgi?id=39569
Bug ID: 39569 Summary: Multiple applications using ntdll.NtQueryObject 'ObjectNameInformation' info class get incorrect names for file objects Product: Wine Version: 1.7.54 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
consider the following trace:
* explicitly removed relay excludes to show internal calls * Wine builtin as example
--- snip --- ... 002a:Call KERNEL32.CreateFileW(00326840 L"C:\windows\notepad.exe",80000000,00000001,00000000,00000003,00000000,00000000) ret=00b16742 002a:Call ntdll.RtlIsDosDeviceName_U(00326840 L"C:\windows\notepad.exe") ret=7f40b89ac80d 002a:Ret ntdll.RtlIsDosDeviceName_U() retval=00000000 ret=7f40b89ac80d 002a:Call ntdll.RtlDosPathNameToNtPathName_U(00326840 L"C:\windows\notepad.exe",0269d820,00000000,00000000) ret=7f40b89ac99c 002a:Ret ntdll.RtlDosPathNameToNtPathName_U() retval=00000001 ret=7f40b89ac99c 002a:Call ntdll.NtCreateFile(0269d808,80100000,0269d830,0269d810,00000000,00000000,00000001,f00000001,00000060,00000000,00000000) ret=7f40b89acb9b 002a:trace:ntdll:FILE_CreateFile handle=0x269d808 access=80100000 name=L"\??\C:\windows\notepad.exe" objattr=00000040 root=(nil) sec=(nil) io=0x269d810 alloc_size=(nil) attr=00000000 sharing=00000001 disp=1 options=00000060 ea=(nil).0x00000000 002a: create_file( access=80100000, attributes=00000040, sharing=00000001, create=1, options=00000060, attrs=00000000, objattr={rootdir=0000,sd={},name=L""}, filename="/home/focht/wine64/dosdevices/c:/windows/notepad.exe" ) 002a: create_file() = 0 { handle=0384 } 002a:Ret ntdll.NtCreateFile() retval=00000000 ret=7f40b89acb9b ... 002a:Ret KERNEL32.CreateFileW() retval=00000384 ret=00b16742 ... 002a:Call ntdll.NtQueryObject(00000384,00000001,00000000,00000000,0269d778) ret=00d222ab 002a:trace:ntdll:NtQueryObject (0x384,0x00000001,(nil),0x00000000,0x269d778) 002a: get_handle_unix_name( handle=0384 ) 002a: get_handle_unix_name() = 0 { name_len=52, name="/home/focht/wine64/dosdevices/c:/windows/notepad.exe" } 002a:Ret ntdll.NtQueryObject() retval=c0000004 ret=00d222ab ... 002a:Call ntdll.NtQueryObject(00000384,00000001,000e0da0,00002046,00000000) ret=00d222f7 002a:trace:ntdll:NtQueryObject (0x384,0x00000001,0xe0da0,0x00002046,(nil)) 002a: get_handle_unix_name( handle=0384 ) 002a: get_handle_unix_name() = 0 { name_len=52, name="/home/focht/wine64/dosdevices/c:/windows/notepad.exe" } 002a:Ret ntdll.NtQueryObject() retval=00000000 ret=00d222f7 ... 002a:Call KERNEL32.QueryDosDeviceW(0269d260 L"c:",0269d270,00000104) ret=00d216f4 002a:Call ntdll.RtlIsDosDeviceName_U(0269d260 L"c:") ret=7f40b8a11373 002a:Ret ntdll.RtlIsDosDeviceName_U() retval=00000000 ret=7f40b8a11373 ... 002a:Call ntdll.RtlInitUnicodeString(0269c910,027fddf0 L"\DosDevices\c:") ret=7f40b8a0cfba 002a:Ret ntdll.RtlInitUnicodeString() retval=0269c910 ret=7f40b8a0cfba 002a:Call ntdll.NtOpenSymbolicLinkObject(0269c908,00000001,0269c920) ret=7f40b8a0cfd9 002a:trace:ntdll:NtOpenSymbolicLinkObject (0x269c908,0x00000001,{name=L"\DosDevices\c:", attr=0x00000040, hRoot=(nil), sd=(nil)} 002a: open_symlink( access=00000001, attributes=00000040, rootdir=0000, name=L"\DosDevices\c:" ) 002a: open_symlink() = 0 { handle=038c } 002a:Ret ntdll.NtOpenSymbolicLinkObject() retval=00000000 ret=7f40b8a0cfd9 002a:Call ntdll.NtQuerySymbolicLinkObject(0000038c,0269c8f0,00000000) ret=7f40b8a0d016 002a:trace:ntdll:NtQuerySymbolicLinkObject (0x38c,0x269c8f0,(nil)) 002a: query_symlink( handle=038c ) 002a: query_symlink() = 0 { total=46, target_name=L"\Device\HarddiskVolume1" } 002a:Ret ntdll.NtQuerySymbolicLinkObject() retval=00000000 ret=7f40b8a0d016 002a:Call ntdll.NtClose(0000038c) ret=7f40b8a0d04c 002a: close_handle( handle=038c ) 002a: close_handle() = 0 002a:Ret ntdll.NtClose() retval=00000000 ret=7f40b8a0d04c ... 002a:Ret KERNEL32.QueryDosDeviceW() retval=00000019 ret=00d216f4 ... 002a:Call KERNEL32.CreateFileW(02086700 L"\??\C:\windows\notepad.exe",80000000,00000001,00000000,00000003,ffffffff00000000,00000000) ret=00b71906 002a:Call ntdll.RtlIsDosDeviceName_U(02086700 L"\??\C:\windows\notepad.exe") ret=7f40b89ac80d 002a:Ret ntdll.RtlIsDosDeviceName_U() retval=00000000 ret=7f40b89ac80d 002a:Call ntdll.RtlDosPathNameToNtPathName_U(02086700 L"\??\C:\windows\notepad.exe",0269c780,00000000,00000000) ret=7f40b89ac99c 002a:Ret ntdll.RtlDosPathNameToNtPathName_U() retval=00000001 ret=7f40b89ac99c 002a:Call ntdll.NtCreateFile(0269c768,80100000,0269c790,0269c770,00000000,00000000,00000001,f00000001,00000060,00000000,00000000) ret=7f40b89acb9b 002a:trace:ntdll:FILE_CreateFile handle=0x269c768 access=80100000 name=L"\??\Z:\??\C:\windows\notepad.exe" objattr=00000040 root=(nil) sec=(nil) io=0x269c770 alloc_size=(nil) attr=00000000 sharing=00000001 disp=1 options=00000060 ea=(nil).0x00000000 002a:warn:ntdll:FILE_CreateFile L"\??\Z:\??\C:\windows\notepad.exe" not found (c0000033) 002a:Ret ntdll.NtCreateFile() retval=c0000033 ret=7f40b89acb9b 002a:Call ntdll.RtlNtStatusToDosError(c0000033) ret=7f40b89acd3c 002a:Ret ntdll.RtlNtStatusToDosError() retval=0000007b ret=7f40b89acd3c ... 002a:Ret KERNEL32.CreateFileW() retval=ffffffffffffffff ret=00b71906 ... 002b:Call KERNEL32.CreateProcessW(02032b40 L"\??\C:\windows\notepad.exe",00000000,00000000,00000000,00000000,00000013,00000000,02061e60 L"\??\C:\windows",00f6d000,00f6cef8) ret=00ef2163 002b:Call ntdll.RtlIsDosDeviceName_U(02abd720 L"\??\C:\windows\notepad.exe") ret=7f40b89ac80d 002b:Ret ntdll.RtlIsDosDeviceName_U() retval=00000000 ret=7f40b89ac80d 002b:Call ntdll.RtlDosPathNameToNtPathName_U(02abd720 L"\??\C:\windows\notepad.exe",02abcfb0,00000000,00000000) ret=7f40b89ac99c 002b:Ret ntdll.RtlDosPathNameToNtPathName_U() retval=00000001 ret=7f40b89ac99c 002b:Call ntdll.NtCreateFile(02abcf98,80100000,02abcfc0,02abcfa0,00000000,00000000,00000005,00000001,00000060,00000000,00000000) ret=7f40b89acb9b 002b:trace:ntdll:FILE_CreateFile handle=0x2abcf98 access=80100000 name=L"\??\Z:\??\C:\windows\notepad.exe" objattr=00000040 root=(nil) sec=(nil) io=0x2abcfa0 alloc_size=(nil) attr=00000000 sharing=00000005 disp=1 options=00000060 ea=(nil).0x00000000 002b:warn:ntdll:FILE_CreateFile L"\??\Z:\??\C:\windows\notepad.exe" not found (c0000033) 002b:Ret ntdll.NtCreateFile() retval=c0000033 ret=7f40b89acb9b ... 002b:Call ntdll.RtlGetFullPathName_U(02abd720 L"\??\C:\windows\notepad.exe",00000410,02abd190,02abd110) ret=7f40b89dd82b 002b:Ret ntdll.RtlGetFullPathName_U() retval=00000038 ret=7f40b89dd82b ... 002b:Ret KERNEL32.CreateProcessW() retval=00000000 ret=00ef2163 --- snip ---
Calling 'kernel32' API with native NT paths is obviously wrong and not intended here.
The relay trace partially corresponds to the following source code - at least for the preceding device/filename lookup/translation:
https://bitbucket.org/mrexodia/devicenameresolver/src/3fc6704267d469bd08633e...
--- snip --- ... __declspec(dllexport) bool DevicePathFromFileHandleW(HANDLE hFile, wchar_t* szDevicePath, size_t nSize) { NativeWinApi::initialize(); ULONG ReturnLength; bool bRet=false; if(NativeWinApi::NtQueryObject(hFile, ObjectNameInformation, 0, 0, &ReturnLength)==STATUS_INFO_LENGTH_MISMATCH) { ReturnLength+=0x2000; //on Windows XP SP3 ReturnLength will not be set just add some buffer space to fix this POBJECT_NAME_INFORMATION NameInformation=(POBJECT_NAME_INFORMATION)GlobalAlloc(0, ReturnLength); if(NativeWinApi::NtQueryObject(hFile, ObjectNameInformation, NameInformation, ReturnLength, 0)==STATUS_SUCCESS) { NameInformation->Name.Buffer[NameInformation->Name.Length/2]=L'\0'; //null-terminate the UNICODE_STRING if(wcslen(NameInformation->Name.Buffer)<nSize) { wcscpy_s(szDevicePath, nSize/sizeof(wchar_t), NameInformation->Name.Buffer); bRet=true; } } GlobalFree(NameInformation); } if(_wcsnicmp(szDevicePath, L"\Device\LanmanRedirector\", 25) == 0) // Win XP { wcscpy_s(szDevicePath, nSize / sizeof(wchar_t), L"\\"); wcscat_s(szDevicePath, nSize / sizeof(wchar_t), &szDevicePath[25]); } else if(_wcsnicmp(szDevicePath, L"\Device\Mup\", 12) == 0) // Win 7 { wcscpy_s(szDevicePath, nSize / sizeof(wchar_t), L"\\"); wcscat_s(szDevicePath, nSize / sizeof(wchar_t), &szDevicePath[12]); } return bRet; }
__declspec(dllexport) bool DevicePathFromFileHandleA(HANDLE hFile, char* szDevicePath, size_t nSize) { DynBuf newDevicePathBuf(nSize*sizeof(wchar_t)); wchar_t* newDevicePath = (wchar_t*)newDevicePathBuf.GetPtr(); if(!DevicePathFromFileHandleW(hFile, newDevicePath, nSize*sizeof(wchar_t))) return false; if(!WideCharToMultiByte(CP_ACP, NULL, newDevicePath, -1, szDevicePath, (int)wcslen(newDevicePath)+1, NULL, NULL)) return false; return true; }
__declspec(dllexport) bool PathFromFileHandleW(HANDLE hFile, wchar_t* szPath, size_t nSize) { typedef DWORD (WINAPI* GETFINALPATHNAMEBYHANDLEW) ( IN HANDLE hFile, OUT wchar_t* lpszFilePath, IN DWORD cchFilePath, IN DWORD dwFlags ); static GETFINALPATHNAMEBYHANDLEW GetFPNBHW=(GETFINALPATHNAMEBYHANDLEW)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetFinalPathNameByHandleW"); if(GetFPNBHW && GetFPNBHW(hFile, szPath, (DWORD)(nSize/sizeof(wchar_t)), 0)) { if(_wcsnicmp(szPath, L"\\?\UNC\", 8) == 0) // Server path { wcscpy_s(szPath, nSize / sizeof(wchar_t), L"\\"); wcscat_s(szPath, nSize / sizeof(wchar_t), &szPath[8]); } else if(_wcsnicmp(szPath, L"\\?\", 4) == 0 && szPath[5]==L':') // Drive path { wcscpy_s(szPath, nSize/sizeof(wchar_t), &szPath[4]); } return true; } if(!DevicePathFromFileHandleW(hFile, szPath, nSize)) return false; std::wstring oldPath(szPath); if (!DevicePathToPathW(szPath, szPath, nSize)) wcscpy_s(szPath, nSize / sizeof(wchar_t), oldPath.c_str()); return true; } ... --- snip ---
https://bitbucket.org/mrexodia/devicenameresolver/src/3fc6704267d469bd08633e...
--- snip --- ... bool DeviceNameResolver::resolveDeviceLongNameToShort(const TCHAR * sourcePath, TCHAR * targetPath) { for (unsigned int i = 0; i < deviceNameList.size(); i++) { if (!_tcsnicmp(deviceNameList.at(i).longName, sourcePath, deviceNameList.at(i).longNameLength) && sourcePath[deviceNameList.at(i).longNameLength]==TEXT('\')) { _tcscpy_s(targetPath, MAX_PATH, deviceNameList.at(i).shortName); _tcscat_s(targetPath, MAX_PATH, sourcePath + deviceNameList.at(i).longNameLength); return true; } } return false; } ... --- snip ---
In short: Wine returns incorrect names for file objects in 'NtQueryObject'.
The app code passes 'C:\windows\notepad.exe', gets '\??\C:\windows\notepad.exe' and tries to translate the path to short form, removing the device name part by matching against device list.
This fails hence the app uses whatever was returned by 'NtQueryObject' as fallback (= native NT path).
The proper object name would have been:
'\Device\HarddiskVolume1\Windows\notepad.exe'
Source: https://source.winehq.org/git/wine.git/blob/71080cc0818e8cc3e8be0c30bcc6602b...
Another article (just to reference the list from second answer):
https://stackoverflow.com/questions/65170/how-to-get-name-associated-with-op... ("How to get name associated with open HANDLE")
--- quote --- ... // returns // "\Device\HarddiskVolume3" (Harddisk Drive) // "\Device\HarddiskVolume3\Temp" (Harddisk Directory) // "\Device\HarddiskVolume3\Temp\transparent.jpeg" (Harddisk File) // "\Device\Harddisk1\DP(1)0-0+6\foto.jpg" (USB stick) // "\Device\TrueCryptVolumeP\Data\Passwords.txt" (Truecrypt Volume) // "\Device\Floppy0\Autoexec.bat" (Floppy disk) // "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB" (DVD drive) // "\Device\Serial1" (real COM port) // "\Device\USBSER000" (virtual COM port) // "\Device\Mup\ComputerName\C$\Boot.ini" (network drive share, Windows 7) // "\Device\LanmanRedirector\ComputerName\C$\Boot.ini" (network drive share, Windwos XP) // "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP) // "\Device\Afd" (internet socket) // "\Device\Console000F" (unique name for any Console handle) // "\Device\NamedPipe\Pipename" (named pipe) // "\BaseNamedObjects\Objectname" (named mutex, named event, named semaphore) // "\REGISTRY\MACHINE\SOFTWARE\Classes.txt" (HKEY_CLASSES_ROOT.txt) ... --- quote ---
$ wine --version wine-1.7.54-212-gf97ac58
Regards