8#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/errors.h"
11#include "pedigree/kernel/process/Process.h"
12#include "pedigree/kernel/process/Thread.h"
13#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
14#include "pedigree/kernel/processor/Processor.h"
15#include "pedigree/kernel/processor/VirtualAddressSpace.h"
17#include "modules/subsys/posix/PosixProcess.h"
18#include "modules/subsys/posix/PosixSubsystem.h"
19#include "modules/subsys/posix/linux-resource-abi.h"
20#include "modules/subsys/posix/system-syscalls.h"
23#include <sys/resource.h>
27constexpr int PreservedErrno = 173;
29struct ResourceSyscallContext {
30 ResourceSyscallContext(
Process* process,
int foreignPid)
31 : process(process), foreignPid(foreignPid), passed(false), returned(0) {}
39int resourceSyscallWorker(
void* parameter) {
40 ResourceSyscallContext* context =
reinterpret_cast<ResourceSyscallContext*
>(parameter);
43 uintptr_t address = 0;
44 if (!context->process->allocateUserRange(Process::UserRegion::Normal, pageSize, address)) {
45 context->returned += 1;
49 uintptr_t mappedAddress = address;
51 mappedAddress, pageSize, MemoryMappedObject::Read | MemoryMappedObject::Write);
52 if (!mapping || mappedAddress != address) {
56 context->process->freeUserRange(Process::UserRegion::Normal, address, pageSize);
57 context->returned += 1;
61 struct rlimit* nativeLimit =
reinterpret_cast<struct rlimit*
>(address + 64);
63 struct tms* processTimes =
reinterpret_cast<struct tms*
>(address + 384);
64 struct rusage*
usage =
reinterpret_cast<struct rusage*
>(address + 512);
66 uint8_t* linuxUsageCanary =
reinterpret_cast<uint8_t*
>(linuxUsage + 1);
68 struct rlimit* badNative =
reinterpret_cast<struct rlimit*
>(kernelStart);
73 passed &= posix_getrlimit(RLIMIT_CPU, nativeLimit) == 0 &&
74 nativeLimit->rlim_cur == RLIM_INFINITY && nativeLimit->rlim_max == RLIM_INFINITY &&
75 thread->
getErrno() == PreservedErrno;
78 passed &= posix_getrlimit(-1, nativeLimit) == -1 && thread->
getErrno() == Error::InvalidArgument;
81 posix_getrlimit(RLIMIT_NOFILE, badNative) == -1 && thread->
getErrno() == Error::BadAddress;
83 passed &= posix_getrlimit(RLIMIT_RTPRIO, nativeLimit) == 0 && nativeLimit->rlim_cur == 0 &&
84 nativeLimit->rlim_max == 0 && thread->
getErrno() == PreservedErrno;
87 passed &= posix_getrlimit(RLIMIT_RTTIME, nativeLimit) == 0 &&
88 nativeLimit->rlim_cur == RLIM_INFINITY && nativeLimit->rlim_max == RLIM_INFINITY &&
89 thread->
getErrno() == PreservedErrno;
93 passed &= posix_prlimit64(0, RLIMIT_NOFILE,
nullptr, linuxLimit) == 0 &&
94 linuxLimit->current == 16384 && linuxLimit->maximum == 16384 &&
95 thread->
getErrno() == PreservedErrno;
97 passed &= posix_prlimit64(
static_cast<int>(context->process->getId()), RLIMIT_NOFILE,
nullptr,
99 thread->
getErrno() == PreservedErrno;
102 passed &= posix_prlimit64(0, RLIMIT_NOFILE, badLinux,
nullptr) == -1 &&
103 thread->
getErrno() == Error::Unimplemented;
105 passed &= posix_prlimit64(0, RLIMIT_NOFILE, linuxLimit,
nullptr) == -1 &&
106 thread->
getErrno() == Error::Unimplemented;
108 passed &= posix_prlimit64(0, RLIMIT_NOFILE,
nullptr, badLinux) == -1 &&
109 thread->
getErrno() == Error::BadAddress;
111 passed &= posix_prlimit64(-1, RLIMIT_NOFILE,
nullptr, linuxLimit) == -1 &&
112 thread->
getErrno() == Error::NoSuchProcess;
114 passed &= posix_prlimit64(context->foreignPid, RLIMIT_NOFILE,
nullptr, linuxLimit) == -1 &&
115 thread->
getErrno() == Error::Unimplemented;
117 passed &= posix_prlimit64(0, -1,
nullptr, linuxLimit) == -1 &&
118 thread->
getErrno() == Error::InvalidArgument;
122 posix_setrlimit(RLIMIT_NOFILE, badNative) == -1 && thread->
getErrno() == Error::Unimplemented;
124 passed &= posix_setrlimit(RLIMIT_NOFILE, nativeLimit) == -1 &&
125 thread->
getErrno() == Error::Unimplemented;
128 passed &= posix_membarrier(0, 0, 0) == 0 && thread->
getErrno() == PreservedErrno;
130 passed &= posix_membarrier(1, 0, 0) == -1 && thread->
getErrno() == Error::InvalidArgument;
132 passed &= posix_membarrier(0, 1, 0) == -1 && thread->
getErrno() == Error::InvalidArgument;
134 constexpr Time::Timestamp clockTick = Time::Multiplier::Second / 100;
135 thread->publishTimeAccountingForHostedTest(73 * clockTick, 41 * clockTick);
136 context->process->publishTimeAccountingForHostedTest(235 * clockTick, 127 * clockTick);
137 Time::Timestamp expectedUser = context->process->getUserTime();
138 Time::Timestamp expectedKernel = context->process->getKernelTime();
139 const clock_t elapsedBefore = Time::getTicks() / clockTick;
141 const clock_t elapsed = posix_times(processTimes);
142 const clock_t elapsedAfter = Time::getTicks() / clockTick;
143 passed &= elapsed >= elapsedBefore && elapsed <= elapsedAfter &&
144 processTimes->tms_utime ==
static_cast<clock_t
>(expectedUser / clockTick) &&
145 processTimes->tms_stime ==
static_cast<clock_t
>(expectedKernel / clockTick) &&
146 !processTimes->tms_cutime && !processTimes->tms_cstime &&
147 thread->
getErrno() == PreservedErrno;
149 passed &= posix_times(
nullptr) >= 0 && thread->
getErrno() == PreservedErrno;
151 passed &= posix_times(
reinterpret_cast<struct tms*
>(kernelStart)) == -1 &&
152 thread->
getErrno() == Error::BadAddress;
154 expectedUser = context->process->getUserTime();
155 expectedKernel = context->process->getKernelTime();
159 posix_getrusage(RUSAGE_SELF,
usage) == 0 &&
160 usage->ru_utime.tv_sec ==
static_cast<time_t
>(expectedUser / Time::Multiplier::Second) &&
161 usage->ru_utime.tv_usec ==
162 static_cast<suseconds_t
>((expectedUser % Time::Multiplier::Second) /
163 Time::Multiplier::Microsecond) &&
164 usage->ru_stime.tv_sec ==
static_cast<time_t
>(expectedKernel / Time::Multiplier::Second) &&
165 usage->ru_stime.tv_usec ==
166 static_cast<suseconds_t
>((expectedKernel % Time::Multiplier::Second) /
167 Time::Multiplier::Microsecond) &&
168 thread->
getErrno() == PreservedErrno;
169 for (
size_t i =
sizeof(
LinuxRusage64); i <
sizeof(*usage); ++i) {
170 passed &= !
reinterpret_cast<uint8_t*
>(
usage)[i];
173 const Time::Timestamp threadUserBeforeNative = thread->
getUserTime();
174 const Time::Timestamp threadKernelBeforeNative = thread->getKernelTime();
176 const bool nativeThreadUsageSucceeded = posix_getrusage(RUSAGE_THREAD,
usage) == 0;
177 const Time::Timestamp threadUserAfterNative = thread->
getUserTime();
178 const Time::Timestamp threadKernelAfterNative = thread->getKernelTime();
179 const Time::Timestamp nativeThreadUser =
180 static_cast<Time::Timestamp
>(
usage->ru_utime.tv_sec) * Time::Multiplier::Second +
181 static_cast<Time::Timestamp
>(
usage->ru_utime.tv_usec) * Time::Multiplier::Microsecond;
182 const Time::Timestamp nativeThreadKernel =
183 static_cast<Time::Timestamp
>(
usage->ru_stime.tv_sec) * Time::Multiplier::Second +
184 static_cast<Time::Timestamp
>(
usage->ru_stime.tv_usec) * Time::Multiplier::Microsecond;
185 passed &= nativeThreadUsageSucceeded &&
187 threadUserBeforeNative - (threadUserBeforeNative % Time::Multiplier::Microsecond) &&
189 threadUserAfterNative - (threadUserAfterNative % Time::Multiplier::Microsecond) &&
190 nativeThreadKernel >= threadKernelBeforeNative -
191 (threadKernelBeforeNative % Time::Multiplier::Microsecond) &&
192 nativeThreadKernel <= threadKernelAfterNative -
193 (threadKernelAfterNative % Time::Multiplier::Microsecond) &&
194 thread->
getErrno() == PreservedErrno;
195 for (
size_t i = offsetof(
struct rusage, ru_maxrss); i <
sizeof(*usage); ++i) {
196 passed &= !
reinterpret_cast<uint8_t*
>(
usage)[i];
198 struct rusage untouched = {};
199 ByteSet(&untouched, 0xA5,
sizeof(untouched));
200 MemoryCopy(
usage, &untouched,
sizeof(untouched));
202 passed &= posix_getrusage(RUSAGE_CHILDREN,
usage) == 0 && !
usage->ru_utime.tv_sec &&
203 !
usage->ru_utime.tv_usec && !
usage->ru_stime.tv_sec && !
usage->ru_stime.tv_usec &&
204 thread->
getErrno() == PreservedErrno;
205 for (
size_t i = offsetof(
struct rusage, ru_maxrss); i <
sizeof(*usage); ++i) {
206 passed &= !
reinterpret_cast<uint8_t*
>(
usage)[i];
209 passed &= posix_getrusage(RUSAGE_SELF,
reinterpret_cast<struct rusage*
>(kernelStart)) == -1 &&
210 thread->
getErrno() == Error::BadAddress;
212 ByteSet(linuxUsage, 0xA5,
sizeof(*linuxUsage) + 32);
215 posix_linux_getrusage(RUSAGE_SELF, linuxUsage) == 0 &&
216 linuxUsage->userSeconds ==
static_cast<int64_t
>(expectedUser / Time::Multiplier::Second) &&
217 linuxUsage->userMicroseconds ==
218 static_cast<int64_t
>((expectedUser % Time::Multiplier::Second) /
219 Time::Multiplier::Microsecond) &&
220 linuxUsage->systemSeconds ==
221 static_cast<int64_t
>(expectedKernel / Time::Multiplier::Second) &&
222 linuxUsage->systemMicroseconds ==
223 static_cast<int64_t
>((expectedKernel % Time::Multiplier::Second) /
224 Time::Multiplier::Microsecond) &&
225 !linuxUsage->maximumResidentSetSize && !linuxUsage->involuntaryContextSwitches &&
226 thread->
getErrno() == PreservedErrno;
227 for (
size_t i = 0; i < 32; ++i) {
228 passed &= linuxUsageCanary[i] == 0xA5;
230 ByteSet(linuxUsage, 0xA5,
sizeof(*linuxUsage) + 32);
231 const Time::Timestamp threadUserBeforeLinux = thread->
getUserTime();
232 const Time::Timestamp threadKernelBeforeLinux = thread->getKernelTime();
234 const bool linuxThreadUsageSucceeded = posix_linux_getrusage(RUSAGE_THREAD, linuxUsage) == 0;
235 const Time::Timestamp threadUserAfterLinux = thread->
getUserTime();
236 const Time::Timestamp threadKernelAfterLinux = thread->getKernelTime();
237 const Time::Timestamp linuxThreadUser =
238 static_cast<Time::Timestamp
>(linuxUsage->userSeconds) * Time::Multiplier::Second +
239 static_cast<Time::Timestamp
>(linuxUsage->userMicroseconds) * Time::Multiplier::Microsecond;
240 const Time::Timestamp linuxThreadKernel =
241 static_cast<Time::Timestamp
>(linuxUsage->systemSeconds) * Time::Multiplier::Second +
242 static_cast<Time::Timestamp
>(linuxUsage->systemMicroseconds) * Time::Multiplier::Microsecond;
243 passed &= linuxThreadUsageSucceeded &&
245 threadUserBeforeLinux - (threadUserBeforeLinux % Time::Multiplier::Microsecond) &&
247 threadUserAfterLinux - (threadUserAfterLinux % Time::Multiplier::Microsecond) &&
248 linuxThreadKernel >= threadKernelBeforeLinux -
249 (threadKernelBeforeLinux % Time::Multiplier::Microsecond) &&
251 threadKernelAfterLinux - (threadKernelAfterLinux % Time::Multiplier::Microsecond) &&
252 thread->
getErrno() == PreservedErrno;
253 for (
size_t i = offsetof(
LinuxRusage64, maximumResidentSetSize); i <
sizeof(*linuxUsage); ++i) {
254 passed &= !
reinterpret_cast<uint8_t*
>(linuxUsage)[i];
256 for (
size_t i = 0; i < 32; ++i) {
257 passed &= linuxUsageCanary[i] == 0xA5;
259 ByteSet(linuxUsage, 0xA5,
sizeof(*linuxUsage) + 32);
261 passed &= posix_linux_getrusage(RUSAGE_CHILDREN, linuxUsage) == 0 && !linuxUsage->userSeconds &&
262 !linuxUsage->userMicroseconds && !linuxUsage->systemSeconds &&
263 !linuxUsage->systemMicroseconds && thread->
getErrno() == PreservedErrno;
264 for (
size_t i = 0; i <
sizeof(*linuxUsage); ++i) {
265 passed &= !
reinterpret_cast<uint8_t*
>(linuxUsage)[i];
267 for (
size_t i = 0; i < 32; ++i) {
268 passed &= linuxUsageCanary[i] == 0xA5;
272 posix_linux_getrusage(RUSAGE_SELF,
reinterpret_cast<LinuxRusage64*
>(kernelStart)) == -1 &&
273 thread->
getErrno() == Error::BadAddress;
275 char* requestedName =
reinterpret_cast<char*
>(address + 256);
276 char* returnedName =
reinterpret_cast<char*
>(address + 320);
277 StringCopy(requestedName,
"0123456789abcdef-long");
278 ByteSet(returnedName, 0xA5, 16);
279 const String originalName = thread->getName();
281 passed &= posix_prctl(PR_SET_NAME,
reinterpret_cast<uint64_t
>(requestedName), 0, 0, 0) == 0 &&
282 thread->getName().
compare(
"0123456789abcde") && thread->
getErrno() == PreservedErrno;
284 passed &= posix_prctl(PR_GET_NAME,
reinterpret_cast<uint64_t
>(returnedName), 0, 0, 0) == 0 &&
285 !MemoryCompare(returnedName,
"0123456789abcde", 15) && !returnedName[15] &&
286 thread->
getErrno() == PreservedErrno;
288 passed &= posix_prctl(-1, 0, 0, 0, 0) == -1 && thread->
getErrno() == Error::InvalidArgument;
290 passed &= posix_prctl(PR_SET_NAME, kernelStart, 0, 0, 0) == -1 &&
291 thread->
getErrno() == Error::BadAddress && thread->getName().
compare(
"0123456789abcde");
293 passed &= posix_prctl(PR_GET_NAME, kernelStart, 0, 0, 0) == -1 &&
294 thread->
getErrno() == Error::BadAddress;
295 thread->setName(originalName);
298 context->process->freeUserRange(Process::UserRegion::Normal, address, pageSize);
299 context->passed = passed;
300 context->returned += 1;
301 return passed ? 0 : 1;
304bool resourceSyscallSemantics(
Process* kernelProcess) {
311 ResourceSyscallContext context(process,
static_cast<int>(foreignProcess->
getId()));
312 Thread*
worker =
new Thread(process, resourceSyscallWorker, &context,
nullptr,
false,
true,
true);
313 worker->setName(
"hosted resource syscall semantics");
314 const bool started =
worker->start();
315 const bool joined = started &&
worker->joinForCompletion();
320 const bool passed = started && joined && context.returned == 1 && context.passed;
321 delete foreignProcess;
325 "HOSTED-SYSCALL-TEST: FAIL resource-syscall-semantics: "
326 "limits, accounting, fail-closed mutation, usercopy, membarrier, or prctl names regressed");
330 NOTICE(
"HOSTED-SYSCALL-TEST: PASS resource-syscall-semantics");
335bool runHostedResourceSyscallRegressions(
Process* process) {
336 return resourceSyscallSemantics(process);
Memory-mapped file interface.
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
size_t remove(uintptr_t base, size_t length)
static MemoryMapManager & instance()
static constexpr size_t getPageSize() PURE
static ProcessorInformation & information()
bool compare(const char *s, size_t len) const
void setErrno(size_t err)
Time::Timestamp getUserTime() const