mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
102 lines
3.9 KiB
C++
102 lines
3.9 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <dlfcn.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
extern "C" int* APS5_VABI __error_nid_postfix();
|
|
|
|
namespace {
|
|
|
|
using SetSpeed = int (APS5_VABI*)(void*, std::uint32_t);
|
|
|
|
void Require(bool value, const char* message) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "cfsetspeed: %s\n", message);
|
|
std::abort();
|
|
}
|
|
}
|
|
|
|
std::uint32_t Read(const unsigned char* data) {
|
|
std::uint32_t result;
|
|
std::memcpy(&result, data, sizeof(result));
|
|
return result;
|
|
}
|
|
|
|
void Check(SetSpeed setSpeed, unsigned char* attributes, std::uint32_t speed) {
|
|
std::array<unsigned char, 44> before;
|
|
std::memcpy(before.data(), attributes, before.size());
|
|
*__error_nid_postfix() = 123;
|
|
Require(setSpeed(attributes, speed) == 0, "valid call failed");
|
|
Require(*__error_nid_postfix() == 123, "successful call changed errno");
|
|
Require(Read(attributes + 36) == speed, "incorrect input speed");
|
|
Require(Read(attributes + 40) == speed, "incorrect output speed");
|
|
Require(std::memcmp(before.data(), attributes, 36) == 0, "flags or control characters changed");
|
|
}
|
|
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
Require(argc == 2, "expected the kernel library path");
|
|
#ifdef _WIN32
|
|
const auto library = LoadLibraryA(argv[1]);
|
|
Require(library != nullptr, "could not load libkernel");
|
|
const auto setSpeed = reinterpret_cast<SetSpeed>(GetProcAddress(library, "cfsetspeed_nid_postfix"));
|
|
SYSTEM_INFO info{};
|
|
GetSystemInfo(&info);
|
|
const std::size_t page = info.dwPageSize;
|
|
auto* memory = static_cast<unsigned char*>(VirtualAlloc(nullptr, 2 * page, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
|
Require(memory != nullptr, "could not allocate boundary fixture");
|
|
DWORD previous = 0;
|
|
Require(VirtualProtect(memory + page, page, PAGE_NOACCESS, &previous) != 0, "could not protect boundary fixture");
|
|
#else
|
|
const auto library = dlopen(argv[1], RTLD_NOW | RTLD_LOCAL);
|
|
Require(library != nullptr, "could not load libkernel");
|
|
const auto setSpeed = reinterpret_cast<SetSpeed>(dlsym(library, "cfsetspeed_nid_postfix"));
|
|
const long pageSize = sysconf(_SC_PAGESIZE);
|
|
Require(pageSize > 0, "could not query page size");
|
|
const auto page = static_cast<std::size_t>(pageSize);
|
|
auto* memory = static_cast<unsigned char*>(mmap(nullptr, 2 * page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
|
Require(memory != MAP_FAILED, "could not allocate boundary fixture");
|
|
Require(mprotect(memory + page, page, PROT_NONE) == 0, "could not protect boundary fixture");
|
|
#endif
|
|
Require(setSpeed != nullptr, "export is missing");
|
|
for (const auto speed : {0u, 1u, 50u, 9600u, 115200u, 0x12345678u, 0x80000000u, 0xffffffffu}) {
|
|
alignas(8) std::array<unsigned char, 60> bytes;
|
|
bytes.fill(0xa5);
|
|
Check(setSpeed, bytes.data() + 8, speed);
|
|
for (std::size_t i = 0; i < 8; ++i) {
|
|
Require(bytes[i] == 0xa5 && bytes[52 + i] == 0xa5, "write escaped the termios object");
|
|
}
|
|
auto* boundary = memory + page - 44;
|
|
std::memset(boundary - 8, 0x5a, 52);
|
|
Check(setSpeed, boundary, speed);
|
|
for (std::size_t i = 0; i < 8; ++i) Require(boundary[-8 + static_cast<int>(i)] == 0x5a, "write preceded the termios object");
|
|
}
|
|
bool threw = false;
|
|
try {
|
|
static_cast<void>(setSpeed(nullptr, 9600));
|
|
} catch (const std::invalid_argument&) {
|
|
threw = true;
|
|
}
|
|
Require(threw, "null pointer must be rejected explicitly");
|
|
#ifdef _WIN32
|
|
Require(VirtualFree(memory, 0, MEM_RELEASE) != 0, "could not free boundary fixture");
|
|
FreeLibrary(library);
|
|
#else
|
|
Require(munmap(memory, 2 * page) == 0, "could not free boundary fixture");
|
|
dlclose(library);
|
|
#endif
|
|
return 0;
|
|
}
|