Skip to content

Commit

Permalink
Merge pull request #4064 from Sonicadvance1/remove_binfmt_flag
Browse files Browse the repository at this point in the history
FEXLoader: Drop the binfmt_misc `I` flag
  • Loading branch information
Sonicadvance1 authored Sep 13, 2024
2 parents 0a35029 + b6e4c47 commit e190d02
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 84 deletions.
1 change: 0 additions & 1 deletion Data/binfmts/FEX-x86.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 0 additions & 1 deletion Data/binfmts/FEX-x86_64.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 2 additions & 13 deletions Source/Tools/FEXLoader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
)
Expand All @@ -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"
)
Expand Down
65 changes: 15 additions & 50 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 0 additions & 5 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@ class FileManager final {
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);
Expand Down Expand Up @@ -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
24 changes: 10 additions & 14 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();

Expand Down

0 comments on commit e190d02

Please sign in to comment.