mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
Pin the descriptor before mmap validation so guest descriptor reuse cannot redirect the eventual mapping. Apply the canonical guest creation mask when creating named objects, distinguishing new objects before setting permissions without changing the host process umask. Add regressions that reproduce both failures and document the remaining host requirements. Constraint: Guest umask must not mutate the process-wide host mask Confidence: high Scope-risk: narrow Tested: 17 targeted Linux runtime tests passed with zero skips; conventions and diff checks; Clang analyzer on three changed production translation units Not-tested: Full project build and suite, Windows runtime, console hardware and titles
84 lines
3.2 KiB
C++
84 lines
3.2 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "nid/Sha1.hpp"
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
|
|
extern "C" int APS5_VABI shm_open_nid_postfix(const char*, int, int);
|
|
extern "C" std::uint16_t APS5_VABI umask_nid_postfix(std::uint16_t);
|
|
|
|
static void Require(bool condition, const char* message) {
|
|
if (!condition) throw std::runtime_error(message);
|
|
}
|
|
|
|
class Masks {
|
|
public:
|
|
Masks(std::uint16_t guest, mode_t host) : guest(umask_nid_postfix(guest)), host(::umask(host)) {}
|
|
~Masks() { ::umask(host); umask_nid_postfix(guest); }
|
|
Masks(const Masks&) = delete;
|
|
Masks& operator=(const Masks&) = delete;
|
|
private:
|
|
std::uint16_t guest;
|
|
mode_t host;
|
|
};
|
|
|
|
class Object {
|
|
public:
|
|
explicit Object(const char* suffix) : name("/anyps5-permissions-" + std::to_string(getpid()) + suffix) {
|
|
const auto digest = Nid::Sha1(std::vector<std::uint8_t>(name.begin(), name.end()));
|
|
for (auto byte : digest) {
|
|
hostName += "0123456789abcdef"[byte >> 4];
|
|
hostName += "0123456789abcdef"[byte & 15];
|
|
}
|
|
::shm_unlink(hostName.c_str());
|
|
}
|
|
~Object() { if (descriptor >= 0) ::close(descriptor); ::shm_unlink(hostName.c_str()); }
|
|
Object(const Object&) = delete;
|
|
Object& operator=(const Object&) = delete;
|
|
std::string name;
|
|
int descriptor = -1;
|
|
private:
|
|
std::string hostName = "/anyps5-shm-";
|
|
};
|
|
|
|
static void CheckMode(const char* suffix, std::uint16_t guestMask, mode_t hostMask, int requested, mode_t expected) {
|
|
Masks masks(guestMask, hostMask);
|
|
Object object(suffix);
|
|
object.descriptor = shm_open_nid_postfix(object.name.c_str(), 2 | 0x200 | 0x800, requested);
|
|
Require(object.descriptor >= 0, "shared-memory creation failed");
|
|
struct stat info{};
|
|
Require(::fstat(object.descriptor, &info) == 0, "stat failed");
|
|
if ((info.st_mode & 07777) != expected) {
|
|
std::fprintf(stderr, "requested=%o guest-mask=%o host-mask=%o actual=%o expected=%o\n", requested, guestMask, hostMask, info.st_mode & 07777, expected);
|
|
throw std::runtime_error("shared-memory mode did not follow the guest umask");
|
|
}
|
|
const auto observedHostMask = ::umask(hostMask);
|
|
Require(observedHostMask == hostMask, "guest creation changed host umask");
|
|
if (expected == 0600) {
|
|
const int reopened = shm_open_nid_postfix(object.name.c_str(), 2 | 0x200, 0777);
|
|
Require(reopened >= 0, "existing-object reopen failed");
|
|
const int result = ::fstat(reopened, &info);
|
|
::close(reopened);
|
|
Require(result == 0 && (info.st_mode & 07777) == expected, "reopen changed existing permissions");
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
try {
|
|
CheckMode("-guest-restricts", 0077, 0000, 0666, 0600);
|
|
CheckMode("-host-restricts", 0000, 0077, 0666, 0666);
|
|
CheckMode("-guest-denies", 0777, 0000, 0777, 0000);
|
|
CheckMode("-special-bits", 0022, 0077, 07777, 0755);
|
|
std::puts("guest shared-memory permissions passed");
|
|
return 0;
|
|
} catch (const std::exception& error) {
|
|
std::fprintf(stderr, "%s\n", error.what());
|
|
return 1;
|
|
}
|
|
}
|