https://bugs.winehq.org/show_bug.cgi?id=37355
Bug ID: 37355 Summary: Tages Protection v5.x needs ntoskrnl 'MmMapLockedPagesSpecifyCache' implementation Product: Wine Version: 1.7.27 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: ntoskrnl Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net
Hello folks,
reported here: https://github.com/compholio/wine-compholio/issues/80
Michael Müller from FDS team:
--- quote --- Sadly this is not enough to make the Tages copy protection happy. The issue you are now running into is:
fixme:ntoskrnl:MmMapLockedPagesSpecifyCache (0x111988, 0, 1, (nil), 0, 32): stub
The MmMapLockedPagesSpecifyCache command is used to map memory of a process into the kernel, so that a kernel driver can write / read it. This is necessary since the kernel does not share the same address space as the process. The problem is that this command is a stub and always returns 0 as mapped address. The Tages protection does not check for NULL pointers and tries to write to the address resulting in:
wine: Unhandled page fault on write access to 0x00000000 at address 0x57fe27 (thread 0018), starting debugger...
The problem is that there is no way to properly implement this on Linux since there is no way to simply map the memory of a different process if you are not inside the kernel. Since wine is no kernel module it can only use memory of different processes, when they explicitly create it as shared memory block. Sadly you can not declare a memory block as shared after it was allocated, so this does not help implementing this command.
Anyway in the case of the Tages protection we have some luck since it seems like the process is paused (I think it was waiting for the response of the DeviceIoControl function) while the memory is changed by the windows kernel driver. This allows us to emulate the mapping of the memory by using ReadProcessMemory and WriteProcessMemory. I wrote some hack to implement this, but this only prevented the crash and made the application to exit silently. I either made a mistake in my hack or there is still something else which prevents it from working. --- quote ---
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |download, obfuscation URL| |http://www.gamefront.com/fi | |les/8448224/Fantasy-Wars-En | |glish-Demo/ Depends on| |23033
https://bugs.winehq.org/show_bug.cgi?id=37355
Michael Müller michael@fds-team.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |michael@fds-team.de
https://bugs.winehq.org/show_bug.cgi?id=37355
lesebas sebdeligny@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |sebdeligny@gmail.com
--- Comment #1 from lesebas sebdeligny@gmail.com --- Bug confirmed too with game Attack On Pearl Harbor
wine version : 1.7.27 (compholio) system Achlinux x86_64
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #2 from Michael Müller michael@fds-team.de --- Created attachment 49677 --> https://bugs.winehq.org/attachment.cgi?id=49677 Hack to emulate mapping of process memory into ntoskrnl
Hi,
I just found my old hack to work around this problem. It uses ReadProcessMemory and WriteProcessMemory to emulate the mapping of the memory block. There was also a similar approach on the mailing list quite some time ago.
Regards, Michael
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #3 from lesebas sebdeligny@gmail.com --- Great... is there any way to test it or do you have to work forward to make it works with tages v5.x ?
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #4 from Michael Müller michael@fds-team.de --- Even with this patch applied, you will run into Bug 37356 which is much harder to fix since Wine does not support layered drivers and there is no workaround for this problem. Wine handles drivers completely wrong compared to Windows and there is a lot of code missing to properly support these kind of drivers.
https://bugs.winehq.org/show_bug.cgi?id=37355
Marc Bessières marc.bessieres@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |marc.bessieres@gmail.com
--- Comment #5 from Marc Bessières marc.bessieres@gmail.com --- Hello,
For reference Operation Matriarchy FR version, protected by Tages v5.5.0 obviously suffers from the same bug.
21:11:45 | C:\Program Files\Buka\Operation Matriarchy\GAME.EXE | Tages v5.5.0 | protection level: Tages BASIC 21:11:45 | C:\Program Files\Buka\Operation Matriarchy\unins000.exe | Inno Setup v5.0.4 Module | Possible CD/DVD-Key or Serial Check In a 32bit prefix.
--- snip ---
pwd
/home/guest/wine32/OperationMatriarchy/drive_c/Program Files/Buka/Operation Matriarchy
WINEDEBUG=+relay,+tid,+seh wine GAME.EXE >> log 2>&1
0018:fixme:ntoskrnl:IoGetCurrentProcess () stub 0018:Ret ntoskrnl.exe.IoAllocateMdl() retval=0011ade0 ret=0054038f 0018:Call ntoskrnl.exe.MmProbeAndLockPages(0011ade0,00000001,00000001) ret=005403ae 0018:fixme:ntoskrnl:MmProbeAndLockPages (0x11ade0, 1, 1): stub 0018:Ret ntoskrnl.exe.MmProbeAndLockPages() retval=0000003f ret=005403ae 0018:Call ntoskrnl.exe.MmMapLockedPagesSpecifyCache(0011ade0,00000000,00000001,00000000,00000000,00000020) ret=00566a9c 0018:fixme:ntoskrnl:MmMapLockedPagesSpecifyCache (0x11ade0, 0, 1, (nil), 0, 32): stub 0018:Ret ntoskrnl.exe.MmMapLockedPagesSpecifyCache() retval=00000000 ret=00566a9c 0018:trace:seh:raise_exception code=c0000005 flags=0 addr=0x566a9c ip=00566a9c tid=0018 0018:trace:seh:raise_exception info[0]=00000001 0018:trace:seh:raise_exception info[1]=00000000 0018:trace:seh:raise_exception eax=00000000 ebx=00000000 ecx=0053e738 edx=0053ef3c esi=0011ade0 edi=00000000 0018:trace:seh:raise_exception ebp=0053e748 esp=0053e6fc cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010202 0018:trace:seh:call_vectored_handlers calling handler at 0x7ed77d80 code=c0000005 flags=0 0018:trace:seh:call_vectored_handlers handler at 0x7ed77d80 returned 0 0018:trace:seh:call_stack_handlers calling handler at 0x562244 code=c0000005 flags=0 0018:trace:seh:call_stack_handlers handler at 0x562244 returned 1 0018:trace:seh:call_stack_handlers calling handler at 0x7bc98960 code=c0000005 flags=0 0018:Call KERNEL32.UnhandledExceptionFilter(0053e248) ret=7bc989a5 wine: Unhandled page fault on write access to 0x00000000 at address 0x566a9c (thread 0018), starting debugger... --- snip ---
sha1sum GAME.EXE
09caa98d3fc035c18b9d7ed3837293cceb9c00a2 GAME.EXE
du -sh GAME.EXE
616K GAME.EXE
wine --version
wine-1.7.35
Cheers, Marc
https://bugs.winehq.org/show_bug.cgi?id=37355
super_man@post.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |super_man@post.com
--- Comment #6 from super_man@post.com --- Download dead.
I am not aware that this would have been fixed so far.
wine 1.9.12
https://bugs.winehq.org/show_bug.cgi?id=37355
mirh mirh@protonmail.ch changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |mirh@protonmail.ch
--- Comment #7 from mirh mirh@protonmail.ch --- https://gamefront.online/files/8448224/FantasyWars_Demo_EN.exe http://www.gamershell.com/download_20855.shtml https://www.gamepressure.com/download.asp?ID=17083
Working mirrors
https://bugs.winehq.org/show_bug.cgi?id=37355
hadim marelo64@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |marelo64@gmail.com
https://bugs.winehq.org/show_bug.cgi?id=37355
Robert Walker bob.mt.wya@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |bob.mt.wya@gmail.com
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Depends on|23033 | Summary|Tages Protection v5.x needs |Multiple software |ntoskrnl |protection schemes need |'MmMapLockedPagesSpecifyCac |ntoskrnl |he' implementation |'MmMapLockedPagesSpecifyCac | |he' implementation (Tages | |Protection v5.x, | |BattleEye's 'bedaisy.sys') Keywords| |patch
--- Comment #8 from Anastasius Focht focht@gmx.net --- Hello folks,
refining summary.
Also needed by 'BEDaisy.sys' kernel driver, part of Battleye. Small client to reproduce: http://static.tibia.com/download/Tibia_Setup.exe
Tidbit: The kernel driver is heavily obfuscated.
--- snip --- ... 0048:trace:ntoskrnl:IoCreateDriver (L"\Driver\BEDaisy", 0x7effb1c0) ... 0048:trace:winedevice:load_driver loading driver L"C:\Program Files\Common Files\BattlEye\BEDaisy.sys" ... 0048:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\fltmgr.sys" at 0xf75d0000: builtin 0048:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\hal.dll" at 0xf7330000: builtin 0048:trace:loaddll:load_native_dll Loaded L"C:\Program Files\Common Files\BattlEye\BEDaisy.sys" at 0x780000: native ... 0048:Ret KERNEL32.LoadLibraryW() retval=00780000 ret=7effaa60 ... 0048:trace:winedevice:load_driver_module L"C:\Program Files\Common Files\BattlEye\BEDaisy.sys": relocating from 0x400000 to 0x780000 ... 0048:Call driver init 0x7fdf6e (obj=0x11cb70,str=L"\Registry\Machine\System\CurrentControlSet\Services\BEDaisy") 0048:Call ntoskrnl.exe.IoAllocateMdl(00780000,00040409,00000000,00000000,00000000) ret=0080bf37 0048:trace:ntoskrnl:IoAllocateMdl (0x780000, 263177, 0, 0, (nil)) 0048:Call ntdll.RtlAllocateHeap(00110000,00000008,00000120) ret=7ece03cc 0048:Ret ntdll.RtlAllocateHeap() retval=0011cd28 ret=7ece03cc 0048:Ret ntoskrnl.exe.IoAllocateMdl() retval=0011cd28 ret=0080bf37 0048:Call ntoskrnl.exe.MmProbeAndLockPages(0011cd28,00000000,00000001) ret=0080bf37 0048:fixme:ntoskrnl:MmProbeAndLockPages (0x11cd28, 0, 1): stub 0048:Ret ntoskrnl.exe.MmProbeAndLockPages() retval=0000003f ret=0080bf37 0048:Call ntoskrnl.exe.MmMapLockedPagesSpecifyCache(0011cd28,00000000,00000000,00000001,00000000,00000000) ret=0080bf37 0048:fixme:ntoskrnl:MmMapLockedPagesSpecifyCache (0x11cd28, 0, 0, 0x1, 0, 0): stub 0048:Ret ntoskrnl.exe.MmMapLockedPagesSpecifyCache() retval=00000000 ret=0080bf37 0048:trace:seh:raise_exception code=c0000005 flags=0 addr=0x809c6a ip=00809c6a tid=0048 0048:trace:seh:raise_exception info[0]=00000001 0048:trace:seh:raise_exception info[1]=00001000 0048:trace:seh:raise_exception eax=007fbae9 ebx=00000001 ecx=00000000 edx=007fba80 esi=0080117d edi=00001000 0048:trace:seh:raise_exception ebp=0065f464 esp=0065f35c cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010203 0048:trace:seh:call_vectored_handlers calling handler at 0x7ecddf85 code=c0000005 flags=0 0048:trace:seh:call_vectored_handlers handler at 0x7ecddf85 returned 0 0048:trace:seh:call_stack_handlers calling handler at 0x7bcaf67c code=c0000005 flags=0 ... --- snip ---
NOTE: There is a problem (regression?) with service state/transition handling causing the kernel driver service not started by helper service. When the window "Starting Battleye service..." shows up, you need to issue 'wine net stop BEService' command from another console and wait a bit. The app will detect this and restart the helper service which in turn will start the kernel service.
$ sha1sum Tibia_Setup.exe 50951008ccc402cc32407bfc56a88da873e3e9bd Tibia_Setup.exe
$ du -sh Tibia_Setup.exe 5.2M Tibia_Setup.exe
$ wine --version wine-3.1-193-g354fa7eb79
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Blocks| |44496
https://bugs.winehq.org/show_bug.cgi?id=37355
Adam Bolte abolte@systemsaviour.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |abolte@systemsaviour.com
https://bugs.winehq.org/show_bug.cgi?id=37355
dereklesho52@Gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |dereklesho52@Gmail.com
--- Comment #9 from dereklesho52@Gmail.com --- I have no experience in wine development, but I do not understand why Linux would need a kernel driver to implement this funtion. Doesn't everything run under wine run in userspace?
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #10 from mirh mirh@protonmail.ch --- Because these programs have their own kernel drivers, which require kernel functions to be implemented to work.
Then it doesn't mean this has to interfere with actual linux kernel.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #11 from Anastasius Focht focht@gmx.net --- Hello Derek,
--- quote --- I have no experience in wine development, but I do not understand why Linux would need a kernel driver to implement this funtion. Doesn't everything run under wine run in userspace? --- quote ---
the term 'kernel driver' refers to the Windows terminology. Unless explicitly stated otherwise, Windows terminology is used when talking about technologies, software architecture etc. There exist kernel and userspace drivers on Windows. Nowadays MS provides Kernel-Mode Driver Framework (KMDF) and User-Mode Driver Framework (UMDF) to ease development.
Under Wine the kernel driver PE binaries are mapped in userspace into 'winedevice' hosting process (Windows has a similar concept of a host process for usermode drivers), and the code is executed in user mode like any other Linux process. That's how Wine works by design.
This is in contrast to the 'ReactOS' project (https://www.reactos.org/) where these kernel drivers are running in kernel space/mode, exactly as in Windows.
There is another project called 'Longene' which claims to be a hybrid, that is providing infrastructure in Linux kernel to run Windows kernel drivers indeed in Linux kernel address space (https://en.wikipedia.org/wiki/Longene). That project was ill-fated from start (disclaimer: personal opinion) and seems abandoned now.
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #12 from Anastasius Focht focht@gmx.net --- Hello folks,
'Secret Files: Tunguska' game demo from bug 39500 has same problem (Tages Protection v5.x).
--- snip --- $ pwd /home/focht/.wine/drive_c/Program Files/Deep Silver/Secret Files Tunguska Demo
$ WINEDEBUG=+seh,+relay,+ntoskrnl,+hal wine ./Tunguska.exe >>log.txt 2>&1 ... 0009:Call KERNEL32.CreateFileA(0034a8ac "\\.\atksgt",c0000000,00000000,00000000,00000003,40000000,00000000) ret=009c7f6e 0009:Ret KERNEL32.CreateFileA() retval=00000040 ret=009c7f6e 0009:Call KERNEL32.DeviceIoControl(00000040,0022e40b,0034a9d0,00000005,00000000,00000000,0034a9cc,00000000) ret=009c7fbc 0017:Ret KERNEL32.WaitForMultipleObjectsEx() retval=00000001 ret=7eccbcec ... 0017:trace:ntoskrnl:dispatch_ioctl ioctl 22e40b device 0x120a98 file 0x11c9c0 in_size 5 out_size 0 0017:trace:ntoskrnl:IoBuildDeviceIoControlRequest 22e40b, 0x120a98, 0x11b948, 5, (nil), 0, 0, (nil), (nil) 0017:trace:ntoskrnl:IoAllocateIrp 1, 0 0017:Call ntdll.RtlAllocateHeap(00110000,00000000,00000094) ret=7ecce269 0017:Ret ntdll.RtlAllocateHeap() retval=0011ccd0 ret=7ecce269 0017:trace:ntoskrnl:ExAllocatePoolWithTag 148 pool 0 -> 0x11ccd0 0017:trace:ntoskrnl:IoInitializeIrp 0x11ccd0, 148, 1 0017:Call ntdll.NtGetTickCount() ret=7ecceb82 0017:Ret ntdll.NtGetTickCount() retval=0051e61a ret=7ecceb82 0017:Call driver dispatch 0x7bfc40 (device=0x120a98,irp=0x11ccd0) 0017:Call ntoskrnl.exe.IoAllocateMdl(0011b948,00000005,00000000,00000000,00000000) ret=0078038f 0017:trace:ntoskrnl:IoAllocateMdl (0x11b948, 5, 0, 0, (nil)) 0017:Call ntdll.RtlAllocateHeap(00110000,00000008,00000020) ret=7eccc39c 0017:Ret ntdll.RtlAllocateHeap() retval=0011cab0 ret=7eccc39c 0017:Ret ntoskrnl.exe.IoAllocateMdl() retval=0011cab0 ret=0078038f 0017:Call ntoskrnl.exe.MmProbeAndLockPages(0011cab0,00000001,00000001) ret=007803ae 0017:fixme:ntoskrnl:MmProbeAndLockPages (0x11cab0, 1, 1): stub 0017:Ret ntoskrnl.exe.MmProbeAndLockPages() retval=0000003f ret=007803ae 0017:Call ntoskrnl.exe.MmMapLockedPagesSpecifyCache(0011cab0,00000000,00000001,00000000,00000000,00000020) ret=007bfe27 0017:fixme:ntoskrnl:MmMapLockedPagesSpecifyCache (0x11cab0, 0, 1, (nil), 0, 32): stub 0017:Ret ntoskrnl.exe.MmMapLockedPagesSpecifyCache() retval=00000000 ret=007bfe27 0017:trace:seh:raise_exception code=c0000005 flags=0 addr=0x7bfe27 ip=007bfe27 tid=0017 0017:trace:seh:raise_exception info[0]=00000001 0017:trace:seh:raise_exception info[1]=00000000 0017:trace:seh:raise_exception eax=00000000 ebx=00000005 ecx=0054fc08 edx=00552f54 esi=00000000 edi=0011cab0 0017:trace:seh:raise_exception ebp=0054fc18 esp=0054fbbc cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010202 0017:trace:seh:call_vectored_handlers calling handler at 0x7ecc9f55 code=c0000005 flags=0 --- snip ---
Disassembly shows access to starting (virtual) address of the mapped pages:
--- snip --- ... 007BFE16 PUSH 20 007BFE18 PUSH 0 007BFE1A PUSH 0 007BFE1C PUSH 1 007BFE1E PUSH 0 007BFE20 PUSH EDI 007BFE21 CALL DWORD PTR DS:[<&ntoskrnl.MmMapLockedPagesSpecifyCache>] 007BFE27 MOV WORD PTR DS:[EAX],5 ; *boom* 007BFE2C MOV WORD PTR DS:[EAX+2],5 007BFE32 MOV BYTE PTR DS:[EAX+4],1 007BFE36 PUSH EDI 007BFE37 CALL DWORD PTR DS:[<&ntoskrnl.MmUnlockPages>] 007BFE3D PUSH EDI 007BFE3E CALL DWORD PTR DS:[<&ntoskrnl.IoFreeMdl>] 007BFE44 MOV EDX,DWORD PTR SS:[EBP+C] 007BFE47 MOV DWORD PTR DS:[EDX+1C],0 007BFE4E JMP atksgt.007C0333 ... --- snip ---
MSDN: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf...
There is a Wine-Staging patchset for ntoskrnl.exe MmMapLockedPages and MmUnmapLockedPages:
https://github.com/wine-staging/wine-staging/blob/master/patches/ntoskrnl-St...
The variants that allow to specify cache attributes can benefit from them or the other way around (should maybe go to Wine-Staging first). In general these stubs should be separated by topic to be tracked by individual tickets.
$ sha1sum secretfilestunguskademo.exe dud081e71f3c0e6f01ed85185afaf938fe43031df6 secretfilestunguskademo.exe
$ du -sh secretfilestunguskademo.exe 575M secretfilestunguskademo.exe
$ wine --version wine-3.2-293-g0a72708126
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
Zebediah Figura z.figura12@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |z.figura12@gmail.com
--- Comment #13 from Zebediah Figura z.figura12@gmail.com --- IF those staging patches are sufficient to fix the problem, it would be nice to mark this bug STAGED.
https://bugs.winehq.org/show_bug.cgi?id=37355
tokktokk fdsfgs@krutt.org changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |fdsfgs@krutt.org
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Blocks|44496 |
https://bugs.winehq.org/show_bug.cgi?id=37355
winetaste@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |winetaste@gmx.net
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |STAGED Staged patchset| |https://github.com/wine-sta | |ging/wine-staging/blob/mast | |er/patches/ntoskrnl-Stubs/0 | |009-ntoskrnl.exe-Implement- | |MmMapLockedPages-and-MmUnma | |pL.patch
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #14 from Anastasius Focht focht@gmx.net --- *** Bug 37356 has been marked as a duplicate of this bug. ***
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #15 from dereklesho52@Gmail.com --- Correct me if I am wrong, but the specific problem this issue is referring to is still not STAGED. While MmMapLockedPages and MmUnmapLockedPages are implemented, MmMapLockedPagesSpecifyCache still is not implemented.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #16 from Anastasius Focht focht@gmx.net --- Hello,
--- quote --- Correct me if I am wrong, but the specific problem this issue is referring to is still not STAGED. While MmMapLockedPages and MmUnmapLockedPages are implemented, MmMapLockedPagesSpecifyCache still is not implemented. --- quote ---
it's the other way around:
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/ntoskrnl.exe/ntoskrnl...
--- snip --- 697 @ stub MmMapLockedPages 698 @ stdcall MmMapLockedPagesSpecifyCache(ptr long long ptr long long) 699 @ stub MmMapLockedPagesWithReservedMapping --- snip ---
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/ntoskrnl.exe/ntoskrnl...
--- snip --- 2188 /*********************************************************************** 2189 * MmMapLockedPagesSpecifyCache (NTOSKRNL.EXE.@) 2190 */ 2191 PVOID WINAPI MmMapLockedPagesSpecifyCache(PMDLX MemoryDescriptorList, KPROCESSOR_MODE AccessMode, MEMORY_CACHING_TYPE CacheType, 2192 PVOID BaseAddress, ULONG BugCheckOnFailure, MM_PAGE_PRIORITY Priority) 2193 { 2194 FIXME("(%p, %u, %u, %p, %u, %u): stub\n", MemoryDescriptorList, AccessMode, CacheType, BaseAddress, BugCheckOnFailure, Priority); 2195 2196 return NULL; 2197 } --- snip ---
The current 'MmMapLockedPagesSpecifyCache()' implementation is not useful at all. The proper way would be to provide a simple-minded implementation of it and use it for 'MmMapLockedPages()' like this:
--- snip --- PVOID WINAPI MmMapLockedPages(PMDL MemoryDescriptorList, KPROCESSOR_MODE AccessMode) { return MmMapLockedPagesSpecifyCache( Mdl, AccessMode, MmCached, NULL, TRUE, HighPagePriority); } --- snip ---
The reason why this ticket is marked 'staged' with that single patch is to have a dedicated ticket reference for this kind of API functionality.
Patchsets such as https://github.com/wine-staging/wine-staging/tree/master/patches/ntoskrnl-St... are rather harmful to integrate at once. You can't dissect properly on regressions if they cover API functionality that is not closely coupled.
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #17 from Zebediah Figura z.figura12@gmail.com --- (In reply to Anastasius Focht from comment #16)
Hello,
--- quote --- Correct me if I am wrong, but the specific problem this issue is referring to is still not STAGED. While MmMapLockedPages and MmUnmapLockedPages are implemented, MmMapLockedPagesSpecifyCache still is not implemented. --- quote ---
it's the other way around:
I believe "in staging" was meant. The Staging patch attached to this bug does indeed not implement MmMapLockedPagesSpecifyCache.
I guess this bug shouldn't really be marked STAGED, but it's not terribly worth doing anything about.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #18 from dereklesho52@Gmail.com --- (In reply to Zebediah Figura from comment #17)
I believe "in staging" was meant. The Staging patch attached to this bug does indeed not implement MmMapLockedPagesSpecifyCache.
I guess this bug shouldn't really be marked STAGED, but it's not terribly worth doing anything about.
Isn't this specific function used by Battleye though? Implementing a separate function won't fix the issue this bug was reported for, right?
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #19 from Anastasius Focht focht@gmx.net --- Hello folks,
please use a separate mailing list thread/WineHQ forum for further questions/discussion or create your own bug report.
I don't want another ticket history being messed up with pointless discussions without substantial contributions.
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|STAGED |NEW
https://bugs.winehq.org/show_bug.cgi?id=37355
Richard Yao ryao@gentoo.org changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |ryao@gentoo.org
--- Comment #20 from Richard Yao ryao@gentoo.org ---
The problem is that there is no way to properly implement this on Linux since there is no way to simply map the memory of a different process if you are not inside the kernel. Since wine is no kernel module it can only use memory of different processes, when they explicitly create it as shared memory block. Sadly you can not declare a memory block as shared after it was allocated, so this does not help implementing this command.
Are you sure?
The way that I see it, if we can insert code into the other process in advance that we can trigger forassistance, this is doable.
1. Our “kernel” process somehow pings the other process. Then it attaches ptrace, saves the registers and request information to a predetermined place in memory and changes the instruction pointer to jump into an pseudo-interrupt handler. It resumes that process and then blocks on hearing back from the other process. 2. The other process’ pseudo-interrupt handler will create an anonymous file, either by making a file and unlinking it or by using O_TMPFILE. The file will be set to the size of the memory region being mapped via ftruncate(). This is then mapped into the address space using mmap(). The memory in the existing region is then copied. The handler now does mmap() the anonymous file into the correct position while calling unmap() on the previous mapping. Finally, it sends the file descriptor to the “kernel” process (via the wine server, a named pipe, whatever). 3. The “kernel” process the calls mmap() on the file descriptor. We have now mapped the region into the process.
I am not well versed in wine’s architecture, but this would achieve shared memory. The caveat being that you are not sharing the existing pages, but making new ones. If multiple processes are sharing the same pages, then we would need help from the wine server in keeping track of who has what mapped where and triggering the interrupt handlers in all processes that are sharing memory that is being mapped somewhere to remap it using a new copy. They also all would need to be paused.
This definitively becomes more complicated than that when you consider other corner cases, like what happens if we have a race where multiple “kernel threads” try to do this at the same time, but the general idea ought to work. Also, I said to use an anonymous file rather than POSIX shared memory to avoid having to keep track of the shared memory objects, but I suppose that if the wineserver is tracking things for the case of multiple processes sharing the same memory having this call done on that memory, then it could also keep track of shared memory objects so that processes using them will be told to properly free them should the mapping disappear so that we don’t risk leaking memory with long running processes.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #21 from Richard Yao ryao@gentoo.org --- To improve on my previous comment, this probably should be implemented as a wine server service. Upon being asked to do it, the requesting “kernel process” could block on recvmsg with the wineserver. Then the wineserver could attach ptrace to the target process and then:
1. Insert the information needed to service the request. 2. Save the registers to a predefined region. 3. Change the instruction pointer to jump into the interrupt handler.
Before finally letting the process continue:
Then the interrupt handler could do the messy stuff that I described previously, send the file descriptor to the wineserver with sendmsg and resume execution. Now, the wineserver can simply send the file descriptor to the “kernel process”.
This makes it easier to handle concurrent usage of this API. Specifically, calls to the API could be serialized would make implementation easier.
There would be more to it than this (especially when the function is called to map invalid or already shared memory), but this should be doable as long as the goal is to simulate a “mmap” that lets you map already existent regions of memory that pre-existing regions.
Another idea that could also work would be if the wineserver kept file descriptors for all memory regions mapped into child processes. Then when shared memory is desired, it could just call dup on the file descriptor, call lseek on the duplicated file descriptor, send it to the child to mmap and then close the duplicate on its end. The child could close it too after mmap’ing it. This would also require keeping track of where everything is mapped with reference counters, but it would easier to be convinced of correctness and there would be no issue from having to do memcopy() and worry about whether this is on memory already shared across multiple processes.
You would have to worry about running out of file-descriptors unless you do a hack where you let child processes hold onto the file descriptors for the wineserver until it needs it to bypass the system limit on the maximum number of file descriptors open by a process.
https://bugs.winehq.org/show_bug.cgi?id=37355
zzzzzyzz@hacari.org changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |zzzzzyzz@hacari.org
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #22 from Henri Verbeet hverbeet@gmail.com --- (In reply to Richard Yao from comment #20)
Are you sure?
The way that I see it, if we can insert code into the other process in advance that we can trigger forassistance, this is doable.
Yeah, we already do that kind of thing in ntdll. See server_select()/invoke_apc().
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #23 from dereklesho52@Gmail.com --- (In reply to Richard Yao from comment #20)
The handler now does mmap() the anonymous file into the correct position while calling unmap() on the previous mapping.
Can you elaborate on this, would we have use shared memory for the entire process heap?
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #24 from Richard Yao ryao@gentoo.org --- (In reply to dereklesho52 from comment #23)
(In reply to Richard Yao from comment #20)
The handler now does mmap() the anonymous file into the correct position while calling unmap() on the previous mapping.
Can you elaborate on this, would we have use shared memory for the entire process heap?
It depends on which of the two approaches are used:
1. For the first approach that I suggested, no. Wine would be leaning on the OS heavily here, but we will need to keep track of what was mapped via this call where and any use of mmap that affects what has been mapped to ensure that we don’t unshare regions or map incorrect regions (e.g. something we thought was mapped is not mapped anymore and we are mapping the stale version).
2. For the second approach, yes. Wine would be reimplementing the kernel’s memory management in userspace such that it would have its own implementation. Ensuring correctness here seems easier, at the expense of going through the wineserver for every memory allocation where the kernel is invoked.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #25 from Richard Yao ryao@gentoo.org ---
The problem is that there is no way to properly implement this on Linux since there is no way to simply map the memory of a different process if you are not inside the kernel. Since wine is no kernel module it can only use memory of different processes, when they explicitly create it as shared memory block. Sadly you can not declare a memory block as shared after it was allocated, so this does not help implementing this command.
It occurred to me that there is a simpler way of doing this on Linux. You just open /proc/$PID/mem, do lseek to the region that you want (after doing page alignment) and then call mmap (also after doing page alignment). The downside is that this requires root privileges, but on the bright side, you don't need to write a kernel module.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #26 from Zebediah Figura z.figura12@gmail.com --- (In reply to Richard Yao from comment #25)
The problem is that there is no way to properly implement this on Linux since there is no way to simply map the memory of a different process if you are not inside the kernel. Since wine is no kernel module it can only use memory of different processes, when they explicitly create it as shared memory block. Sadly you can not declare a memory block as shared after it was allocated, so this does not help implementing this command.
It occurred to me that there is a simpler way of doing this on Linux. You just open /proc/$PID/mem, do lseek to the region that you want (after doing page alignment) and then call mmap (also after doing page alignment). The downside is that this requires root privileges, but on the bright side, you don't need to write a kernel module.
I think needing root privileges probably rules this approach out. Is there anything preventing the aforementioned approach using APCs from working?
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #27 from Richard Yao ryao@gentoo.org --- I could see someone writing a really tiny root daemon that allows a process to gain access to a file descriptor of a child’s address space in any case that ptrace allows access and having the wine server talk to it. It should be possible to do that in a secure manner.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #28 from Richard Yao ryao@gentoo.org --- (In reply to Richard Yao from comment #27)
I could see someone writing a really tiny root daemon that allows a process to gain access to a file descriptor of a child’s address space in any case that ptrace allows access and having the wine server talk to it. It should be possible to do that in a secure manner.
Let me reword that, it should be!
I could see someone writing a really tiny root daemon that allows a process to gain access to a file descriptor of the address space of another process in any case that ptrace allows access and having the wine server talk to it. It should be possible to do that in a secure manner.
ptrace allows access to every process on the system if you have root, child or non child. The same goes for processes owned by the same UNIX user if I recall correctly. It would possible to add restrictions to such a daemon to lock it down, such as allowing only descendant processes and/or processes that are certain executables though. However, those restrictions should be enough to give Wine what it needs.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #29 from Richard Yao ryao@gentoo.org --- That is the last time I post to the bug tracker from a mobile device. Anyway, here is what I imagine as being possible:
A tiny root daemon that opens a unix domain socket that lets programs request file descriptors from /proc. It will do some checks to see if ptrace would allow access. It could do some additional checks to further restrict things such as:
1. The program requesting it is on a white list of allowed programs by checking the /proc/$PID/exe symlink. 2. The program whose fd it requested is a decedent of it in the process tree.
If all checks pass, it could open the file descriptor and send it back via the UNIX domain socket. In the case of wine, the wineserver should be able to pass those checks. wine could get a file descriptor from it to implement `MmMapLockedPagesSpecifyCache()`.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #30 from Richard Yao ryao@gentoo.org --- (In reply to Zebediah Figura from comment #26)
I think needing root privileges probably rules this approach out. Is there anything preventing the aforementioned approach using APCs from working?
To answer the APCs question, if that does what I think it does, it would be a pain to to handle MmMapLockedPagesSpecifyCache if it is invoked multiple times on the same pages such that different processes expect to share the same pages. Here is a scenario:
1. Process 2 invokes MmMapLockedPagesSpecifyCache to map pages from process 1 into itself. The two expect to share this memory. 2. Process 3 invokes MmMapLockedPagesSpecifyCache to map pages from process 2 into itself. All 3 expect to share the same memory. 3. In a naive implementation, we would copy and remap the pages on the second MmMapLockedPagesSpecifyCache call, such that process 1 will have different pages from process 3.
You also need to handle multiple adjacent allocations and do reference counting. You basically get to reimplement the kernel's memory management, which is plenty of effort to get right. The kernel does all of this for us, so why reimplement it? We'd never have an implementation that is both fast and correct either due to the need to stop all of the processes' threads to copy things in a way that would match what it would normally see. The fact that we need to copy at all would slow this down.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #31 from Zebediah Figura z.figura12@gmail.com --- (In reply to Richard Yao from comment #30)
You also need to handle multiple adjacent allocations and do reference counting. You basically get to reimplement the kernel's memory management, which is plenty of effort to get right. The kernel does all of this for us, so why reimplement it? We'd never have an implementation that is both fast and correct either due to the need to stop all of the processes' threads to copy things in a way that would match what it would normally see. The fact that we need to copy at all would slow this down.
I don't think this is as difficult as you make it out to be. It's not like we don't already do memory management anyway (see e.g. server/mapping.c).
It seems to me that we'd obviously want to avoid any need for root access (or kernel patching) if possible.
https://bugs.winehq.org/show_bug.cgi?id=37355
--- Comment #32 from Richard Yao ryao@gentoo.org --- Well, my /proc/${PID}/mem idea won't work. iops->mmap is not implemented for /proc/${PID}/mem in fs/proc/base.c. In fact iops isn't implemented period.
https://bugs.winehq.org/show_bug.cgi?id=37355
Captain Crutches captaincrutches@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |captaincrutches@gmail.com
https://bugs.winehq.org/show_bug.cgi?id=37355
timawesomeness winehq@timawesomeness.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |winehq@timawesomeness.com
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Summary|Multiple software |Multiple software |protection schemes need |protection schemes need |ntoskrnl |ntoskrnl |'MmMapLockedPagesSpecifyCac |'MmMapLockedPagesSpecifyCac |he' implementation (Tages |he' implementation (Tages |Protection v5.x, |Protection v5.x, |BattleEye's 'bedaisy.sys') |BattleEye's 'bedaisy.sys', | |MRAC Anti-Cheat)
--- Comment #33 from Anastasius Focht focht@gmx.net --- Hello folks,
revisiting and adding another protection/anti-cheat scheme:
MRAC Anti-Cheat (My.Com Warface) -> continued from bug 47047
Download:
https://web.archive.org/web/20190331063634/http://static.gc.my.com/WarfaceMy...
With that part(s) fixed, the driver passes the init sequence and processes IRPs from client (MRAC service) ioctls.
--- snip --- $ WINEDEBUG=+seh,+loaddll,+process,+ntoskrnl wine ./GameCenter.exe ... 0031:trace:ntoskrnl:load_driver loading driver L"C:\windows\System32\drivers\mracdrv.sys" 0031:Call KERNEL32.LoadLibraryW(00032010 L"C:\windows\System32\drivers\mracdrv.sys") ret=7f12f8b0bc4c ... 0031:Ret KERNEL32.LoadLibraryW() retval=140000000 ret=7f12f8b0bc4c ... 0031:Call driver init 0x140098005 (obj=0x31c70,str=L"\Registry\Machine\System\CurrentControlSet\Services\mracdrv") ... 0031:Call ntoskrnl.exe.ExAllocatePoolWithTag(00000000,00002000,4943414d) ret=140ab5668 0031:Call ntdll.RtlAllocateHeap(00010000,00000000,00002000) ret=7f12f8b0b158 0031:trace:heap:RtlAllocateHeap (0x10000,70000062,00002000): returning 0x48ba0 0031:Ret ntdll.RtlAllocateHeap() retval=00048ba0 ret=7f12f8b0b158 0031:trace:ntoskrnl:ExAllocatePoolWithTag 8192 pool 0 -> 0x48ba0 0031:Ret ntoskrnl.exe.ExAllocatePoolWithTag() retval=00048ba0 ret=140ab5668 ... 0031:Call ntoskrnl.exe.MmGetPhysicalAddress(00049000) ret=1403a839c 0031:fixme:ntoskrnl:MmGetPhysicalAddress stub: 0x49000 0031:Ret ntoskrnl.exe.MmGetPhysicalAddress() retval=00049000 ret=1403a839c ... 0031:Call ntoskrnl.exe.IoAllocateMdl(00049000,00001000,00000000,00000000,00000000) ret=140f3d8e4 0031:trace:ntoskrnl:IoAllocateMdl (0x49000, 4096, 0, 0, (nil)) 0031:Call ntdll.RtlAllocateHeap(00010000,00000008,00000034) ret=7f12f8b0e514 0031:trace:heap:RtlAllocateHeap (0x10000,7000006a,00000034): returning 0x4abc0 0031:Ret ntdll.RtlAllocateHeap() retval=0004abc0 ret=7f12f8b0e514 0031:Ret ntoskrnl.exe.IoAllocateMdl() retval=0004abc0 ret=140f3d8e4 ... 0031:Call ntoskrnl.exe.MmProbeAndLockPages(0004abc0,00000000,00000000) ret=1403e3800 0031:fixme:ntoskrnl:MmProbeAndLockPages (0x4abc0, 0, 0): stub 0031:Ret ntoskrnl.exe.MmProbeAndLockPages() retval=0000003e ret=1403e3800 ... 0031:Call ntoskrnl.exe.MmMapLockedPagesSpecifyCache(0004abc0,00000000,00000001,00000000,00000000,00000010) ret=140a50460 0031:fixme:ntoskrnl:MmMapLockedPagesSpecifyCache (0x4abc0, 0, 1, (nil), 0, 16): stub 0031:Ret ntoskrnl.exe.MmMapLockedPagesSpecifyCache() retval=00049000 ret=140a50460 ... <repeats for more sets of buffers/MDLs> ... 0031:Ret driver init 0x140098005 (obj=0x31c70,str=L"\Registry\Machine\System\CurrentControlSet\Services\mracdrv") retval=00000000 ... --- snip ---
$ sha1sum WarfaceMycomLoader_805e0da40d16630c2fe73ed12399cb48_.exe b07e87a029d6697ad823dc03fdbf297c406a91b9 WarfaceMycomLoader_805e0da40d16630c2fe73ed12399cb48_.exe
$ du -sh WarfaceMycomLoader_805e0da40d16630c2fe73ed12399cb48_.exe 6.8M WarfaceMycomLoader_805e0da40d16630c2fe73ed12399cb48_.exe
$ wine --version wine-4.6-61-g085e58878f
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
pattietreutel katyaberezyaka@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |katyaberezyaka@gmail.com
https://bugs.winehq.org/show_bug.cgi?id=37355
Luke Bratch luke@bratch.co.uk changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |luke@bratch.co.uk
https://bugs.winehq.org/show_bug.cgi?id=37355
kabelix@bit-ion.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |kabelix@bit-ion.net
--- Comment #34 from kabelix@bit-ion.net --- May I add that "process_vm_mmap" might be a option if it gets added in the kernel. https://patchwork.kernel.org/patch/10951291/
https://bugs.winehq.org/show_bug.cgi?id=37355
Ker noa blue-t@web.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |blue-t@web.de
--- Comment #35 from Ker noa blue-t@web.de --- What is the state of a solution in the upstream kernel?
https://bugs.winehq.org/show_bug.cgi?id=37355
Alexis NICOLAS nyamiou@galeanthrope.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |nyamiou@galeanthrope.com
https://bugs.winehq.org/show_bug.cgi?id=37355
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- URL|http://www.gamefront.com/fi |https://web.archive.org/web |les/8448224/Fantasy-Wars-En |/20210119110340/http://file |glish-Demo/ |.4gamer.net/demo/FantasyWar | |s_Demo_EN.exe
--- Comment #36 from Anastasius Focht focht@gmx.net --- Hello folks,
replacing broken link with a stable one from Internet Archive:
https://web.archive.org/web/20210119110340/http://file.4gamer.net/demo/Fanta...
$ sha1sum FantasyWars_Demo_EN.exe 96c0d6a46adca29ea5d55d0013cc78d842f441dd FantasyWars_Demo_EN.exe
$ du -sh FantasyWars_Demo_EN.exe 356M FantasyWars_Demo_EN.exe
$ wine --version wine-6.0-75-g88220e0ee41
Regards
https://bugs.winehq.org/show_bug.cgi?id=37355
bz+wine@arisu.eu.org changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |bz+wine@arisu.eu.org
https://bugs.winehq.org/show_bug.cgi?id=37355
Linards linards.liepins@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |linards.liepins@gmail.com
--- Comment #37 from Linards linards.liepins@gmail.com --- Also Destiny 2 is using BattleEye's protection, which is not working on Fedora 38 in my case. Please add it to the title.
https://bugs.winehq.org/show_bug.cgi?id=37355
Olivier F. R. Dierick o.dierick@piezo-forte.be changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |o.dierick@piezo-forte.be
--- Comment #38 from Olivier F. R. Dierick o.dierick@piezo-forte.be --- (In reply to Linards from comment #37)
Also Destiny 2 is using BattleEye's protection, which is not working on Fedora 38 in my case. Please add it to the title.
Hello,
BattlEye is already in the title. No need to list every app that uses it.
Regards.