fix(linux): resolve the Mono image base from /proc/maps so Wine/Proton works - #7
Conversation
The Linux read_mono_root_domain() swept the address space from 0 in 4KiB steps looking for the MZ magic. Under Wine/Proton — the only way MTGA runs on Linux, and what the README documents this path as targeting — the game's mono-2.0-bdwgc.dll is mapped around 0x6ffff_xxxx_xxxx, roughly 3e10 pages up. The loop is unbounded, so init() never returns. Wine maps the DLL from disk, so /proc/<pid>/maps names it outright. Take the base from there and hand it to PEReader, mirroring what the Windows path already does with Process::module(). Verified against MTGA under Proton Experimental (Arch, kernel 6.17): init() 2.3s, then readAccount/readRanks/readInventory/readDecks(95)/ readCollection all return correct data matching the Arena UI.
is_admin() equated privilege with uid 0, which is a Windows-shaped assumption. On Linux, cross-process memory reads are permitted to root, to any process holding CAP_SYS_PTRACE, and to same-uid processes whenever the Yama LSM is absent or set to ptrace_scope=0. Users in those last two groups can read MTGA's memory perfectly well, but the desktop app still greeted them with "App is not running with admin/elevated privileges" — a warning with no action behind it, since elevating was never what they were missing. Check the actual conditions instead. Verified on Arch (ptrace_scope=0): isAdmin() now returns true as an ordinary user, and the typed readers succeed in the same process.
|
Hi @raymondshiner, Thanks you for submitting this PR ! As you noted there is no Mono target specifically for Arena on Linux, if a dedicated version would exist, it would use the IL2CPP implementation instead, thus, we rely on the Mono target on Linux because that is what people use (virtualized windows versiones runnin Mono). Also, on my tests, the admin requirement on Linux is variable. Usually, it was not required like you mentioned, other times it actually blocked me from reading /proc entirely, even without writing (rust libraries back when I was testing did not discriminate permissions for either and you would be blocked with having to elevate the process just to do reads). this might have changed but I havent been able to test myself in quite some time. I will check if it causes any regressions against mac/windows, but any more tests are very appreciated! thanks again for this! :) |
|
All looks good, the changes were contained on Linux and honestly without these changes the reader wouldnt even work on Linux as is stands, thanks again ! |
Makes the Linux/Wine Mono path actually reach the runtime, and stops warning users about privileges they already have.
Both bugs surface the same way: Arena installed through Steam on Linux, running under Proton.
init()hangs forever, and the desktop app shows "App is not running with admin/elevated privileges" regardless of what the user does.1.
read_mono_root_domain()never returns under WineThe Linux implementation sweeps the address space from
0in 4 KiB steps looking for theMZmagic:That terminates quickly on Windows, where the image sits within the first few GB. But Wine loads
mono-2.0-bdwgc.dllhigh — on my machine:0x6ffffa010000is 123 TB, or 30,064,746,512 iterations, each one aprocess_vm_readvsyscall. The loop is unbounded, so it doesn't fail — it just never finishes.Since Wine maps the DLL from disk,
/proc/<pid>/mapsnames it outright. That's the same informationProcess::module()gives the Windows path, so this change simply mirrors what Windows already does: take the base, hand it toPEReader.detection.rswas already reading that exact file to grep for"mono-2.0"— it just discarded the address.Worth noting the README documents this path as "Windows / Linux (Wine) → Mono", and Wine is the only way Arena runs on Linux, so the scan had no configuration in which it could succeed.
2.
is_admin()equates privilege with uid 0Cross-process memory reads are available to root, to anyone holding
CAP_SYS_PTRACE, and to same-uid processes whenever Yama is absent or set toptrace_scope=0. The last two groups can read Arena's memory fine, but were still told to elevate — advice that wouldn't have helped, since elevation wasn't the missing piece. Now all three conditions are checked.Verification
Arch Linux, kernel 6.17, Proton Experimental, Arena via Steam (appid 2141910), ordinary user with
ptrace_scope=0:init("MTGA.exe")isAdmin()falsetruereadAccountreadRanksreadInventoryreadDecksreadCollectionValues cross-checked against the Arena UI: wildcards, gold, gems, vault percentage, and both rank tracks all match. Nothing downstream of the base address needed changing — the Mono walker handles Wine's layout as-is.
cargo check --lib --features napi-bindingsis clean; no new warnings.Notes for review
mono_module_base()deliberately narrow. Selecting the mapping at file offset 0 is what puts us on the PE header; the.min()on(file_offset, start)is doing that.is_admin()change reviewed separately.