8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/errors.h"
10#include "pedigree/kernel/process/Process.h"
11#include "pedigree/kernel/process/Thread.h"
12#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
13#include "pedigree/kernel/utilities/lib.h"
17#include "modules/subsys/posix/PosixProcess.h"
18#include "modules/subsys/posix/PosixSubsystem.h"
19#include "modules/subsys/posix/system-syscalls.h"
21#include <sys/utsname.h>
32 uint32_t capabilities[3];
33 const char* arguments[2];
40int usercopyWorker(
void* parameter) {
41 Context* context =
reinterpret_cast<Context*
>(parameter);
45 const size_t length = PosixSubsystem::MaximumExecArgumentBytes + 2 * pageSize;
46 uintptr_t address = 0;
47 if (!process->allocateUserRange(Process::UserRegion::Normal, length, address)) {
50 uintptr_t mappedAddress = address;
52 if (!mappings.
mapAnon(mappedAddress, length,
53 MemoryMappedObject::Read | MemoryMappedObject::Write) ||
54 mappedAddress != address) {
57 UserFixture initial = {};
58 initial.groups[0] = 17;
59 initial.groups[1] = 29;
60 initial.capVersion = 0x19980330;
61 StringCopy(initial.executable,
"/__pedigree_missing_usercopy_fixture__");
62 auto*
fixture =
reinterpret_cast<UserFixture*
>(address);
64 process->setUserId(101);
65 process->setEffectiveUserId(102);
66 process->setSavedUserId(103);
67 process->setGroupId(201);
68 process->setEffectiveGroupId(202);
69 process->setSavedGroupId(203);
70 passed &= posix_getuid() == 101 && posix_geteuid() == 102 && posix_getgid() == 201 &&
71 posix_getegid() == 202;
76 passed &= posix_uname(&
fixture->name) == 0 &&
fixture->name.sysname[0] ==
'P' &&
77 fixture->name.nodename[0] ==
'p';
79 passed &= posix_uname(
nullptr) == -1 && thread->
getErrno() == Error::BadAddress;
80 passed &= posix_setgroups(2,
fixture->groups) == 0 && posix_getgroups(0,
nullptr) == 2;
83 posix_getgroups(1,
fixture->groups) == -1 && thread->
getErrno() == Error::InvalidArgument;
84 passed &= posix_getgroups(3,
fixture->groups) == 2 &&
fixture->groups[0] == 17 &&
87 passed &= posix_setgroups(NGROUPS_MAX + 1,
fixture->groups) == -1 &&
88 thread->
getErrno() == Error::InvalidArgument;
90 passed &= posix_setgroups(1,
nullptr) == -1 && thread->
getErrno() == Error::BadAddress;
91 passed &= posix_setgroups(0,
nullptr) == 0 && posix_getgroups(0,
nullptr) == 0;
92 const unsigned long savedTls = thread->
getTlsBase();
93 passed &= posix_arch_prctl(0x1003,
reinterpret_cast<unsigned long>(&
fixture->tls)) == 0 &&
96 passed &= posix_arch_prctl(0x1003, 0) == -1 && thread->
getErrno() == Error::BadAddress;
100 const unsigned long replacementTls =
reinterpret_cast<unsigned long>(&
fixture->tls);
101 const bool changedTls = posix_arch_prctl(0x1002, replacementTls) == 0 &&
103 const bool clearedTls = posix_arch_prctl(0x1002, 0) == 0 && thread->
getTlsBase() == 0;
104 const bool restoredTls = posix_arch_prctl(0x1002, savedTls) == 0;
105 passed &= changedTls && clearedTls && restoredTls;
106 passed &= posix_capget(&
fixture->capVersion,
fixture->capabilities) == 0 &&
107 fixture->capabilities[0] == 0xFFFFFFFF &&
fixture->capabilities[1] == 0xFFFFFFFF &&
108 fixture->capabilities[2] == 0xFFFFFFFF;
109 passed &= posix_capset(&
fixture->capVersion,
fixture->capabilities) == 0;
112 posix_capset(&
fixture->capVersion,
nullptr) == -1 && thread->
getErrno() == Error::BadAddress;
115 passed &= posix_capget(&
fixture->capVersion,
nullptr) == -1 &&
116 thread->
getErrno() == Error::InvalidArgument &&
fixture->capVersion == 0x19980330;
118 SyscallState state = {};
120 passed &= posix_execve(
fixture->executable,
nullptr,
nullptr, state) == -1 &&
121 thread->
getErrno() == Error::DoesNotExist;
124 passed &= posix_execve(
fixture->executable,
fixture->arguments,
nullptr, state) == -1 &&
125 thread->
getErrno() == Error::DoesNotExist;
126 char* oversized =
reinterpret_cast<char*
>(address + pageSize);
127 const size_t argumentBytes = PosixSubsystem::MaximumExecArgumentBytes;
128 char* content =
new char[argumentBytes + 1];
129 ByteSet(content,
'a', argumentBytes);
130 content[argumentBytes] = 0;
133 fixture->arguments[0] = oversized;
135 passed &= posix_execve(
fixture->executable,
fixture->arguments,
nullptr, state) == -1 &&
136 thread->
getErrno() == Error::TooBig;
138 mappings.
remove(address, length);
139 process->freeUserRange(Process::UserRegion::Normal, address, length);
140 context->passed = passed;
141 return passed ? 0 : 1;
145bool runHostedSystemUsercopyRegressions(
Process* kernelProcess) {
151 const bool joined =
worker->joinForCompletion();
152 const bool passed = joined && context.passed;
155 NOTICE(
"HOSTED-SYSCALL-TEST: PASS system-usercopy-contracts");
157 ERROR(
"HOSTED-SYSCALL-TEST: FAIL system-usercopy-contracts");
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 bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
VirtualAddressSpace * getAddressSpace()
static ProcessorInformation & information()
void setErrno(size_t err)
Process * getParent() const
virtual uintptr_t getKernelStart() const =0