Skip to content

Commit

Permalink
FileManagement: Hide the FEX RootFS fd from /proc/self/fd take 2
Browse files Browse the repository at this point in the history
Apparently Chromium/CEF can chroot or otherwise sandbox the filesystem
away before forking and checking for directory FDs, making /proc
inaccessible, which means we can't stat it for our inode check, breaking
the hiding.

So, double down on things and do what Chromium does: open an fd to /proc
ahead of time, so that continues to work. Then we use it to update the
inode of our RootFS fd instead, and finally, also do the /proc fd itself
to hide that one too.

We also don't need to check the st_dev of /proc more than once, since
that's not expected to change anyway.

Fixes cefsimple.
  • Loading branch information
asahilina committed Nov 12, 2024
1 parent e675f42 commit 73ffaa1
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
33 changes: 26 additions & 7 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,16 @@ FileManager::FileManager(FEXCore::Context::Context* ctx)
}
}

// Keep an fd open for /proc, to bypass chroot-style sandboxes
ProcFD = open("/proc", O_RDONLY | O_CLOEXEC);

// Track the st_dev of /proc, to check for inode equality
struct stat Buffer;
auto Result = fstat(ProcFD, &Buffer);
if (Result >= 0) {
ProcFSDev = Buffer.st_dev;
}

UpdatePID(::getpid());
}

Expand Down Expand Up @@ -998,30 +1008,39 @@ void FileManager::UpdatePID(uint32_t PID) {
CurrentPID = PID;

// Track the inode of /proc/self/fd/<RootFSFD>, to be able to hide it
auto FDpath = fextl::fmt::format("/proc/self/fd/{}", RootFSFD);
auto FDpath = fextl::fmt::format("self/fd/{}", RootFSFD);
struct stat Buffer {};
int Result = fstatat(AT_FDCWD, FDpath.c_str(), &Buffer, AT_SYMLINK_NOFOLLOW);
int Result = fstatat(ProcFD, FDpath.c_str(), &Buffer, AT_SYMLINK_NOFOLLOW);
if (Result >= 0) {
RootFSFDInode = Buffer.st_ino;
} else {
// Probably in a strict sandbox
RootFSFDInode = 0;
ProcFDInode = 0;
return;
}

// Track the st_dev of /proc, to check for inode equality
Result = stat("/proc/self", &Buffer);
// And track the ProcFSFD itself
FDpath = fextl::fmt::format("self/fd/{}", ProcFD);
Result = fstatat(ProcFD, FDpath.c_str(), &Buffer, AT_SYMLINK_NOFOLLOW);
if (Result >= 0) {
ProcFSDev = Buffer.st_dev;
ProcFDInode = Buffer.st_ino;
} else {
// ??
ProcFDInode = 0;
return;
}
}

bool FileManager::IsRootFSFD(int dirfd, uint64_t inode) {

// Check if we have to hide this entry
if (inode == RootFSFDInode) {
if (inode == RootFSFDInode || inode == ProcFDInode) {
struct stat Buffer;
if (fstat(dirfd, &Buffer) >= 0) {
if (Buffer.st_dev == ProcFSDev) {
LogMan::Msg::DFmt("Hiding directory entry for RootFSFD");
return true;
} else {
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ class FileManager final {
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
uint32_t CurrentPID {};
int RootFSFD {AT_FDCWD};
int ProcFD {0};
int64_t RootFSFDInode = 0;
int64_t ProcFDInode = 0;
dev_t ProcFSDev;
};
} // namespace FEX::HLE

0 comments on commit 73ffaa1

Please sign in to comment.