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.
This commit is contained in:
Ryan Houdek committed 2024-09-12 19:58:35 -07:00
1 parent 0a35029d9a
commit b6e4c47abc
6 files changed
+26 -83

No files matched your search

-1
View File
@@ -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
-1
View File
@@ -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
+2 -13
View File
@@ -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"
)
@@ -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<std::string_view> 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);
// 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());
}
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;
@@ -89,10 +89,6 @@ public:
using FDPathTmpData = std::array<char[PATH_MAX], 2>;
std::pair<int, const char*> 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 @@ private:
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
uint32_t CurrentPID {};
int RootFSFD {AT_FDCWD};
bool SupportsProcFSInterpreter {};
};
} // namespace FEX::HLE
@@ -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<char* const*>(ExecveArgs.data()), EnvpPtr, Args.flags);
Result = ::syscall(SYS_execveat, Args.dirfd, "/proc/self/exe", const_cast<char* const*>(ExecveArgs.data()), EnvpPtr, Args.flags);
CloseSeccompFD();
CloseFDExecFD();