AnyPS5/core/libs/tests/GuestNamedShmPermissions.cpp

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;
}
}