Merge pull request #5097 from wcampbell-nv/cmdline-map

Remap /proc/pid/cmdline with PR_SET_MM_MAP
This commit is contained in:
Ryan Houdek authored and GitHub committed 2025-12-04 14:02:19 -08:00
commit c460cf0678
3 files changed
+62 -35

No files matched your search

-11
View File
@@ -54,17 +54,6 @@ public:
return ApplicationArgs;
}
/**
* Writes out the arguments in the format of /proc/self/cmdline
*/
virtual void WriteCmdlineFD(int32_t fd) const {
const auto& Args = GetApplicationArguments();
// cmdline is an array of null terminated arguments
for (const auto& Arg : Args) {
write(fd, Arg.c_str(), Arg.size() + 1); // Add 1 to include the null terminator
}
}
protected:
fextl::vector<fextl::string> ApplicationArgs;
};
+62 -9
View File
@@ -17,6 +17,7 @@
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/TypeDefines.h>
#include <FEXCore/Utils/FileLoading.h>
#include <FEXCore/fextl/list.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
@@ -29,7 +30,9 @@
#include <sys/auxv.h>
#include <sys/mman.h>
#include <sys/personality.h>
#include <sys/prctl.h>
#include <sys/random.h>
#include <linux/prctl.h>
#define PAGE_START(x) ((x) & ~(uintptr_t)(4095))
#define PAGE_OFFSET(x) ((x) & 4095)
@@ -707,6 +710,63 @@ public:
*AuxTabSize = sizeof(AuxType) * AuxVariables.size();
}
// Get the current memory map from /proc/self/stat
static bool GetCurrentMap(struct prctl_mm_map& map) {
// /proc/self/stat has 52 fields of at most 20 digits each (UINT64_MAX).
// 52*20 = 1040, so 2048 is a conservative upper bound
char stat_buffer[2048];
ssize_t bytes_read = FEXCore::FileLoading::LoadFileToBuffer("/proc/self/stat", stat_buffer);
// Ensure we don't read past the end into garbage data
stat_buffer[std::clamp(bytes_read, 0L, static_cast<ssize_t>(sizeof(stat_buffer)) - 1)] = '\0';
// See man proc_pid_stat
int items_read = sscanf(stat_buffer,
"%*d %*s %*c %*d %*d " // 1 to 5
"%*d %*d %*d %*u %*u " // 6 to 10
"%*u %*u %*u %*u %*u " // 11 to 15
"%*d %*d %*d %*d %*d " // 16 to 20
"%*d %*u %*u %*d %*u " // 21 to 25
"%llu %llu %llu %*u %*u " // 26 to 30
"%*u %*u %*u %*u %*u " // 31 to 35
"%*u %*u %*d %*d %*u " // 36 to 40
"%*u %*u %*u %*d %llu " // 40 to 45
"%llu %llu %llu %llu %llu " // 46 to 50
"%llu", // 51
&map.start_code, &map.end_code, &map.start_stack, &map.start_data, &map.end_data, &map.start_brk,
&map.arg_start, &map.arg_end, &map.env_start, &map.env_end);
if (items_read != 10) {
return false;
}
map.brk = reinterpret_cast<uint64_t>(sbrk(0));
// The kernel will leave these values unchanged, see implementation in sys.c
map.auxv = NULL;
map.auxv_size = 0;
map.exe_fd = -1;
return true;
}
// Point the OS to our new stack's argument data
void RemapArgumentData(uintptr_t NewArgStart, uint64_t ArgSize) {
struct prctl_mm_map map {};
if (GetCurrentMap(map)) {
map.arg_start = NewArgStart;
map.arg_end = NewArgStart + ArgSize;
int r = prctl(PR_SET_MM, PR_SET_MM_MAP, &map, sizeof(map), 0L);
if (r != 0) {
LogMan::Msg::EFmt("Failed to remap /proc/pid/cmdline data (prctl failed: result {}, errno {})", r, errno);
}
} else {
LogMan::Msg::EFmt("Failed to remap /proc/pid/cmdline data (GetCurrentMap failed)");
}
}
// Setups the stack initial data (argv, envp, auxv)
void SetupStack() {
StackPointer += StackSize();
@@ -803,6 +863,8 @@ public:
SetupPointers<uint32_t, auxv32_t, 4>(StackPointer, AuxVOffset, ArgumentOffset, EnvpOffset, ApplicationArgs, EnvironmentVariables,
AuxVariables, &AuxTabBase, &AuxTabSize);
}
RemapArgumentData(StackPointer + ArgumentOffset, ArgumentBackingSize);
}
fextl::vector<const char*> GetExecveArguments() const override {
@@ -816,15 +878,6 @@ public:
};
}
void WriteCmdlineFD(int32_t fd) const override {
// '/proc/self/cmdline' typically maps to the stack's argv data.
// Applications can write to this to change the cmdline value,
// but in FEX they'll write to the emulated stack rather than the OS'.
//
// Expose the contents of the emulated stack's argument data.
write(fd, reinterpret_cast<const void*>(StackPointer + ArgumentOffset), ArgumentBackingSize);
}
uint64_t GetBaseOffset() const override {
return BaseOffset;
}
@@ -586,21 +586,6 @@ EmulatedFDManager::EmulatedFDManager(FEXCore::Context::Context* ctx)
FDReadCreators[procAuxv] = &EmulatedFDManager::ProcAuxv;
FDReadCreators["/proc/self/auxv"] = &EmulatedFDManager::ProcAuxv;
auto cmdline_handler = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t {
const int FD = GenTmpFD(pathname, flags);
const auto* CodeLoader = FEX::HLE::_SyscallHandler->GetCodeLoader();
CodeLoader->WriteCmdlineFD(FD);
// One additional null terminator to finish the list
lseek(FD, 0, SEEK_SET);
SealTmpFD(FD);
return FD;
};
FDReadCreators["/proc/self/cmdline"] = cmdline_handler;
fextl::string procCmdLine = fextl::fmt::format("/proc/{}/cmdline", getpid());
FDReadCreators[procCmdLine] = cmdline_handler;
if (ThreadsConfig > 1) {
cpus_online = fextl::fmt::format("0-{}", ThreadsConfig - 1);
} else {