mirror of
https://github.com/FEX-Emu/FEX.git
synced 2024-12-15 09:59:28 +00:00
Merge pull request #3666 from Sonicadvance1/fix_initial_darwinia
FileManagement: Fix fstatat/statx with self and NOFOLLOW
This commit is contained in:
commit
6052b335dc
@ -503,6 +503,24 @@ std::pair<int, const char*> FileManager::GetEmulatedFDPath(int dirfd, const char
|
||||
return std::make_pair(RootFSFD, &SubPath[1]);
|
||||
}
|
||||
|
||||
///< Returns true if the pathname is self and symlink flags are set NOFOLLOW.
|
||||
bool FileManager::IsSelfNoFollow(const char* Pathname, int flags) const {
|
||||
const bool Follow = (flags & AT_SYMLINK_NOFOLLOW) == 0;
|
||||
if (Follow) {
|
||||
// If we are following the self symlink then we don't care about this.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Pathname) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char PidSelfPath[50];
|
||||
snprintf(PidSelfPath, sizeof(PidSelfPath), "/proc/%i/exe", CurrentPID);
|
||||
|
||||
return strcmp(Pathname, "/proc/self/exe") == 0 || strcmp(Pathname, "/proc/thread-self/exe") == 0 || strcmp(Pathname, PidSelfPath) == 0;
|
||||
}
|
||||
|
||||
std::optional<std::string_view> FileManager::GetSelf(const char* Pathname) {
|
||||
if (SupportsProcFSInterpreter) {
|
||||
// FEX doesn't need to track procfs/exe if this is supported.
|
||||
@ -514,7 +532,7 @@ std::optional<std::string_view> FileManager::GetSelf(const char* Pathname) {
|
||||
}
|
||||
|
||||
char PidSelfPath[50];
|
||||
snprintf(PidSelfPath, 50, "/proc/%i/exe", CurrentPID);
|
||||
snprintf(PidSelfPath, sizeof(PidSelfPath), "/proc/%i/exe", CurrentPID);
|
||||
|
||||
if (strcmp(Pathname, "/proc/self/exe") == 0 || strcmp(Pathname, "/proc/thread-self/exe") == 0 || strcmp(Pathname, PidSelfPath) == 0) {
|
||||
return Filename();
|
||||
@ -829,6 +847,12 @@ uint64_t FileManager::Openat2(int dirfs, const char* pathname, FEX::HLE::open_ho
|
||||
}
|
||||
|
||||
uint64_t FileManager::Statx(int dirfd, const char* pathname, int flags, uint32_t mask, struct statx* statxbuf) {
|
||||
if (IsSelfNoFollow(pathname, flags)) {
|
||||
// If we aren't following the symlink for self then we need to return data about the symlink itself.
|
||||
// Let's just /actually/ return FEXInterpreter symlink information in this case.
|
||||
return FHU::Syscalls::statx(dirfd, pathname, flags, mask, statxbuf);
|
||||
}
|
||||
|
||||
auto NewPath = GetSelf(pathname);
|
||||
const char* SelfPath = NewPath ? NewPath->data() : nullptr;
|
||||
|
||||
@ -870,6 +894,11 @@ uint64_t FileManager::Statfs(const char* path, void* buf) {
|
||||
}
|
||||
|
||||
uint64_t FileManager::NewFSStatAt(int dirfd, const char* pathname, struct stat* buf, int flag) {
|
||||
if (IsSelfNoFollow(pathname, flag)) {
|
||||
// See Statx
|
||||
return ::fstatat(dirfd, pathname, buf, flag);
|
||||
}
|
||||
|
||||
auto NewPath = GetSelf(pathname);
|
||||
const char* SelfPath = NewPath ? NewPath->data() : nullptr;
|
||||
|
||||
@ -885,6 +914,11 @@ uint64_t FileManager::NewFSStatAt(int dirfd, const char* pathname, struct stat*
|
||||
}
|
||||
|
||||
uint64_t FileManager::NewFSStatAt64(int dirfd, const char* pathname, struct stat64* buf, int flag) {
|
||||
if (IsSelfNoFollow(pathname, flag)) {
|
||||
// See Statx
|
||||
return ::fstatat64(dirfd, pathname, buf, flag);
|
||||
}
|
||||
|
||||
auto NewPath = GetSelf(pathname);
|
||||
const char* SelfPath = NewPath ? NewPath->data() : nullptr;
|
||||
|
||||
|
@ -79,6 +79,7 @@ public:
|
||||
uint64_t Statfs(const char* path, void* buf);
|
||||
|
||||
std::optional<std::string_view> GetSelf(const char* Pathname);
|
||||
bool IsSelfNoFollow(const char* Pathname, int flags) const;
|
||||
|
||||
void UpdatePID(uint32_t PID) {
|
||||
CurrentPID = PID;
|
||||
|
29
unittests/FEXLinuxTests/tests/fs/self_symlink.cpp
Normal file
29
unittests/FEXLinuxTests/tests/fs/self_symlink.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
TEST_CASE("proc-self symlink") {
|
||||
// Saw with the Darwinia Linux game port.
|
||||
// It sanity checks that `/proc/self/exe` is a symlink and also that it points to a regular file.
|
||||
// This uses newfsstatat or statx behind the scenes which FEX didn't handle this edge-case correctly.
|
||||
|
||||
// Create a path with /proc/self/exe
|
||||
std::filesystem::path path {"/proc/self/exe"};
|
||||
|
||||
// Check the status of the file with status first.
|
||||
std::error_code ec;
|
||||
auto status = std::filesystem::status(path, ec);
|
||||
|
||||
// No error
|
||||
REQUIRE(!ec);
|
||||
CHECK(status.type() == std::filesystem::file_type::regular);
|
||||
|
||||
// Now check the status with symlink_status.
|
||||
status = std::filesystem::symlink_status(path, ec);
|
||||
|
||||
// No error
|
||||
REQUIRE(!ec);
|
||||
CHECK(status.type() == std::filesystem::file_type::symlink);
|
||||
|
||||
// The game would then continue to read std::filesystem::read_symlink.
|
||||
}
|
Loading…
Reference in New Issue
Block a user