From b6e4c47abcf9cbd9919b1864b7c5e265cfb9358a Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 12 Sep 2024 19:56:55 -0700 Subject: [PATCH] FEXLoader: Drop the binfmt_misc `I` flag Upstream has rejected this flag which would have let FEX close the gap in functionality between binfmt_misc interpreters and PT_INTERP interpreters for how `/proc/exe` is handled. Since we are unable to change their opinions, just remove the code from FEX since it's never going to happen. Removes a little bit of confusing behaviour in execveat and filemanagement handling. Leaving us with only the regular confusing behaviour of trying to track accesses to `/proc/exe` instead. --- Data/binfmts/FEX-x86.in | 1 - Data/binfmts/FEX-x86_64.in | 1 - Source/Tools/FEXLoader/CMakeLists.txt | 15 +---- .../LinuxSyscalls/FileManagement.cpp | 65 +++++-------------- .../LinuxSyscalls/FileManagement.h | 5 -- .../LinuxEmulation/LinuxSyscalls/Syscalls.cpp | 24 +++---- 6 files changed, 27 insertions(+), 84 deletions(-) diff --git a/Data/binfmts/FEX-x86.in b/Data/binfmts/FEX-x86.in index a728b4befc..c76259dcaf 100644 --- a/Data/binfmts/FEX-x86.in +++ b/Data/binfmts/FEX-x86.in @@ -6,4 +6,3 @@ mask \xff\xff\xff\xff\xff\xfe\xfe\x00\x00\x00\x00\xff\xff\xff\xff\xff\xfe\xff\xf credentials yes fix_binary yes preserve yes -expose_interpreter optional diff --git a/Data/binfmts/FEX-x86_64.in b/Data/binfmts/FEX-x86_64.in index 4e13c3ff7e..fa0e195f4e 100644 --- a/Data/binfmts/FEX-x86_64.in +++ b/Data/binfmts/FEX-x86_64.in @@ -6,4 +6,3 @@ mask \xff\xff\xff\xff\xff\xfe\xfe\x00\x00\x00\x00\xff\xff\xff\xff\xff\xfe\xff\xf credentials yes fix_binary yes preserve yes -expose_interpreter optional diff --git a/Source/Tools/FEXLoader/CMakeLists.txt b/Source/Tools/FEXLoader/CMakeLists.txt index 3998fb9125..80f08b1297 100644 --- a/Source/Tools/FEXLoader/CMakeLists.txt +++ b/Source/Tools/FEXLoader/CMakeLists.txt @@ -96,17 +96,6 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") add_dependencies(uninstall uninstall_binfmt_misc_64) endif() else() - set (SUPPORTED_BINFMT_MISC_FLAGS "POCF") - execute_process(COMMAND uname -r OUTPUT_VARIABLE UNAME_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(REGEX MATCH "[0-9]+.[0-9]+" KERNEL_VERSION ${UNAME_VERSION}) - message(STATUS "Kernel version: ${KERNEL_VERSION}") - - if (KERNEL_VERSION VERSION_GREATER_EQUAL 9999.0) - # New binfmt_misc flag for exposing the interpreter was added in version '9999.0' - # Only enable it if the host kernel is at least that. - set (SUPPORTED_BINFMT_MISC_FLAGS "POCFI") - endif() - # In the case of update-binfmts not being available (Arch for example) then we need to install manually add_custom_target(binfmt_misc_32 COMMAND ${CMAKE_COMMAND} -E @@ -117,7 +106,7 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") echo "Attempting to install FEX-x86 misc now." COMMAND ${CMAKE_COMMAND} -E echo - ':FEX-x86:M:0:\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x03\\x00:\\xff\\xff\\xff\\xff\\xff\\xfe\\xfe\\x00\\x00\\x00\\x00\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:${CMAKE_INSTALL_PREFIX}/bin/FEXInterpreter:${SUPPORTED_BINFMT_MISC_FLAGS}' > /proc/sys/fs/binfmt_misc/register + ':FEX-x86:M:0:\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x03\\x00:\\xff\\xff\\xff\\xff\\xff\\xfe\\xfe\\x00\\x00\\x00\\x00\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:${CMAKE_INSTALL_PREFIX}/bin/FEXInterpreter:POCF' > /proc/sys/fs/binfmt_misc/register COMMAND ${CMAKE_COMMAND} -E echo "binfmt_misc FEX-x86 installed" ) @@ -130,7 +119,7 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") echo "Attempting to install FEX-x86_64 misc now." COMMAND ${CMAKE_COMMAND} -E echo - ':FEX-x86_64:M:0:\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x3e\\x00:\\xff\\xff\\xff\\xff\\xff\\xfe\\xfe\\x00\\x00\\x00\\x00\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:${CMAKE_INSTALL_PREFIX}/bin/FEXInterpreter:${SUPPORTED_BINFMT_MISC_FLAGS}' > /proc/sys/fs/binfmt_misc/register + ':FEX-x86_64:M:0:\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x3e\\x00:\\xff\\xff\\xff\\xff\\xff\\xfe\\xfe\\x00\\x00\\x00\\x00\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:${CMAKE_INSTALL_PREFIX}/bin/FEXInterpreter:POCF' > /proc/sys/fs/binfmt_misc/register COMMAND ${CMAKE_COMMAND} -E echo "binfmt_misc FEX-x86_64 installed" ) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp index 1f41f1eb86..e57c281586 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp @@ -322,32 +322,6 @@ FileManager::FileManager(FEXCore::Context::Context* ctx) } } - // Check to see if this kernel exposes `/proc/self/interpreter`. - // In the case that it does then behaviour is different than without. - // - // When procfs/interpreter is supported (binfmt_misc flag enabled): - // - procfs/exe -> symlink to the correct executable just like when executing natively. - // - procfs/interpreter -> symlink to FEXInterpreter. - // - // FEX no longer needs to track accesses to procfs/exe which improves performance and also improves correctness. - // - // When procfs/interpreter is supported (binfmt_misc flag not enabled): - // When procfs/interpreter is NOT supported: - // - procfs/exe -> symlink to FEXInterpreter. - // - procfs/interpreter -> symlink doesn't exist. - // - // In either of these two cases, FEX still needs to track procfs/exe so we can't completely get away from it. - // This happens in a few edge cases - // - binfmt_misc not installed - // - binfmt_misc doesn't support enabling the new flag - // - executable called through FEXInterpreter directly - // - Can happen because of directly executing the process through FEXIntepreter or through FEXBash. - char FilenameExe[PATH_MAX]; - char FilenameInterpreter[PATH_MAX]; - const auto ExeSymlinkPath = FHU::Symlinks::ResolveSymlink("/proc/self/exe", FilenameExe); - const auto InterpreterSymlinkPath = FHU::Symlinks::ResolveSymlink("/proc/self/interpreter", FilenameInterpreter); - SupportsProcFSInterpreter = !InterpreterSymlinkPath.empty() && ExeSymlinkPath != InterpreterSymlinkPath; - UpdatePID(::getpid()); } @@ -498,11 +472,6 @@ bool FileManager::IsSelfNoFollow(const char* Pathname, int flags) const { } std::optional FileManager::GetSelf(const char* Pathname) { - if (SupportsProcFSInterpreter) { - // FEX doesn't need to track procfs/exe if this is supported. - return Pathname; - } - if (!Pathname) { return std::nullopt; } @@ -666,17 +635,15 @@ uint64_t FileManager::FAccessat2(int dirfd, const char* pathname, int mode, int } uint64_t FileManager::Readlink(const char* pathname, char* buf, size_t bufsiz) { - if (!SupportsProcFSInterpreter) { - // calculate the non-self link to exe - // Some executables do getpid, stat("/proc/$pid/exe") - char PidSelfPath[50]; - snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); - - if (strcmp(pathname, "/proc/self/exe") == 0 || strcmp(pathname, "/proc/thread-self/exe") == 0 || strcmp(pathname, PidSelfPath) == 0) { - const auto& App = Filename(); - strncpy(buf, App.c_str(), bufsiz); - return std::min(bufsiz, App.size()); - } + // calculate the non-self link to exe + // Some executables do getpid, stat("/proc/$pid/exe") + char PidSelfPath[50]; + snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); + + if (strcmp(pathname, "/proc/self/exe") == 0 || strcmp(pathname, "/proc/thread-self/exe") == 0 || strcmp(pathname, PidSelfPath) == 0) { + const auto& App = Filename(); + strncpy(buf, App.c_str(), bufsiz); + return std::min(bufsiz, App.size()); } FDPathTmpData TmpFilename; @@ -745,15 +712,13 @@ uint64_t FileManager::Readlinkat(int dirfd, const char* pathname, char* buf, siz } } - if (!SupportsProcFSInterpreter) { - char PidSelfPath[50]; - snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); + char PidSelfPath[50]; + snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID); - if (Path == "/proc/self/exe" || Path == "/proc/thread-self/exe" || Path == PidSelfPath) { - const auto& App = Filename(); - strncpy(buf, App.c_str(), bufsiz); - return std::min(bufsiz, App.size()); - } + if (Path == "/proc/self/exe" || Path == "/proc/thread-self/exe" || Path == PidSelfPath) { + const auto& App = Filename(); + strncpy(buf, App.c_str(), bufsiz); + return std::min(bufsiz, App.size()); } FDPathTmpData TmpFilename; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h index 1ac10fc540..c230aedb48 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h @@ -89,10 +89,6 @@ class FileManager final { using FDPathTmpData = std::array; std::pair GetEmulatedFDPath(int dirfd, const char* pathname, bool FollowSymlink, FDPathTmpData& TmpFilename); - bool SupportsProcFSInterpreterPath() const { - return SupportsProcFSInterpreter; - } - #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED void TrackFEXFD(int FD) noexcept { std::lock_guard lk(FEXTrackingFDMutex); @@ -166,6 +162,5 @@ class FileManager final { FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); uint32_t CurrentPID {}; int RootFSFD {AT_FDCWD}; - bool SupportsProcFSInterpreter {}; }; } // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp index 886f66a593..92a80ee32d 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp @@ -205,7 +205,6 @@ uint64_t ExecveHandler(FEXCore::Core::CpuStateFrame* Frame, const char* pathname // AT_EMPTY_PATH is only used if the pathname is empty. const bool IsFDExec = (Args.flags & AT_EMPTY_PATH) && strlen(pathname) == 0; - const bool SupportsProcFSInterpreter = SyscallHandler->FM.SupportsProcFSInterpreterPath(); fextl::string FDExecEnv; fextl::string FDSeccompEnv; @@ -233,19 +232,17 @@ uint64_t ExecveHandler(FEXCore::Core::CpuStateFrame* Frame, const char* pathname return -ENOENT; } - if (!SupportsProcFSInterpreter) { - int pid = getpid(); + int pid = getpid(); - char PidSelfPath[50]; - snprintf(PidSelfPath, 50, "/proc/%i/exe", pid); + char PidSelfPath[50]; + snprintf(PidSelfPath, 50, "/proc/%i/exe", pid); - if (strcmp(pathname, "/proc/self/exe") == 0 || strcmp(pathname, "/proc/thread-self/exe") == 0 || strcmp(pathname, PidSelfPath) == 0) { - // If the application is trying to execve `/proc/self/exe` or its variants, - // then we need to redirect this path to the true application path. - // This is because this path is a symlink to the executing application, which is always `FEXInterpreter` or `FEXLoader`. - // ex: JRE and shapez.io do this self-execution. - Filename = SyscallHandler->Filename(); - } + if (strcmp(pathname, "/proc/self/exe") == 0 || strcmp(pathname, "/proc/thread-self/exe") == 0 || strcmp(pathname, PidSelfPath) == 0) { + // If the application is trying to execve `/proc/self/exe` or its variants, + // then we need to redirect this path to the true application path. + // This is because this path is a symlink to the executing application, which is always `FEXInterpreter` or `FEXLoader`. + // ex: JRE and shapez.io do this self-execution. + Filename = SyscallHandler->Filename(); } Type = ELFLoader::ELFContainer::GetELFType(Filename); @@ -392,8 +389,7 @@ uint64_t ExecveHandler(FEXCore::Core::CpuStateFrame* Frame, const char* pathname ExecveArgs.emplace_back(nullptr); } - const char* InterpreterPath = SupportsProcFSInterpreter ? "/proc/self/interpreter" : "/proc/self/exe"; - Result = ::syscall(SYS_execveat, Args.dirfd, InterpreterPath, const_cast(ExecveArgs.data()), EnvpPtr, Args.flags); + Result = ::syscall(SYS_execveat, Args.dirfd, "/proc/self/exe", const_cast(ExecveArgs.data()), EnvpPtr, Args.flags); CloseSeccompFD(); CloseFDExecFD();