Skip to content

Commit

Permalink
FEXLoader: Add some debug-only tracking for FEX owned FDs
Browse files Browse the repository at this point in the history
I remember seeing some application last year where they closed a FEX
owned FD but now I don't remember what it was. This can really mess us
up so add some debug tracking so we can try and find it again.

Might be something specifically around flatpack, appimage, or chrome's
sandbox. I have some ideas about how to work around these problems if
they crop up but need to find the problem applications again.
  • Loading branch information
Sonicadvance1 committed Mar 22, 2024
1 parent 8852d94 commit 869a452
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
13 changes: 11 additions & 2 deletions Source/Tools/FEXLoader/FEXLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ desc: Glues the ELF loader, FEXCore and LinuxSyscalls to launch an elf under fex

namespace {
static bool SilentLog;
static int OutputFD {STDERR_FILENO};
static int OutputFD {-1};
static bool ExecutedWithFD {false};

void MsgHandler(LogMan::DebugLevels Level, char const *Message) {
Expand All @@ -88,7 +88,7 @@ void AssertHandler(char const *Message) {
} // Anonymous namespace

namespace FEXServerLogging {
int FEXServerFD{};
int FEXServerFD{-1};
void MsgHandler(LogMan::DebugLevels Level, char const *Message) {
FEXServerClient::MsgHandler(FEXServerFD, Level, Message);
}
Expand Down Expand Up @@ -456,6 +456,15 @@ int main(int argc, char **argv, char **const envp) {
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get())
: FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator));

// Now that we have the syscall handler. Track some FDs that are FEX owned.
if (OutputFD != -1) {
SyscallHandler->FM.TrackFEXFD(OutputFD);
}
SyscallHandler->FM.TrackFEXFD(FEXServerClient::GetServerFD());
if (FEXServerLogging::FEXServerFD != -1) {
SyscallHandler->FM.TrackFEXFD(FEXServerLogging::FEXServerFD);
}

{
// Load VDSO in to memory prior to mapping our ELFs.
void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get());
Expand Down
18 changes: 18 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ FileManager::FileManager(FEXCore::Context::Context *ctx)
if (RootFSFD == -1) {
RootFSFD = AT_FDCWD;
}
else {
TrackFEXFD(RootFSFD);
}
}

fextl::unordered_map<fextl::string, ThunkDBObject> ThunkDB;
Expand Down Expand Up @@ -571,13 +574,28 @@ uint64_t FileManager::Open(const char *pathname, int flags, uint32_t mode) {
}

uint64_t FileManager::Close(int fd) {
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
if (CheckIfFDInTrackedSet(fd)) {
LogMan::Msg::EFmt("{} closing FEX FD {}", __func__, fd);
RemoveFEXFD(fd);
}
#endif

return ::close(fd);
}

uint64_t FileManager::CloseRange(unsigned int first, unsigned int last, unsigned int flags) {
#ifndef CLOSE_RANGE_CLOEXEC
#define CLOSE_RANGE_CLOEXEC (1U << 2)
#endif
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
if (!(flags & CLOSE_RANGE_CLOEXEC) &&
CheckIfFDRangeInTrackedSet(first, last)) {
LogMan::Msg::EFmt("{} closing FEX FDs in range ({}, {})", __func__, first, last);
RemoveFEXFDRange(first, last);
}
#endif

return ::syscall(SYSCALL_DEF(close_range), first, last, flags);
}

Expand Down
53 changes: 53 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,60 @@ class FileManager final {

bool SupportsProcFSInterpreterPath() const { return SupportsProcFSInterpreter; }

#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
void TrackFEXFD(int FD) noexcept {
std::lock_guard lk(FEXTrackingFDMutex);
FEXTrackingFDs.emplace(FD);
}

void RemoveFEXFD(int FD) noexcept {
std::lock_guard lk(FEXTrackingFDMutex);
FEXTrackingFDs.erase(FD);
}

void RemoveFEXFDRange(int begin, int end) noexcept {
std::lock_guard lk(FEXTrackingFDMutex);

// Just linear scan since the number of tracking FDs is low.
for (auto it = FEXTrackingFDs.begin(); it != FEXTrackingFDs.end(); ) {
auto FD = *it;
if (FD >= begin && (FD <= end || end == -1)) {
it = FEXTrackingFDs.erase(it);
}
else {
++it;
}
}
}

bool CheckIfFDInTrackedSet(int FD) noexcept {
std::lock_guard lk(FEXTrackingFDMutex);
return FEXTrackingFDs.contains(FD);
}

bool CheckIfFDRangeInTrackedSet(int begin, int end) noexcept {
std::lock_guard lk(FEXTrackingFDMutex);
// Just linear scan since the number of tracking FDs is low.
for (auto it : FEXTrackingFDs) {
if (it >= begin && (it <= end || end == -1)) return true;
}
return false;
}

#else
void TrackFEXFD(int FD) const noexcept {}
bool CheckIfFDInTrackedSet(int FD) const noexcept { return false; }
void RemoveFEXFD(int FD) const noexcept {}
void RemoveFEXFDRange(int begin, int end) const noexcept {}
bool CheckIfFDRangeInTrackedSet(int begin, int end) const noexcept { return false; }
#endif

private:
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
std::mutex FEXTrackingFDMutex;
fextl::set<int> FEXTrackingFDs;
#endif

bool RootFSPathExists(const char* Filepath);

struct ThunkDBObject {
Expand Down

0 comments on commit 869a452

Please sign in to comment.