Files
AnyPS5/core/libs/tests/GuestSetrlimit.cpp
ionut27001andClaude Opus 5.5 ad9772edd1 fix(libkernel): report the getrlimit values measured on a PS5 for RLIMIT_STACK, RSS, MEMLOCK and NPROC
In a payload process on a PS5 (firmware 12.70), getrlimit returns
0x200000 for RLIMIT_STACK, infinity for RLIMIT_RSS and RLIMIT_MEMLOCK,
and 1604 for RLIMIT_NPROC, each as both soft and hard limit. These four
threw here. Whether a title process reads the same limits is not
measured.

setrlimit reads getrlimit first, so it now accepts RLIMIT_STACK,
RLIMIT_RSS and RLIMIT_MEMLOCK when the values do not change, as the
payload process does. RLIMIT_NPROC throws: in the payload process
setting it to its current value succeeds, but getrlimit then reads 1443,
and the limit is not stored here. Any other change still throws. The
getrlimit and setrlimit debt entries also record the payload process's
RLIMIT_DATA and RLIMIT_NOFILE readings, its 12555 clamp of RLIMIT_NOFILE
and its RLIMIT_NPROC reading after a same-value set.

AI-assisted: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:21:34 +02:00

93 lines
3.5 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <stdexcept>
struct ResourceLimit {
std::int64_t rlim_cur;
std::int64_t rlim_max;
};
extern "C" {
int APS5_VABI getrlimit_nid_postfix(int, ResourceLimit*);
int APS5_VABI setrlimit_nid_postfix(int, const ResourceLimit*);
int* APS5_VABI __error_nid_postfix();
}
static constexpr int GUEST_EFAULT = 14;
static constexpr int GUEST_EINVAL = 22;
static constexpr int GUEST_RLIMIT_DATA = 2;
static constexpr int GUEST_RLIMIT_STACK = 3;
static constexpr int GUEST_RLIMIT_RSS = 5;
static constexpr int GUEST_RLIMIT_MEMLOCK = 6;
static constexpr int GUEST_RLIMIT_NPROC = 7;
static constexpr int GUEST_RLIMIT_NOFILE = 8;
static constexpr int GUEST_RLIM_NLIMITS = 15;
static constexpr std::int64_t GUEST_RLIM_INFINITY = std::numeric_limits<std::int64_t>::max();
static void Require(bool value) { if (!value) std::abort(); }
static bool Throws(int resource, const ResourceLimit& limit) {
try {
setrlimit_nid_postfix(resource, &limit);
} catch (const std::runtime_error&) {
return true;
}
return false;
}
static void RequireError(int resource, const ResourceLimit* limit, int error) {
*__error_nid_postfix() = 0;
Require(setrlimit_nid_postfix(resource, limit) == -1);
Require(*__error_nid_postfix() == error);
}
int main() {
const ResourceLimit infinity{GUEST_RLIM_INFINITY, GUEST_RLIM_INFINITY};
RequireError(-1, nullptr, GUEST_EFAULT);
RequireError(GUEST_RLIM_NLIMITS, nullptr, GUEST_EFAULT);
RequireError(-1, &infinity, GUEST_EINVAL);
RequireError(GUEST_RLIM_NLIMITS, &infinity, GUEST_EINVAL);
static constexpr int unchanged[] = {GUEST_RLIMIT_STACK, GUEST_RLIMIT_RSS, GUEST_RLIMIT_MEMLOCK};
for (int resource : unchanged) {
ResourceLimit before{};
Require(getrlimit_nid_postfix(resource, &before) == 0);
*__error_nid_postfix() = 13;
Require(setrlimit_nid_postfix(resource, &before) == 0 && *__error_nid_postfix() == 13);
ResourceLimit after{};
Require(getrlimit_nid_postfix(resource, &after) == 0 && after.rlim_cur == before.rlim_cur && after.rlim_max == before.rlim_max);
}
ResourceLimit processes{};
Require(getrlimit_nid_postfix(GUEST_RLIMIT_NPROC, &processes) == 0 && processes.rlim_cur == 1604 && processes.rlim_max == 1604);
Require(Throws(GUEST_RLIMIT_NPROC, processes));
Require(Throws(GUEST_RLIMIT_STACK, ResourceLimit{0x100000, 0x200000}));
ResourceLimit current{};
Require(getrlimit_nid_postfix(GUEST_RLIMIT_DATA, &current) == 0);
*__error_nid_postfix() = 13;
Require(setrlimit_nid_postfix(GUEST_RLIMIT_DATA, &current) == 0);
Require(*__error_nid_postfix() == 13);
if (current.rlim_cur > 0) {
const ResourceLimit changed{current.rlim_cur - 1, current.rlim_max};
Require(Throws(GUEST_RLIMIT_DATA, changed));
}
const ResourceLimit softAboveHard{GUEST_RLIM_INFINITY, current.rlim_max};
if (current.rlim_cur == current.rlim_max)
Require(setrlimit_nid_postfix(GUEST_RLIMIT_DATA, &softAboveHard) == 0);
else
Require(Throws(GUEST_RLIMIT_DATA, softAboveHard));
const ResourceLimit negative{-1, -2};
if (current.rlim_cur == GUEST_RLIM_INFINITY && current.rlim_max == GUEST_RLIM_INFINITY)
Require(setrlimit_nid_postfix(GUEST_RLIMIT_DATA, &negative) == 0);
else
Require(Throws(GUEST_RLIMIT_DATA, negative));
Require(Throws(GUEST_RLIMIT_NOFILE, infinity));
return 0;
}