mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 12:00:17 +02:00
Merge pull request #5264 from Sonicadvance1/66
FEXLinuxTests: Adds execveat with mfd_cloexec test and related fixes.
This commit is contained in:
5 files changed
+129
-13
No files matched your search
+61
-11
@@ -7,6 +7,7 @@
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/map.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/FileLoading.h>
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
#include <FEXHeaderUtils/SymlinkChecks.h>
|
||||
@@ -22,6 +23,9 @@
|
||||
#include <utility>
|
||||
#include <tiny-json.h>
|
||||
|
||||
#include <range/v3/view/split.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
namespace FEX::Config {
|
||||
namespace JSON {
|
||||
static void LoadJSonConfig(const fextl::string& Config, std::function<void(const char* Name, const char* ConfigSring)> Func) {
|
||||
@@ -494,20 +498,66 @@ void LoadConfig(fextl::string ProgramName, char** const envp, const PortableInfo
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
const char* FindUserHomeThroughUID() {
|
||||
auto passwd = getpwuid(geteuid());
|
||||
if (passwd) {
|
||||
return passwd->pw_dir;
|
||||
fextl::string FindUserHomeThroughUID() {
|
||||
// `getpwuid` allocates memory, parse `/etc/passwd` manually.
|
||||
// Format is trivial: `<name>:<password hash>:<uid>:<gid>:<comment>:<home>:<shell>`
|
||||
|
||||
fextl::vector<char> Data;
|
||||
if (!FEXCore::FileLoading::LoadFile(Data, "/etc/passwd")) {
|
||||
return {};
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
auto to_string_view = [](auto rng) {
|
||||
return std::string_view(&*rng.begin(), ranges::distance(rng));
|
||||
};
|
||||
|
||||
const auto uid = geteuid();
|
||||
|
||||
for (const auto entry : ranges::views::split(Data, '\n') | ranges::views::transform(to_string_view)) {
|
||||
const auto elements = ranges::views::split(entry, ':') | ranges::views::transform(to_string_view);
|
||||
// Reject bad entries.
|
||||
if (std::distance(elements.begin(), elements.end()) != 7) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto iter = elements.begin();
|
||||
++iter; // name
|
||||
++iter; // password hash
|
||||
++iter; // comment
|
||||
// uid
|
||||
const auto uid_s = *iter;
|
||||
++iter;
|
||||
++iter; // gid
|
||||
// home
|
||||
const auto home_s = *iter;
|
||||
++iter;
|
||||
++iter; // shell
|
||||
|
||||
uint64_t element_uid;
|
||||
auto Results = std::from_chars(uid_s.begin(), uid_s.end(), element_uid, 10);
|
||||
|
||||
// Error parsing.
|
||||
if (Results.ptr == uid_s.begin()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element_uid == uid) {
|
||||
return fextl::string(home_s);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* GetHomeDirectory() {
|
||||
fextl::string GetHomeDirectory() {
|
||||
const char* HomeDir = getenv("HOME");
|
||||
|
||||
// Try to get home directory from uid
|
||||
if (!HomeDir || !FHU::Filesystem::Exists(HomeDir)) {
|
||||
HomeDir = FindUserHomeThroughUID();
|
||||
auto UIDHome = FindUserHomeThroughUID();
|
||||
if (!UIDHome.empty() && FHU::Filesystem::Exists(UIDHome)) {
|
||||
return UIDHome;
|
||||
}
|
||||
}
|
||||
|
||||
// try the PWD
|
||||
@@ -523,7 +573,7 @@ const char* GetHomeDirectory() {
|
||||
return HomeDir;
|
||||
}
|
||||
#else
|
||||
const char* GetHomeDirectory() {
|
||||
fextl::string GetHomeDirectory() {
|
||||
const char* HomeDir = getenv("WINEHOMEDIR");
|
||||
if (HomeDir) {
|
||||
// Skip over the \??\ prefix in the NT path since we want a DOS path
|
||||
@@ -560,7 +610,7 @@ fextl::string GetDataDirectory(bool Global, const PortableInformation& PortableI
|
||||
return GLOBAL_DATA_DIRECTORY;
|
||||
}
|
||||
|
||||
const char* HomeDir = GetHomeDirectory();
|
||||
auto HomeDir = GetHomeDirectory();
|
||||
const char* DataXDG = getenv("XDG_DATA_HOME");
|
||||
const fextl::string LegacyDir = fextl::string {HomeDir} + "/.fex-emu/";
|
||||
|
||||
@@ -607,7 +657,7 @@ fextl::string GetConfigDirectory(bool Global, const PortableInformation& Portabl
|
||||
return GLOBAL_DATA_DIRECTORY;
|
||||
}
|
||||
|
||||
const char* HomeDir = GetHomeDirectory();
|
||||
auto HomeDir = GetHomeDirectory();
|
||||
const char* ConfigXDG = getenv("XDG_CONFIG_HOME");
|
||||
|
||||
const fextl::string LegacyDir = fextl::string {HomeDir} + "/.fex-emu/";
|
||||
@@ -644,7 +694,7 @@ fextl::string GetCacheDirectory() {
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* HomeDir = GetHomeDirectory();
|
||||
auto HomeDir = GetHomeDirectory();
|
||||
const char* CacheXDG = getenv("XDG_CACHE_HOME");
|
||||
return (CacheXDG ? fextl::string {CacheXDG} : (fextl::string {HomeDir} + "/.cache")) + "/fex-emu/";
|
||||
#else
|
||||
|
||||
@@ -57,7 +57,7 @@ ApplicationNames GetApplicationNames(const fextl::vector<fextl::string>& Args, b
|
||||
*/
|
||||
void LoadConfig(fextl::string ProgramName = {}, char** const envp = nullptr, const PortableInformation& PortableInfo = {});
|
||||
|
||||
const char* GetHomeDirectory();
|
||||
fextl::string GetHomeDirectory();
|
||||
|
||||
fextl::string GetDataDirectory(const PortableInformation& PortableInfo);
|
||||
fextl::string GetConfigDirectory(bool Global, const PortableInformation& PortableInfo);
|
||||
|
||||
@@ -106,7 +106,7 @@ void FileManager::LoadThunkDatabase(fextl::unordered_map<fextl::string, ThunkDBO
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view HomeDirectory = FEX::Config::GetHomeDirectory();
|
||||
auto HomeDirectory = FEX::Config::GetHomeDirectory();
|
||||
|
||||
for (const json_t* Library = json_getChild(DB); Library != nullptr; Library = json_getSibling(Library)) {
|
||||
// Get the user defined name for the library
|
||||
|
||||
@@ -110,6 +110,10 @@ These all consume a `std::string` as their first argument. Use the equivalent fu
|
||||
### `fmt::format`
|
||||
Use `fextl::fmt::` instead
|
||||
|
||||
### `getpwuid` and `getpwuid_r`
|
||||
Allocates memory for parsing passwd and other files. One would assume `getpwuid_r` would use the buffer passed in, but nope glibc nss_database_get
|
||||
allocates memory.
|
||||
|
||||
### APIs that FEX doesn't have a replacement for
|
||||
Don't use any of these APIs in FEXLoader/FEXInterpreter. Shoutout to
|
||||
[this](https://stackoverflow.com/questions/43056338/standard-library-facilities-which-allocate-but-dont-use-an-allocator) StackOverflow post for this
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
static std::vector<char> LoadFile(const char* Path) {
|
||||
int fd = open(Path, O_RDONLY);
|
||||
REQUIRE(fd != -1);
|
||||
|
||||
struct stat st {};
|
||||
REQUIRE(fstat(fd, &st) != -1);
|
||||
|
||||
std::vector<char> Result {};
|
||||
Result.resize(st.st_size);
|
||||
|
||||
size_t DidRead {};
|
||||
do {
|
||||
auto Read = read(fd, Result.data() + DidRead, Result.size() - DidRead);
|
||||
|
||||
if (Read == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
REQUIRE(errno != 0);
|
||||
}
|
||||
|
||||
DidRead += Read;
|
||||
} while (DidRead != st.st_size);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
TEST_CASE("execveat - memfd - MFD_CLOEXEC") {
|
||||
auto MapsFile = LoadFile("/usr/bin/true");
|
||||
REQUIRE(MapsFile.size() != 0);
|
||||
|
||||
int fd = memfd_create("Anonymous", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
REQUIRE(fd != -1);
|
||||
|
||||
size_t Written {};
|
||||
do {
|
||||
auto Wrote = write(fd, MapsFile.data() + Written, MapsFile.size() - Written);
|
||||
if (Wrote == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
REQUIRE(errno != 0);
|
||||
}
|
||||
Written += Wrote;
|
||||
} while (Written != MapsFile.size());
|
||||
|
||||
const char* argv[] = {"tmp", nullptr};
|
||||
auto Res = ::syscall(SYS_execveat, fd, "", argv, nullptr, AT_EMPTY_PATH);
|
||||
|
||||
// Will only get here if execveat fails.
|
||||
close(fd);
|
||||
REQUIRE(Res == 0);
|
||||
}
|
||||
Reference in new issue
Block a user