The Pedigree Project 0.1
system-syscalls.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/ActivityDiagnostics.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/Version.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/linker/Elf.h"
25#include "pedigree/kernel/linker/KernelElf.h"
26#include "pedigree/kernel/panic.h"
27#include "pedigree/kernel/process/PerProcessorScheduler.h"
28#include "pedigree/kernel/process/Process.h"
29#include "pedigree/kernel/process/Scheduler.h"
30#include "pedigree/kernel/process/TerminationDeferral.h"
31#include "pedigree/kernel/process/Thread.h"
32#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
33#include "pedigree/kernel/processor/Processor.h"
34#include "pedigree/kernel/processor/StackFrame.h"
35#include "pedigree/kernel/processor/SyscallManager.h"
36#include "pedigree/kernel/processor/VirtualAddressSpace.h"
37#include "pedigree/kernel/processor/state.h"
38#include "pedigree/kernel/processor/types.h"
39#include "pedigree/kernel/syscallError.h"
40#include "pedigree/kernel/utilities/SecureRandom.h"
41#include "pedigree/kernel/utilities/String.h"
42#include "pedigree/kernel/utilities/Vector.h"
43#include "pedigree/kernel/utilities/ZombieQueue.h"
44#include "pedigree/kernel/utilities/lib.h"
45#include "pedigree/kernel/utilities/utility.h"
46
47#include "file-syscalls.h"
48#include "ipc-namespace.h"
49#include "linux-resource-abi.h"
50#include "modules/system/linker/DynamicLinker.h"
51#include "modules/system/vfs/File.h"
52#include "modules/system/vfs/MountView.h"
53#include "modules/system/vfs/Symlink.h"
54#include "modules/system/vfs/VFS.h"
55#include "network-namespace.h"
56#include "pipe-syscalls.h"
57#include "posixSyscallNumbers.h"
58#include "pthread-syscalls.h"
59#include "sandbox-state.h"
60#include "signal-syscalls.h"
61#include "system-syscalls.h"
62#include "sysv-semaphore-syscalls.h"
63#include "user-namespace.h"
64
65#define MACHINE_FORWARD_DECL_ONLY
66#include "pedigree/kernel/Subsystem.h"
67#include "pedigree/kernel/machine/Machine.h"
68#include "pedigree/kernel/machine/Timer.h"
69
70#include <PosixProcess.h>
71#include <PosixSubsystem.h>
72#include <grp.h>
73#include <limits.h>
74#include <pwd.h>
75#include <sched.h>
76#include <syslog.h>
77
78#include "modules/system/console/Console.h"
79#include "modules/system/users/Group.h"
80#include "modules/system/users/User.h"
81#include "modules/system/users/UserManager.h"
83#include <sys/resource.h>
84#include <sys/times.h>
85#include <sys/utsname.h>
86#include <sys/wait.h>
87
88#if X64 && !HOSTED
89static_assert(RUSAGE_SELF == 0, "musl RUSAGE_SELF selector changed");
90static_assert(RUSAGE_CHILDREN == -1, "musl RUSAGE_CHILDREN selector changed");
91static_assert(RUSAGE_THREAD == 1, "musl RUSAGE_THREAD selector changed");
92static_assert(offsetof(struct rusage, __reserved) == sizeof(LinuxRusage64),
93 "musl rusage prefix no longer matches the Linux amd64 syscall ABI");
94static_assert(sizeof(struct rusage) == sizeof(LinuxRusage64) + 16 * sizeof(long),
95 "musl rusage reserve changed");
96#endif
97
98// arch_prctl
99#define ARCH_SET_GS 0x1001
100#define ARCH_SET_FS 0x1002
101#define ARCH_GET_FS 0x1003
102#define ARCH_GET_GS 0x1004
103
104// Linux prctl operations used by musl's current-thread naming helpers.
105#define LINUX_PR_SET_NAME 15
106#define LINUX_PR_GET_NAME 16
107#define LINUX_TASK_NAME_LENGTH 16
108
109#define LINUX_GRND_NONBLOCK 0x1
110#define LINUX_GRND_RANDOM 0x2
111
112namespace {
113class CloneInterruptScope {
114 public:
115 explicit CloneInterruptScope(bool enabled = false) : m_Previous(Processor::getInterrupts()) {
117 }
118
119 ~CloneInterruptScope() {
120 Processor::setInterrupts(m_Previous);
121 }
122
123 private:
124 bool m_Previous;
125};
126
127enum class CloneRoute { Process, Vfork, Thread, Invalid };
128
129CloneRoute cloneRoute(unsigned long flags) {
130 constexpr unsigned long ExitSignalMask = 0xff;
131 constexpr unsigned long SpawnFlags = CLONE_VM | CLONE_VFORK | SIGCHLD;
132 constexpr unsigned long ProcessModifiers =
133 CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNET |
134 CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS;
135 constexpr unsigned long ThreadRequired =
136 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD;
137 constexpr unsigned long ThreadAllowed = ThreadRequired | CLONE_SYSVSEM | CLONE_SETTLS |
138 CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
139 CLONE_DETACHED | CLONE_CHILD_SETTID;
140
141 if (flags & CLONE_THREAD) {
142 if ((flags & ExitSignalMask) || (flags & ThreadRequired) != ThreadRequired ||
143 (flags & ~ThreadAllowed)) {
144 return CloneRoute::Invalid;
145 }
146 return CloneRoute::Thread;
147 }
148
149 // Process sharing is limited to vfork's bounded borrow. Other sharing and
150 // namespace combinations must not silently receive fork semantics.
151 const unsigned long processFlags = flags & ~ProcessModifiers;
152 if (processFlags == SpawnFlags)
153 return CloneRoute::Vfork;
154 if (processFlags == 0 || processFlags == SIGCHLD) {
155 return CloneRoute::Process;
156 }
157 return CloneRoute::Invalid;
158}
159} // namespace
160
161#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
162namespace {
163using CloneBeforeStartHook = void (*)(Thread*, size_t, void*);
164
165CloneBeforeStartHook g_CloneBeforeStartHook = nullptr;
166void* g_CloneBeforeStartHookContext = nullptr;
167} // namespace
168
169extern "C" EXPORTED_PUBLIC void posixSetCloneBeforeStartHookForTest(CloneBeforeStartHook hook,
170 void* context) {
171 if (hook) {
172 __atomic_store_n(&g_CloneBeforeStartHookContext, context, __ATOMIC_RELEASE);
173 __atomic_store_n(&g_CloneBeforeStartHook, hook, __ATOMIC_RELEASE);
174 } else {
175 __atomic_store_n(&g_CloneBeforeStartHook, static_cast<CloneBeforeStartHook>(nullptr),
176 __ATOMIC_RELEASE);
177 __atomic_store_n(&g_CloneBeforeStartHookContext, static_cast<void*>(nullptr), __ATOMIC_RELEASE);
178 }
179}
180
181extern "C" EXPORTED_PUBLIC int posixCloneRouteForTest(unsigned long flags) {
182 switch (cloneRoute(flags)) {
183 case CloneRoute::Process:
184 return 0;
185 case CloneRoute::Thread:
186 return 1;
187 case CloneRoute::Vfork:
188 return 2;
189 case CloneRoute::Invalid:
190 return -1;
191 }
192
193 return -1;
194}
195#endif
196
197
198//
199// Syscalls pertaining to system operations.
200//
201
202static PosixProcess* getPosixProcess() {
203 // Not a POSIX process
204 Process* pStockProcess = Processor::information().getCurrentThread()->getParent();
205 if (pStockProcess->getType() != Process::Posix) {
206 return nullptr;
207 }
208
209 return static_cast<PosixProcess*>(pStockProcess);
210}
211
212static bool copyUserString(const char* userString, String& copy) {
213 PosixSubsystem::UserStringResult result =
214 PosixSubsystem::copyUserString(userString, copy, PATH_MAX);
215 if (result == PosixSubsystem::UserStringBadAddress) {
216 SYSCALL_ERROR(BadAddress);
217 return false;
218 }
219 if (result == PosixSubsystem::UserStringTooLong) {
220 SYSCALL_ERROR(NameTooLong);
221 return false;
222 }
223 return true;
224}
225
226ssize_t posix_getrandom(void* buffer, size_t length, unsigned int flags) {
227 if (flags & ~(LINUX_GRND_NONBLOCK | LINUX_GRND_RANDOM)) {
228 SYSCALL_ERROR(InvalidArgument);
229 return -1;
230 }
231
232 uint8_t snapshot[256];
233 const size_t requested = length < sizeof(snapshot) ? length : sizeof(snapshot);
234 const size_t produced = secure_random_bytes(snapshot, requested);
235 if (requested && !produced) {
236 SYSCALL_ERROR(NoMoreProcesses);
237 return -1;
238 }
239 const bool copied = PosixSubsystem::copyToUser(buffer, snapshot, produced);
240 pedigree_random::erase(snapshot, sizeof(snapshot));
241 if (!copied) {
242 SYSCALL_ERROR(BadAddress);
243 return -1;
244 }
245 return static_cast<ssize_t>(produced);
246}
247
249static size_t save_string_array(const char** array, Vector<SharedPointer<String>>& rArray) {
250 size_t result = 0;
251 while (*array) {
252 String* pStr = new String(*array);
253 rArray.pushBack(SharedPointer<String>(pStr));
254 array++;
255
256 result += pStr->length() + 1;
257 }
258
259 return result;
260}
261
265static char** load_string_array(Vector<SharedPointer<String>>& rArray, uintptr_t arrayLoc,
266 uintptr_t& arrayEndLoc) {
267 char** pMasterArray = reinterpret_cast<char**>(arrayLoc);
268
269 char* pPtr = reinterpret_cast<char*>(arrayLoc + sizeof(char*) * (rArray.count() + 1));
270 int i = 0;
271 for (auto it = rArray.begin(); it != rArray.end(); it++) {
272 const String* pStr = it->get();
273
274 StringCopy(pPtr, pStr->cstr());
275 pPtr[pStr->length()] = '\0'; // Ensure NULL-termination.
276
277 pMasterArray[i] = pPtr;
278
279 pPtr += pStr->length() + 1;
280 i++;
281 }
282
283 pMasterArray[i] = 0; // Null terminate.
284 arrayEndLoc = reinterpret_cast<uintptr_t>(pPtr);
285
286 return pMasterArray;
287}
288
289long posix_sbrk(int delta) {
290 SC_NOTICE("sbrk(" << delta << ")");
291
292 long ret = reinterpret_cast<long>(Processor::information().getVirtualAddressSpace().expandHeap(
294 SC_NOTICE(" -> " << ret);
295 if (ret == 0) {
296 SYSCALL_ERROR(OutOfMemory);
297 return -1;
298 } else
299 return ret;
300}
301
302uintptr_t posix_brk(uintptr_t theBreak) {
303 SC_NOTICE("brk(" << theBreak << ")");
305 auto& space = Processor::information().getVirtualAddressSpace();
306 const uintptr_t current = reinterpret_cast<uintptr_t>(space.getEndOfHeap());
307 // The Linux syscall returns the unchanged break on failed growth. Musl's
308 // allocator compares this value with the requested address.
309 Processor::information().getCurrentThread()->setErrno(0);
310 if (theBreak <= current || theBreak - current > static_cast<uintptr_t>(INTPTR_MAX))
311 return current;
312 if (!space.expandHeap(static_cast<intptr_t>(theBreak - current), VirtualAddressSpace::Write)) {
313 Processor::information().getCurrentThread()->setErrno(0);
314 return current;
315 }
316 return reinterpret_cast<uintptr_t>(space.getEndOfHeap());
317}
318
319SyscallState posix_copy_clone_state(const SyscallState& state) {
320#if X64 && !HOSTED
321 // The child's frame must own its metadata before it leaves this CPU.
322 state.getUserEntryMetadata();
323#endif
324 SyscallState clonedState = state;
325#if HOSTED
326 // The hosted bridge's errno destination is stack-local to the parent's
327 // translator frame and cannot survive in the child return state.
328 clonedState.error_ptr = 0;
329#endif
330 return clonedState;
331}
332
333long posix_clone(SyscallState& state, unsigned long flags, void* child_stack, int* ptid, int* ctid,
334 unsigned long newtls, bool linuxAbi, bool clearSignalHandlers) {
335 SC_NOTICE("clone(" << Hex << flags << ", " << child_stack << ", " << ptid << ", " << ctid << ", "
336 << newtls << ")");
337
338 Process* pParentProcess = Processor::information().getCurrentThread()->getParent();
339 Process::ThreadCreationScope creation(*pParentProcess);
340 if (!creation) {
341 SYSCALL_ERROR(NoMoreProcesses);
342 return -1;
343 }
344
345 // Allocation and the mapping policy may wait. Low-level page-table changes
346 // provide their own short critical sections; restore the caller's IRQ state.
347 CloneInterruptScope interrupts(true);
348
349 // Must clone state as we make modifications for the new thread here.
350 SyscallState clonedState = posix_copy_clone_state(state);
351
352 // Basic warnings to start with.
353 if (flags & CLONE_PARENT) {
354 SC_NOTICE(" -> CLONE_PARENT is not yet supported!");
355 }
356
357 const CloneRoute route = cloneRoute(flags);
358 if (route == CloneRoute::Invalid || (clearSignalHandlers && route == CloneRoute::Thread)) {
359 SYSCALL_ERROR(InvalidArgument);
360 SC_NOTICE(" -> EINVAL (unsupported or inconsistent clone flags)");
361 return -1;
362 }
363 if (route == CloneRoute::Thread && pParentProcess->isVforkChild()) {
364 // Detach is owned by the sole child thread; it cannot strand peers in
365 // the borrowed image when exec or exit wakes the creator.
366 SYSCALL_ERROR(InvalidArgument);
367 return -1;
368 }
369
370 if (route != CloneRoute::Thread &&
371 (flags & (CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_SETTLS))) {
373 MemoryMapManager::OperationGuard mappingGuard(mappings);
374 auto writableId = [&](int* address) {
375 const uintptr_t target = reinterpret_cast<uintptr_t>(address);
376 return PosixSubsystem::checkAddress(target, sizeof(int), PosixSubsystem::SafeWrite) &&
377 mappings.faultIn(target, true) && mappings.faultIn(target + sizeof(int) - 1, true);
378 };
379 if (((flags & CLONE_PARENT_SETTID) && !writableId(ptid)) ||
380 ((flags & CLONE_CHILD_SETTID) && !writableId(ctid))) {
381 SYSCALL_ERROR(BadAddress);
382 return -1;
383 }
384 if ((flags & CLONE_SETTLS) && (newtls >= pParentProcess->getAddressSpace()->getKernelStart()
385#if X64
386 || newtls >= 0x0000800000000000ULL
387#endif
388 )) {
389 SYSCALL_ERROR(NotEnoughPermissions);
390 return -1;
391 }
392 }
393
394 Thread& creator = *Processor::information().getCurrentThread();
395 TaskCredentialsRef childCredentials;
396 if ((flags & CLONE_NEWUSER) && !posix_user_namespace_prepare(creator, childCredentials)) {
397 return -1;
398 }
399 if (!(flags & CLONE_NEWUSER) &&
400 (flags & (CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWNET)) &&
401 !posix_capable(PosixCapabilities::SysAdmin)) {
402 SYSCALL_ERROR(NotEnoughPermissions);
403 return -1;
404 }
405 const auto ownerNamespace =
406 childCredentials ? childCredentials->userNamespace : posix_user_namespace(creator);
407 NetworkNamespaceRef childNetwork;
408 if ((flags & CLONE_NEWNET) && !posix_network_namespace_prepare(ownerNamespace, childNetwork)) {
409 return -1;
410 }
412 if (flags & CLONE_NEWIPC) {
413 childIpc = SharedPointer<IpcNamespace>::tryAllocate(ownerNamespace);
414 if (!childIpc) {
415 SYSCALL_ERROR(OutOfMemory);
416 return -1;
417 }
418 }
419 Thread::SecurityStateRef childSecurity;
420 if (!posix_sandbox_prepare_namespaces(creator, childCredentials, childIpc, childNetwork,
421 childSecurity)) {
422 return -1;
423 }
424 PosixSubsystem* creatorSubsystem = getSubsystem();
425 TraceCloneAdmission traceCreation;
426 TraceTaskRef creatorTask;
428 if (!creatorSubsystem || !creatorSubsystem->traceContext().taskToken(
429 *Processor::information().getCurrentThread(), creatorTask)) {
430 SYSCALL_ERROR(NoSuchProcess);
431 return -1;
432 }
433 if (route == CloneRoute::Thread) {
434 if (creatorSubsystem->traceContext().reserveThreadCreation(traceCreation) !=
435 TraceStatus::Success) {
436 SYSCALL_ERROR(OperationNotSupported);
437 return -1;
438 }
439 if (creatorSubsystem->traceContext().prepareTask(preparedTrace) != TraceStatus::Success) {
440 SYSCALL_ERROR(OutOfMemory);
441 return -1;
442 }
443 }
444 auto creatorNamespaces = creatorSubsystem ? creatorSubsystem->namespaceContext()
446 UtsRef creatorUts;
448 if (!creatorNamespaces ||
449 !creatorNamespaces->acquireThread(*Processor::information().getCurrentThread(), creatorUts))
450 return posix_uts_error(UtsStatus::Missing);
451 UtsStatus utsPrepared;
452 {
454 utsPrepared =
455 posix_uts_prepare_thread(creatorUts, flags & CLONE_NEWUTS, preparedUts, ownerNamespace);
456 }
457 if (utsPrepared != UtsStatus::Success)
458 return posix_uts_error(utsPrepared);
459
460 const ThreadPlacement placement =
461 ThreadPlacement::inherit(*Processor::information().getCurrentThread());
462
463 if (route == CloneRoute::Thread) {
464 // clone vm doesn't actually copy the address space, it shares it
465
466 // New child's stack. Must be valid as we're sharing the address space.
467 if (!child_stack) {
468 SYSCALL_ERROR(InvalidArgument);
469 return -1;
470 }
471
472 // Set up stack for new thread.
473 clonedState.setStackPointer(reinterpret_cast<uintptr_t>(child_stack));
474
475 // Child returns 0 -- parent returns the new thread ID.
476 clonedState.setSyscallReturnValue(0);
477
478 Thread* pThread = nullptr;
479 size_t threadId = 0;
480 bool copiedIds = false;
481 {
483 MemoryMapManager::OperationGuard mappingGuard(mappings);
484 auto writableId = [&](int* address) {
485 const uintptr_t target = reinterpret_cast<uintptr_t>(address);
486 return PosixSubsystem::checkAddress(target, sizeof(int), PosixSubsystem::SafeWrite) &&
487 mappings.faultIn(target, true) && mappings.faultIn(target + sizeof(int) - 1, true);
488 };
489 if (((flags & CLONE_CHILD_SETTID) && !writableId(ctid)) ||
490 ((flags & CLONE_PARENT_SETTID) && !writableId(ptid))) {
491 SYSCALL_ERROR(BadAddress);
492 return -1;
493 }
494 const bool setTls = !linuxAbi || (flags & CLONE_SETTLS);
495 if (setTls && (newtls >= pParentProcess->getAddressSpace()->getKernelStart()
496#if X64
497 || newtls >= 0x0000800000000000ULL
498#endif
499 )) {
500 SYSCALL_ERROR(NotEnoughPermissions);
501 return -1;
502 }
503 // The native ABI initializes its TLS self pointer. Linux supplies an
504 // opaque FS base and owns initialization of any memory it points to.
505 if (!linuxAbi &&
506 !PosixSubsystem::copyToUser(reinterpret_cast<void*>(newtls), &newtls, sizeof(newtls))) {
507 SYSCALL_ERROR(BadAddress);
508 return -1;
509 }
510
511 pThread = new Thread(pParentProcess, clonedState, true, &placement);
512 if (!pThread) {
513 SYSCALL_ERROR(OutOfMemory);
514 return -1;
515 }
516 pThread->executionPersonality().inherit(
517 Processor::information().getCurrentThread()->executionPersonality());
518 posix_sandbox_inherit(*pThread, *Processor::information().getCurrentThread());
519 creatorNamespaces->publishThread(preparedUts, *pThread, false);
520 if (creatorSubsystem->traceContext().publishTask(preparedTrace, *pThread) !=
521 TraceStatus::Success &&
523 FATAL("clone trace task publication failed");
524 pThread->setName("posix clone() thread");
525 if (setTls) {
526 pThread->setTlsBase(newtls);
527 }
528 threadId = linuxAbi ? pThread->getUserspaceTaskId() : pThread->getId();
529 }
530 if (linuxAbi && !threadId) {
532 pThread->startDetached();
533 SYSCALL_ERROR(OutOfMemory);
534 return -1;
535 }
536 {
537 CloneInterruptScope enabled(true);
538 if (!posix_sem_clone(Processor::information().getCurrentThread(), pThread,
539 flags & CLONE_SYSVSEM)) {
541 pThread->startDetached();
542 SYSCALL_ERROR(OutOfMemory);
543 return -1;
544 }
545 }
546 const int id = static_cast<int>(threadId);
547 copiedIds =
548 (!(flags & CLONE_CHILD_SETTID) || PosixSubsystem::copyToUser(ctid, &id, sizeof(id))) &&
549 (!(flags & CLONE_PARENT_SETTID) || PosixSubsystem::copyToUser(ptid, &id, sizeof(id)));
550 if (copiedIds && (flags & CLONE_CHILD_CLEARTID)) {
551 pThread->setClearChildTid(reinterpret_cast<uintptr_t>(ctid));
552 }
553 if (!copiedIds) {
554 // The existing delayed-start cancellation path owns retirement. A
555 // published Thread cannot be deleted directly on this error path.
557 pThread->startDetached();
558 SYSCALL_ERROR(BadAddress);
559 return -1;
560 }
561
562#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
563 void* hookContext = __atomic_load_n(&g_CloneBeforeStartHookContext, __ATOMIC_ACQUIRE);
564 CloneBeforeStartHook hook = __atomic_load_n(&g_CloneBeforeStartHook, __ATOMIC_ACQUIRE);
565 if (hook) {
566 hook(pThread, threadId, hookContext);
567 }
568#endif
569
570 if (!pThread->startDetached()) {
571 FATAL("clone(): delayed thread could not be started.");
572 }
573
574 // Parent gets the new thread ID.
575 SC_NOTICE(" -> " << threadId << " [new thread]");
576 return threadId;
577 }
578
580 const bool borrowAddressSpace = route == CloneRoute::Vfork;
581 if (borrowAddressSpace) {
582 vforkCompletion =
584 if (!vforkCompletion) {
585 SYSCALL_ERROR(OutOfMemory);
586 return -1;
587 }
588 }
589
590 // A vfork caller may borrow its current stack; clone wrappers supply one.
591 if (child_stack) {
592 clonedState.setStackPointer(reinterpret_cast<uintptr_t>(child_stack));
593 }
594
595 PosixSubsystem* pParentSubsystem = static_cast<PosixSubsystem*>(pParentProcess->getSubsystem());
596 if (!pParentSubsystem) {
597 ERROR("No subsystem for the parent process!");
598 SYSCALL_ERROR(InvalidArgument);
599 return -1;
600 }
601
602 // Enrollment precedes MM admission. Pivot updates this unpublished context
603 // too; any rollback retires its owner after the mapping guard has unwound.
604 FilesystemContextOwner childFilesystem;
605 auto parentFilesystem = pParentProcess->acquireFilesystemContext();
606 auto* parentView = VfsMountView::fromContext(parentFilesystem);
607 if (!parentFilesystem || !parentView ||
608 ((flags & CLONE_NEWNS)
609 ? !parentView->forkNamespace(parentFilesystem, childFilesystem,
610 ownerNamespace ? ownerNamespace->identity() : 0)
611 : !parentFilesystem->forkForProcess(childFilesystem))) {
612 SYSCALL_ERROR(OutOfMemory);
613 return -1;
614 }
615
616 // Inhibit signals to the parent
617 for (size_t sig = 0; sig < PosixSubsystem::SignalDispositionCount; sig++)
618 Processor::information().getCurrentThread()->inhibitEvent(sig, true);
619
620 PosixProcess* pProcess;
621 PosixSubsystem* pSubsystem;
622 {
623 // PTEs, raw allocation inventory, and managed metadata describe one snapshot.
625 pProcess = new PosixProcess(pParentProcess, true, Process::FilesystemContextMode::Deferred,
626 borrowAddressSpace);
627 if (!pProcess || !pProcess->getAddressSpace() || !pProcess->jobControlReady() ||
628 !pProcess->pidNamespaceReady() ||
629 ((flags & CLONE_NEWPID) && !pProcess->createPidNamespace())) {
630 delete pProcess;
631 for (size_t sig = 0; sig < PosixSubsystem::SignalDispositionCount; sig++)
632 Processor::information().getCurrentThread()->inhibitEvent(sig, false);
633 SYSCALL_ERROR(OutOfMemory);
634 SC_NOTICE(" -> ENOMEM");
635 return -1;
636 }
637
638 pSubsystem = new PosixSubsystem(*pParentSubsystem, clearSignalHandlers);
639 if (!pSubsystem || !pSubsystem->namespaceContext() ||
640 !pSubsystem->namespaceContext()->valid()) {
641 if (pSubsystem)
642 pProcess->setSubsystem(pSubsystem);
643 ERROR("Could not create a subsystem for the child process!");
644 delete pProcess;
645
646 SYSCALL_ERROR(OutOfMemory);
647
648 // Allow signals again, something went wrong
649 for (size_t sig = 0; sig < PosixSubsystem::SignalDispositionCount; sig++)
650 Processor::information().getCurrentThread()->inhibitEvent(sig, false);
651 SC_NOTICE(" -> ENOMEM");
652 return -1;
653 }
654 pProcess->setSubsystem(pSubsystem);
655 pSubsystem->setProcess(pProcess);
656
657 // Copy POSIX Process Group information if needed
658 if (pParentProcess->getType() == Process::Posix) {
659 PosixProcess* p = static_cast<PosixProcess*>(pParentProcess);
660
661 // Do not adopt leadership status.
662 if (p->getGroupMembership() == PosixProcess::Leader) {
663 SC_NOTICE("fork parent was a group leader.");
664 } else {
665 SC_NOTICE("fork parent had status " << static_cast<int>(p->getGroupMembership()) << "...");
666 }
667 pProcess->inheritProcessGroup(p);
668 }
669
670 // Register with the dynamic linker.
671 DynamicLinker* oldLinker = pProcess->getLinker();
672 if (oldLinker) {
673 DynamicLinker* newLinker = new DynamicLinker(*oldLinker);
674 pProcess->setLinker(newLinker);
675 }
676
677 if (borrowAddressSpace) {
678 pProcess->borrowVforkAddressSpace(*pParentProcess, vforkCompletion);
679 } else if (!MemoryMapManager::instance().clone(pProcess)) {
680 delete pProcess;
681 for (size_t sig = 0; sig < PosixSubsystem::SignalDispositionCount; ++sig)
682 Processor::information().getCurrentThread()->inhibitEvent(sig, false);
683 SYSCALL_ERROR(OutOfMemory);
684 return -1;
685 }
686 }
687
688 if (!pProcess->installFilesystemContext(pedigree_std::move(childFilesystem)))
689 FATAL("Fork could not install its prepared filesystem context");
690
691 // Copy the file descriptors from the parent
692 pSubsystem->copyDescriptors(pParentSubsystem);
693
694 // Child returns 0.
695 clonedState.setSyscallReturnValue(0);
696
697 // Allow signals to the parent again
698 for (size_t sig = 0; sig < PosixSubsystem::SignalDispositionCount; sig++)
699 Processor::information().getCurrentThread()->inhibitEvent(sig, false);
700
701 // Set ctid in the new address space if we are required to.
702 if (flags & CLONE_CHILD_SETTID) {
703 VirtualAddressSpace& curr = Processor::information().getVirtualAddressSpace();
704 VirtualAddressSpace* va = pProcess->getAddressSpace();
705 const int childId = static_cast<int>(pProcess->getUserspaceId());
706 bool copied = false;
707 {
710 copied = PosixSubsystem::copyToUser(ctid, &childId, sizeof(childId));
712 }
713 if (!copied) {
714 delete pProcess;
715 SYSCALL_ERROR(BadAddress);
716 return -1;
717 }
718 }
719
720 if (flags & CLONE_PARENT_SETTID) {
721 const int childId =
722 static_cast<int>(pProcess->getUserspaceId(pParentProcess->pidNamespace().get()));
723 if (!PosixSubsystem::copyToUser(ptid, &childId, sizeof(childId))) {
724 delete pProcess;
725 SYSCALL_ERROR(BadAddress);
726 return -1;
727 }
728 }
729
730 pSubsystem->traceContext().setCreator(creatorTask);
731 if (pSubsystem->traceContext().prepareTask(preparedTrace) != TraceStatus::Success) {
732 delete pProcess;
733 SYSCALL_ERROR(OutOfMemory);
734 return -1;
735 }
736
737 // The process is still unpublished, so this image is not remotely reachable
738 // until its remaining thread state is assembled and publish() runs below.
739 if (!pSubsystem->publishUserImage(*pProcess->getAddressSpace())) {
740 delete pProcess;
741 SYSCALL_ERROR(OutOfMemory);
742 return -1;
743 }
744
745 // Create a new thread for the new process.
746 Thread* pThread = new Thread(pProcess, clonedState, true, &placement);
747 if (!pThread) {
748 delete pProcess;
749 SYSCALL_ERROR(OutOfMemory);
750 return -1;
751 }
752 pThread->executionPersonality().inherit(
753 Processor::information().getCurrentThread()->executionPersonality());
754 pThread->setSecurityState(childSecurity);
755 pSubsystem->namespaceContext()->publishThread(preparedUts, *pThread, true);
756 if (pSubsystem->traceContext().publishTask(preparedTrace, *pThread) != TraceStatus::Success &&
758 FATAL("fork trace task publication failed");
759 pThread->setName("posix clone() forked thread");
760 if (flags & CLONE_SETTLS)
761 pThread->setTlsBase(newtls);
762 pThread->detach();
763 if (flags & CLONE_CHILD_CLEARTID) {
764 // The exit hook clears this before releasing a borrowed vfork image.
765 pThread->setClearChildTid(reinterpret_cast<uintptr_t>(ctid));
766 }
767
768 // Finish publishing the child-side POSIX state before it can execute.
769 pedigree_copy_posix_thread(Processor::information().getCurrentThread(), pParentSubsystem, pThread,
770 pSubsystem);
771 const size_t childId = pProcess->getUserspaceId(pParentProcess->pidNamespace().get());
772 Uninterruptible parentEvents;
773 pProcess->publish();
774 if (!pThread->start()) {
775 FATAL("fork(): delayed child thread could not be started.");
776 }
777 if (vforkCompletion)
778 vforkCompletion->wait();
779
780 // Parent returns child ID.
781 SC_NOTICE(" -> " << childId << " [new process]");
782 return childId;
783}
784
785int posix_fork(SyscallState& state) {
786 SC_NOTICE("fork");
787
788 return posix_clone(state, 0, 0, 0, 0, 0);
789}
790
791int posix_vfork(SyscallState& state) {
792 return posix_clone(state, CLONE_VM | CLONE_VFORK | SIGCHLD, nullptr, nullptr, nullptr, 0, true);
793}
794
795int posix_execve(const char* name, const char** argv, const char** env, SyscallState& state) {
796 String nameCopy;
797 if (!copyUserString(name, nameCopy)) {
798 SC_NOTICE("execve -> invalid address");
799 return -1;
800 }
801
802 SC_NOTICE("execve(\"" << nameCopy << "\")");
803
804 Process* pProcess = Processor::information().getCurrentThread()->getParent();
805 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
806 if (!pSubsystem) {
807 ERROR("No subsystem for this process!");
808 return -1;
809 }
810
811 Vector<String> listArgv, listEnv;
812 {
814 size_t remaining = PosixSubsystem::MaximumExecArgumentBytes - 2 * sizeof(uintptr_t);
815 if (nameCopy.length() >= remaining) {
816 SYSCALL_ERROR(TooBig);
817 return -1;
818 }
819 remaining -= nameCopy.length() + 1;
820 auto snapshot = [&](const char** pointers, Vector<String>& output) {
821 uintptr_t cursor = reinterpret_cast<uintptr_t>(pointers);
822 while (cursor) {
823 const char* argument = nullptr;
824 if (!PosixSubsystem::copyFromUser(&argument, reinterpret_cast<void*>(cursor),
825 sizeof(argument))) {
826 SYSCALL_ERROR(BadAddress);
827 return false;
828 }
829 if (!argument) {
830 return true;
831 }
832 if (remaining <= sizeof(uintptr_t)) {
833 SYSCALL_ERROR(TooBig);
834 return false;
835 }
836 remaining -= sizeof(uintptr_t);
837 String value;
838 const auto result = PosixSubsystem::copyUserString(argument, value, remaining);
839 if (result != PosixSubsystem::UserStringSuccess) {
840 syscallError(result == PosixSubsystem::UserStringBadAddress ? Error::BadAddress
841 : Error::TooBig);
842 return false;
843 }
844 remaining -= value.length() + 1;
845 output.pushBack(value);
846 if (cursor > ~uintptr_t(0) - sizeof(uintptr_t)) {
847 SYSCALL_ERROR(BadAddress);
848 return false;
849 }
850 cursor += sizeof(uintptr_t);
851 }
852 return true;
853 };
854 if (!snapshot(argv, listArgv) || !snapshot(env, listEnv)) {
855 return -1;
856 }
857 }
858
859 // Normalise path to ensure we have the correct path to invoke.
860 String invokePath;
861 normalisePath(invokePath, nameCopy.cstr());
862
863 if (!pSubsystem->invoke(invokePath.cstr(), listArgv, listEnv, state)) {
864 SC_NOTICE(" -> execve failed in invoke");
865 return -1;
866 }
867
868 // Technically, we never get here.
869 return 0;
870}
871
872int posix_getpid() {
873 SC_NOTICE("getpid");
874
875 Process* pProcess = Processor::information().getCurrentThread()->getParent();
876 return pProcess->getUserspaceId();
877}
878
879int posix_getppid() {
880 SC_NOTICE("getppid");
881
882 Process* pProcess = Processor::information().getCurrentThread()->getParent();
883 while (true) {
884 Process* expectedParent = pProcess->getParent();
885 if (!expectedParent) {
886 return 0;
887 }
888
890 if (!Scheduler::instance().acquireProcess(parent, expectedParent)) {
891 if (pProcess->getParent() != expectedParent) {
892 continue;
893 }
894 return 0;
895 }
896 if (pProcess->getParent() == parent.get()) {
897 return parent->getUserspaceId(pProcess->pidNamespace().get());
898 }
899 }
900}
901
902int posix_gettimeofday(timeval* tv, struct timezone* tz) {
903 SC_NOTICE("gettimeofday");
904
905 const Time::Timestamp nanoseconds = Time::getTimeNanoseconds();
906 if (tv) {
907 struct timeval result = {};
908 result.tv_sec = nanoseconds / Time::Multiplier::Second;
909 result.tv_usec = (nanoseconds % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
910 if (!PosixSubsystem::copyToUser(tv, &result, sizeof(result))) {
911 SYSCALL_ERROR(BadAddress);
912 return -1;
913 }
914 }
915
916 if (tz) {
917 const struct timezone result = {};
918 if (!PosixSubsystem::copyToUser(tz, &result, sizeof(result))) {
919 SYSCALL_ERROR(BadAddress);
920 return -1;
921 }
922 }
923
924 return 0;
925}
926
927int posix_settimeofday(const timeval* tv, const struct timezone* tz) {
928 SC_NOTICE("settimeofday");
929 SYSCALL_ERROR(Unimplemented);
930 return -1;
931}
932
933time_t posix_time(time_t* tval) {
934 SC_NOTICE("time");
935
936 time_t result = Time::getTime();
937 if (tval && !PosixSubsystem::copyToUser(tval, &result, sizeof(result))) {
938 SYSCALL_ERROR(BadAddress);
939 return -1;
940 }
941
942 return result;
943}
944
945clock_t posix_times(struct tms* tm) {
946 SC_NOTICE("times");
947
948 Process* pProcess = Processor::information().getCurrentThread()->getParent();
949 constexpr Time::Timestamp nanosecondsPerClockTick = Time::Multiplier::Second / 100;
950
951 struct tms result = {};
952 result.tms_utime = pProcess->getUserTime() / nanosecondsPerClockTick;
953 result.tms_stime = pProcess->getKernelTime() / nanosecondsPerClockTick;
954 result.tms_cutime = pProcess->getReapedChildrenUserTime() / nanosecondsPerClockTick;
955 result.tms_cstime = pProcess->getReapedChildrenKernelTime() / nanosecondsPerClockTick;
956 if (tm && !PosixSubsystem::copyToUser(tm, &result, sizeof(result))) {
957 SC_NOTICE("posix_times -> invalid address");
958 SYSCALL_ERROR(BadAddress);
959 return -1;
960 }
961
962 SC_NOTICE("times: u=" << pProcess->getUserTime() << ", s=" << pProcess->getKernelTime());
963
964 return Time::getTicks() / nanosecondsPerClockTick;
965}
966
967int posix_getrusage(int who, struct rusage* r) {
968 SC_NOTICE("getrusage who=" << who);
969
970 if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && who != RUSAGE_THREAD) {
971 SC_NOTICE("posix_getrusage -> unsupported selector");
972 SYSCALL_ERROR(InvalidArgument);
973 return -1;
974 }
975
976 Thread* currentThread = Processor::information().getCurrentThread();
977 Process* pProcess = currentThread->getParent();
978 const Time::Timestamp user = who == RUSAGE_THREAD ? currentThread->getUserTime()
979 : who == RUSAGE_CHILDREN ? pProcess->getReapedChildrenUserTime()
980 : pProcess->getUserTime();
981 const Time::Timestamp kernel = who == RUSAGE_THREAD ? currentThread->getKernelTime()
982 : who == RUSAGE_CHILDREN ? pProcess->getReapedChildrenKernelTime()
983 : pProcess->getKernelTime();
984
985 struct rusage result = {};
986 result.ru_utime.tv_sec = user / Time::Multiplier::Second;
987 result.ru_utime.tv_usec = (user % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
988 result.ru_stime.tv_sec = kernel / Time::Multiplier::Second;
989 result.ru_stime.tv_usec = (kernel % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
990
991 if (!PosixSubsystem::copyToUser(r, &result, sizeof(result))) {
992 SC_NOTICE("posix_getrusage -> invalid address");
993 SYSCALL_ERROR(BadAddress);
994 return -1;
995 }
996
997 return 0;
998}
999
1000int posix_linux_getrusage(int who, LinuxRusage64* r) {
1001 SC_NOTICE("Linux getrusage who=" << who);
1002
1003 if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && who != RUSAGE_THREAD) {
1004 SC_NOTICE("posix_linux_getrusage -> unsupported selector");
1005 SYSCALL_ERROR(InvalidArgument);
1006 return -1;
1007 }
1008
1009 Thread* currentThread = Processor::information().getCurrentThread();
1010 Process* pProcess = currentThread->getParent();
1011 const Time::Timestamp user = who == RUSAGE_THREAD ? currentThread->getUserTime()
1012 : who == RUSAGE_CHILDREN ? pProcess->getReapedChildrenUserTime()
1013 : pProcess->getUserTime();
1014 const Time::Timestamp kernel = who == RUSAGE_THREAD ? currentThread->getKernelTime()
1015 : who == RUSAGE_CHILDREN ? pProcess->getReapedChildrenKernelTime()
1016 : pProcess->getKernelTime();
1017
1018 LinuxRusage64 result = {};
1019 result.userSeconds = user / Time::Multiplier::Second;
1020 result.userMicroseconds = (user % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
1021 result.systemSeconds = kernel / Time::Multiplier::Second;
1022 result.systemMicroseconds = (kernel % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
1023
1024 if (!PosixSubsystem::copyToUser(r, &result, sizeof(result))) {
1025 SC_NOTICE("posix_linux_getrusage -> invalid address");
1026 SYSCALL_ERROR(BadAddress);
1027 return -1;
1028 }
1029
1030 return 0;
1031}
1032
1033namespace {
1034int copyPasswd(User* user, passwd* output, char* userStrings) {
1035 if (!user) {
1036 return -1;
1037 }
1038 // The native glue supplies one 256-byte buffer for all passwd strings.
1039 char strings[256] = {};
1040 passwd result = {};
1041 size_t used = 0;
1042 const uintptr_t base = reinterpret_cast<uintptr_t>(userStrings);
1043 const String empty;
1044 const String* values[] = {&user->getUsername(), &empty, &user->getFullName(), &user->getHome(),
1045 &user->getShell()};
1046 char** fields[] = {&result.pw_name, &result.pw_passwd, &result.pw_gecos, &result.pw_dir,
1047 &result.pw_shell};
1048 for (size_t i = 0; i < 5; ++i) {
1049 const size_t length = values[i]->length();
1050 if (length >= sizeof(strings) - used) {
1051 SYSCALL_ERROR(BadRange);
1052 return -1;
1053 }
1054 *fields[i] = reinterpret_cast<char*>(base + used);
1055 MemoryCopy(strings + used, values[i]->cstr(), length + 1);
1056 used += length + 1;
1057 }
1058 result.pw_uid = user->getId();
1059 result.pw_gid = user->getDefaultGroup()->getId();
1060 if (!PosixSubsystem::copyToUser(userStrings, strings, used) ||
1061 !PosixSubsystem::copyToUser(output, &result, sizeof(result))) {
1062 SYSCALL_ERROR(BadAddress);
1063 return -1;
1064 }
1065 return 0;
1066}
1067
1068int copyGroup(Group* group, struct group* output) {
1069 if (!group) {
1070 return -1;
1071 }
1072 struct group result = {};
1073 if (!PosixSubsystem::copyFromUser(&result, output, sizeof(result))) {
1074 SYSCALL_ERROR(BadAddress);
1075 return -1;
1076 }
1077 // The native getgr* glue allocates 256 bytes for the caller-owned name.
1078 const String& name = group->getName();
1079 if (name.length() >= 256) {
1080 SYSCALL_ERROR(BadRange);
1081 return -1;
1082 }
1083 result.gr_gid = group->getId();
1084 if (!PosixSubsystem::copyToUser(result.gr_name, name.cstr(), name.length() + 1) ||
1085 !PosixSubsystem::copyToUser(output, &result, sizeof(result))) {
1086 SYSCALL_ERROR(BadAddress);
1087 return -1;
1088 }
1089 return 0;
1090}
1091} // namespace
1092
1093int posix_getpwent(passwd* pw, int n, char* str) {
1094 return copyPasswd(UserManager::instance().getUser(n), pw, str);
1095}
1096
1097int posix_getpwnam(passwd* pw, const char* name, char* str) {
1098 String nameCopy;
1099 if (!copyUserString(name, nameCopy)) {
1100 return -1;
1101 }
1102 return copyPasswd(UserManager::instance().getUser(nameCopy), pw, str);
1103}
1104
1105int posix_getgrnam(const char* name, struct group* out) {
1106 String nameCopy;
1107 if (!copyUserString(name, nameCopy)) {
1108 return -1;
1109 }
1110 return copyGroup(UserManager::instance().getGroup(nameCopy), out);
1111}
1112
1113int posix_getgrgid(gid_t id, struct group* out) {
1114 return copyGroup(UserManager::instance().getGroup(id), out);
1115}
1116
1117EXPORTED_PUBLIC int pedigree_login(int uid) {
1118 PosixProcess* process = getPosixProcess();
1119 if (!process) {
1120 SYSCALL_ERROR(NotEnoughPermissions);
1121 return -1;
1122 }
1124 if (!posix_global_capable(PosixCapabilities::Setuid)) {
1125 SYSCALL_ERROR(NotEnoughPermissions);
1126 return -1;
1127 }
1128 if (process->getNumThreads() != 1) {
1129 SYSCALL_ERROR(NoMoreProcesses);
1130 return -1;
1131 }
1132 User* user = uid < 0 ? nullptr : UserManager::instance().getUser(uid);
1133 if (!user) {
1134 SYSCALL_ERROR(InvalidArgument);
1135 return -1;
1136 }
1137 if (!user->login()) {
1138 SYSCALL_ERROR(InvalidArgument);
1139 return -1;
1140 }
1141 Processor::information().getCurrentThread()->setErrno(0);
1142 return 0;
1143}
1144
1145mode_t posix_umask(mode_t mask) {
1146 SC_NOTICE("umask(" << Oct << mask << ")");
1147
1148 // Not a POSIX process
1149 Process* pStockProcess = Processor::information().getCurrentThread()->getParent();
1150 if (pStockProcess->getType() != Process::Posix) {
1151 SC_NOTICE("umask -> called on something not a POSIX process");
1152 SYSCALL_ERROR(InvalidArgument);
1153 return -1;
1154 }
1155
1156 PosixProcess* pProcess = static_cast<PosixProcess*>(pStockProcess);
1157
1158 uint32_t previous = pProcess->getMask();
1159 pProcess->setMask(mask);
1160
1161 return previous;
1162}
1163
1164int posix_linux_syslog(int type, char* buf, int len) {
1165 switch (type) {
1166 case 0:
1167 case 1:
1168 return 0;
1169 case 3:
1170 break;
1171 case 10:
1172 return static_cast<int>(Log::textCapacity());
1173#if PEDIGREE_SYSCALL_COUNTER
1174 case 11: {
1175 if (len != static_cast<int>(sizeof(uint64_t))) {
1176 SYSCALL_ERROR(InvalidArgument);
1177 return -1;
1178 }
1179 Process* process = Processor::information().getCurrentThread()->getParent();
1180 const uint64_t count = process->getReapedChildrenSyscallCount();
1181 if (!PosixSubsystem::copyToUser(buf, &count, sizeof(count))) {
1182 SYSCALL_ERROR(BadAddress);
1183 return -1;
1184 }
1185 return static_cast<int>(sizeof(count));
1186 }
1187 case 12: {
1188 Process* process = Processor::information().getCurrentThread()->getParent();
1189 Process::SyscallLatencySnapshot snapshot = {};
1190 process->getReapedChildrenSyscallLatencySnapshot(snapshot);
1191 if (len != static_cast<int>(sizeof(snapshot))) {
1192 SYSCALL_ERROR(InvalidArgument);
1193 return -1;
1194 }
1195 if (!PosixSubsystem::copyToUser(buf, &snapshot, sizeof(snapshot))) {
1196 SYSCALL_ERROR(BadAddress);
1197 return -1;
1198 }
1199 return static_cast<int>(sizeof(snapshot));
1200 }
1201#endif
1202#if PEDIGREE_ACTIVITY_DIAGNOSTICS
1203 case 13: {
1204 if (len != static_cast<int>(sizeof(ActivityDiagnostics::Snapshot))) {
1205 SYSCALL_ERROR(InvalidArgument);
1206 return -1;
1207 }
1208 ActivityDiagnostics::Snapshot snapshot = {};
1209 ActivityDiagnostics::snapshot(snapshot);
1210 if (!PosixSubsystem::copyToUser(buf, &snapshot, sizeof(snapshot))) {
1211 SYSCALL_ERROR(BadAddress);
1212 return -1;
1213 }
1214 return static_cast<int>(sizeof(snapshot));
1215 }
1216#endif
1217#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
1218 case 15: {
1219 if (buf || (len != 0 && len != 1)) {
1220 SYSCALL_ERROR(InvalidArgument);
1221 return -1;
1222 }
1223 Process* process = Processor::information().getCurrentThread()->getParent();
1224 process->setBenchmarkSyscallTiming(len != 0);
1225 return 0;
1226 }
1227 case 16: {
1228 constexpr size_t snapshotSize =
1229 Process::SyscallTimingSlotCount * sizeof(Process::SyscallTimingEntry);
1230 if (len != static_cast<int>(snapshotSize)) {
1231 SYSCALL_ERROR(InvalidArgument);
1232 return -1;
1233 }
1234 Process* process = Processor::information().getCurrentThread()->getParent();
1235 for (size_t i = 0; i < Process::SyscallTimingSlotCount; ++i) {
1236 Process::SyscallTimingEntry entry = {};
1237 process->getSyscallTimingEntry(i, entry);
1238 if (!PosixSubsystem::copyToUser(buf + i * sizeof(entry), &entry, sizeof(entry))) {
1239 SYSCALL_ERROR(BadAddress);
1240 return -1;
1241 }
1242 }
1243 return static_cast<int>(snapshotSize);
1244 }
1245#endif
1246#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1247 case 17: {
1248 if (buf || (len != 0 && len != 1)) {
1249 SYSCALL_ERROR(InvalidArgument);
1250 return -1;
1251 }
1252 Process* process = Processor::information().getCurrentThread()->getParent();
1253 process->setBenchmarkVmDiagnostics(len != 0);
1254 return 0;
1255 }
1256 case 18: {
1257 constexpr size_t snapshotSize = Process::BenchmarkVmCounterCount * sizeof(uint64_t);
1258 if (len != static_cast<int>(snapshotSize)) {
1259 SYSCALL_ERROR(InvalidArgument);
1260 return -1;
1261 }
1262 Process* process = Processor::information().getCurrentThread()->getParent();
1263 for (size_t i = 0; i < Process::BenchmarkVmCounterCount; ++i) {
1264 const uint64_t value = process->getBenchmarkVmCounter(i);
1265 if (!PosixSubsystem::copyToUser(buf + i * sizeof(value), &value, sizeof(value))) {
1266 SYSCALL_ERROR(BadAddress);
1267 return -1;
1268 }
1269 }
1270 return static_cast<int>(snapshotSize);
1271 }
1272#endif
1273 case 20: {
1274#if PEDIGREE_BENCHMARK_SYSCALL_TRACE
1275 if (buf || (len != 0 && len != 1)) {
1276 SYSCALL_ERROR(InvalidArgument);
1277 return -1;
1278 }
1279 Process* process = Processor::information().getCurrentThread()->getParent();
1280 process->setBenchmarkSyscallTrace(len != 0);
1281 return 0;
1282#else
1283 SYSCALL_ERROR(Unimplemented);
1284 return -1;
1285#endif
1286 }
1287 case 2:
1288 case 4:
1289 case 5:
1290 case 6:
1291 case 7:
1292 case 8:
1293 case 9:
1294 SYSCALL_ERROR(Unimplemented);
1295 return -1;
1296 default:
1297 SYSCALL_ERROR(InvalidArgument);
1298 return -1;
1299 }
1300
1301 if (len < 0) {
1302 SYSCALL_ERROR(InvalidArgument);
1303 return -1;
1304 }
1305 if (!len)
1306 return 0;
1307 const size_t capacity = static_cast<size_t>(len) < Log::textCapacity() ? static_cast<size_t>(len)
1308 : Log::textCapacity();
1309 if (!PosixSubsystem::checkAddress(reinterpret_cast<uintptr_t>(buf), capacity,
1310 PosixSubsystem::SafeWrite)) {
1311 SYSCALL_ERROR(BadAddress);
1312 return -1;
1313 }
1314
1315 // User memory may fault: never copy to it while holding the log spinlock.
1316 TerminationDeferral lifetime;
1317 char* snapshot = new char[capacity];
1318 if (!snapshot) {
1319 SYSCALL_ERROR(OutOfMemory);
1320 return -1;
1321 }
1322 const size_t copied = Log::instance().copyText(snapshot, capacity);
1323 const bool valid = PosixSubsystem::copyToUser(buf, snapshot, copied);
1324 delete[] snapshot;
1325 if (!valid) {
1326 SYSCALL_ERROR(BadAddress);
1327 return -1;
1328 }
1329 return static_cast<int>(copied);
1330}
1331
1332int posix_syslog(const char* msg, int prio) {
1333 String msgCopy;
1334 if (!copyUserString(msg, msgCopy)) {
1335 SC_NOTICE("klog -> invalid address");
1336 return -1;
1337 }
1338
1339 uint64_t id = Processor::information().getCurrentThread()->getParent()->getId();
1340 if (id <= 1) {
1341 if (prio <= LOG_CRIT)
1342 FATAL("[" << Dec << id << Hex << "]\tklog: " << msgCopy);
1343 }
1344
1345 if (prio <= LOG_ERR)
1346 ERROR("[" << Dec << id << Hex << "]\tklog: " << msgCopy);
1347 else if (prio == LOG_WARNING)
1348 WARNING("[" << Dec << id << Hex << "]\tklog: " << msgCopy);
1349 else if (prio == LOG_NOTICE || prio == LOG_INFO)
1350 NOTICE("[" << Dec << id << Hex << "]\tklog: " << msgCopy);
1351#if DEBUGGER
1352 else
1353 NOTICE("[" << Dec << id << Hex << "]\tklog: " << msgCopy);
1354#endif
1355 return 0;
1356}
1357
1358int posix_reboot(uint32_t magic1, uint32_t magic2, uint32_t command) {
1359 if (!posix_global_capable(PosixCapabilities::SysBoot)) {
1360 SYSCALL_ERROR(NotEnoughPermissions);
1361 return -1;
1362 }
1363 if (magic1 != 0xfee1dead ||
1364 (magic2 != 672274793 && magic2 != 85072278 && magic2 != 369367448 && magic2 != 537993216)) {
1365 SYSCALL_ERROR(InvalidArgument);
1366 return -1;
1367 }
1368
1369 Machine::ShutdownType type;
1370 switch (command) {
1371 case 0x00000000: // CAD_OFF
1372 case 0x89abcdef: // CAD_ON
1373 // There is no kernel Ctrl-Alt-Del policy to change.
1374 return 0;
1375 case 0x01234567:
1376 type = Machine::ShutdownType::Restart;
1377 break;
1378 case 0xcdef0123:
1379 type = Machine::ShutdownType::Halt;
1380 break;
1381 case 0x4321fedc:
1382 type = Machine::ShutdownType::PowerOff;
1383 break;
1384 default:
1385 // RESTART2, suspend and kexec require contracts we do not implement.
1386 SYSCALL_ERROR(InvalidArgument);
1387 return -1;
1388 }
1389
1390 // Catch known writeback failures before committing to terminal teardown.
1391 // Module shutdown closes writers and performs the final cache drains.
1392 Machine::instance().displayShutdownMessage("Shutdown requested...\nSynchronizing filesystems");
1393 const auto status = VFS::instance().syncAll();
1394 if (status == Filesystem::SyncStatus::IoError || status == Filesystem::SyncStatus::NoMemory) {
1395 Machine::instance().displayShutdownMessage(
1396 "Shutdown failed: filesystem synchronization failed");
1397 syscallError(status == Filesystem::SyncStatus::IoError ? Error::IoError : Error::OutOfMemory);
1398 return -1;
1399 }
1400 if (!SyscallManager::instance().requestReboot(type)) {
1401 SYSCALL_ERROR(DeviceBusy);
1402 return -1;
1403 }
1404 return 0;
1405}
1406
1407EXPORTED_PUBLIC int pedigree_reboot() {
1408 return posix_reboot(0xfee1dead, 672274793, 0x01234567);
1409}
1410
1411int posix_prctl(int option, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
1412 NOTICE("prctl(" << Hex << option << ", " << arg2 << ", " << arg3 << ", " << arg4 << ", " << arg5
1413 << ")");
1414
1415 Thread* thread = Processor::information().getCurrentThread();
1416 if (option == 38 || option == 39) { // PR_SET_NO_NEW_PRIVS / PR_GET_NO_NEW_PRIVS
1417 if (arg3 || arg4 || arg5 || (option == 38 ? arg2 != 1 : arg2 != 0)) {
1418 SYSCALL_ERROR(InvalidArgument);
1419 return -1;
1420 }
1421 if (option == 38) {
1422 return posix_set_no_new_privs();
1423 }
1424 thread->setErrno(0);
1425 return posix_no_new_privs() ? 1 : 0;
1426 }
1427 if (option == 7 || option == 8 || option == 23 || option == 24 || option == 27 || option == 28 ||
1428 option == 47) {
1429 return posix_capability_prctl(option, arg2, arg3, arg4, arg5);
1430 }
1431 if (option == 21) { // PR_GET_SECCOMP
1432 return posix_seccomp_mode();
1433 }
1434 if (option == 22) { // PR_SET_SECCOMP
1435 if (arg2 != 2) {
1436 SYSCALL_ERROR(InvalidArgument);
1437 return -1;
1438 }
1439 return posix_seccomp(1, 0, reinterpret_cast<const void*>(arg3));
1440 }
1441 if (option == 1 || option == 2) { // PR_SET_PDEATHSIG / PR_GET_PDEATHSIG
1442 auto* subsystem = static_cast<PosixSubsystem*>(thread->getParent()->getSubsystem());
1443 if (!subsystem) {
1444 SYSCALL_ERROR(NoSuchProcess);
1445 return -1;
1446 }
1447 if (option == 1) {
1448 if (arg2 >= PosixSubsystem::SignalDispositionCount) {
1449 SYSCALL_ERROR(InvalidArgument);
1450 return -1;
1451 }
1452 if (!subsystem->traceContext().setParentDeathSignal(*thread, static_cast<int>(arg2))) {
1453 SYSCALL_ERROR(NoSuchProcess);
1454 return -1;
1455 }
1456 } else {
1457 TraceTaskRef task;
1458 if (!subsystem->traceContext().taskToken(*thread, task)) {
1459 SYSCALL_ERROR(NoSuchProcess);
1460 return -1;
1461 }
1462 const int signal = task->parentDeathSignal();
1463 if (!PosixSubsystem::copyToUser(reinterpret_cast<void*>(arg2), &signal, sizeof(signal))) {
1464 SYSCALL_ERROR(BadAddress);
1465 return -1;
1466 }
1467 }
1468 thread->setErrno(0);
1469 return 0;
1470 }
1471 if (option == 3 || option == 4) {
1472 PosixProcess* process = getPosixProcess();
1473 if (!process) {
1474 SYSCALL_ERROR(InvalidArgument);
1475 return -1;
1476 }
1477 if (option == 3) {
1478 thread->setErrno(0);
1479 return process->snapshotCredentials().dumpable ? 1 : 0;
1480 }
1481 if (arg2 > 1) {
1482 SYSCALL_ERROR(InvalidArgument);
1483 return -1;
1484 }
1485 process->setDumpable(arg2 != 0);
1486 thread->setErrno(0);
1487 return 0;
1488 }
1489
1490 if (option == LINUX_PR_SET_NAME) {
1491 String requested;
1492 const PosixSubsystem::UserStringResult result = PosixSubsystem::copyUserString(
1493 reinterpret_cast<const char*>(arg2), requested, LINUX_TASK_NAME_LENGTH);
1494 if (result == PosixSubsystem::UserStringBadAddress) {
1495 SYSCALL_ERROR(BadAddress);
1496 return -1;
1497 }
1498
1499 // Linux task names are a 16-byte field including the terminator. Direct
1500 // prctl callers are truncated; pthread_setname_np applies its own ERANGE.
1501 const size_t length = requested.length() < (LINUX_TASK_NAME_LENGTH - 1)
1502 ? requested.length()
1503 : (LINUX_TASK_NAME_LENGTH - 1);
1504 thread->setName(String(requested.cstr(), length, true));
1505 return 0;
1506 }
1507
1508 if (option == LINUX_PR_GET_NAME) {
1509 char name[LINUX_TASK_NAME_LENGTH] = {};
1510 const String& current = thread->getName();
1511 const size_t length = current.length() < (LINUX_TASK_NAME_LENGTH - 1)
1512 ? current.length()
1513 : (LINUX_TASK_NAME_LENGTH - 1);
1514 MemoryCopy(name, current.cstr(), length);
1515 if (!PosixSubsystem::copyToUser(reinterpret_cast<void*>(arg2), name, sizeof(name))) {
1516 SYSCALL_ERROR(BadAddress);
1517 return -1;
1518 }
1519 return 0;
1520 }
1521
1522 SYSCALL_ERROR(InvalidArgument);
1523 return -1;
1524}
1525
1526int posix_arch_prctl(int code, unsigned long addr) {
1527 Thread* current = Processor::information().getCurrentThread();
1528 switch (code) {
1529#if X64 && !HOSTED
1530 case ARCH_SET_GS:
1531 // Paranoid entry distinguishes kernel and user GS by the address half.
1532 // FSGSBASE stays disabled, so userspace cannot bypass this restriction.
1533 if (addr >= current->getParent()->getAddressSpace()->getKernelStart() ||
1534 addr >= 0x0000800000000000ULL) {
1535 SYSCALL_ERROR(NotEnoughPermissions);
1536 return -1;
1537 }
1538 current->setUserGsBase(addr);
1539 break;
1540
1541 case ARCH_GET_GS: {
1542 const unsigned long base = Processor::getUserGsBase();
1543 if (!PosixSubsystem::copyToUser(reinterpret_cast<void*>(addr), &base, sizeof(base))) {
1544 SYSCALL_ERROR(BadAddress);
1545 return -1;
1546 }
1547 break;
1548 }
1549#endif
1550 case ARCH_SET_FS:
1551 if (addr >= current->getParent()->getAddressSpace()->getKernelStart()
1552#if X64
1553 || addr >= 0x0000800000000000ULL
1554#endif
1555 ) {
1556 SYSCALL_ERROR(NotEnoughPermissions);
1557 return -1;
1558 }
1559 current->setTlsBase(addr);
1560 break;
1561
1562 case ARCH_GET_FS: {
1563 const unsigned long base = current->getTlsBase();
1564 if (!PosixSubsystem::copyToUser(reinterpret_cast<void*>(addr), &base, sizeof(base))) {
1565 SYSCALL_ERROR(BadAddress);
1566 return -1;
1567 }
1568 break;
1569 }
1570
1571 default:
1572 SYSCALL_ERROR(InvalidArgument);
1573 return -1;
1574 }
1575 return 0;
1576}
1577
1578int posix_pause() {
1579 SC_NOTICE("pause");
1580
1581 Processor::information().getCurrentThread()->waitForEvent();
1582
1583 SYSCALL_ERROR(Interrupted);
1584 return -1;
1585}
1586
1587int posix_membarrier(int command, unsigned int flags, int cpuId) {
1588 SC_NOTICE("membarrier(" << Dec << command << ", " << flags << ", " << cpuId << ")");
1589
1590 // A zero query result truthfully advertises that no membarrier commands are
1591 // available. Callers can then select their ordinary synchronization path.
1592 if (command == 0 && flags == 0) {
1593 return 0;
1594 }
1595
1596 SYSCALL_ERROR(InvalidArgument);
1597 return -1;
1598}
1599
1600int posix_getpriority(int which, int who, bool linuxAbi) {
1601 SC_NOTICE("getpriority(" << which << ", " << Dec << who << ")");
1602 if (which != PRIO_PROCESS && which != PRIO_PGRP && which != PRIO_USER) {
1603 SYSCALL_ERROR(InvalidArgument);
1604 return -1;
1605 }
1606 if (who < 0) {
1607 SYSCALL_ERROR(NoSuchProcess);
1608 return -1;
1609 }
1610
1611 PosixProcess* caller = getPosixProcess();
1612 if (!caller) {
1613 SYSCALL_ERROR(NoSuchProcess);
1614 return -1;
1615 }
1616
1617 // POSIX nice values are not mutable yet. Linux returns 20 minus nice,
1618 // while the native POSIX service exposes the public value directly.
1619 const int priority = linuxAbi ? 20 : 0;
1620 if (which == PRIO_PROCESS) {
1621 if (!who || static_cast<size_t>(who) == caller->getUserspaceId()) {
1622 return priority;
1623 }
1624 Scheduler::ProcessLease candidate;
1625 if (Scheduler::instance().acquireProcessByUserspaceId(candidate, static_cast<size_t>(who)) &&
1626 candidate->getType() == Process::Posix && candidate->getState() != Process::Reaped) {
1627 return priority;
1628 }
1629 SYSCALL_ERROR(NoSuchProcess);
1630 return -1;
1631 }
1632
1633 if (which == PRIO_USER) {
1634 if (!who || static_cast<int64_t>(who) == caller->getUserId()) {
1635 return priority;
1636 }
1637 // The scheduler has no stable process snapshot for another user's set.
1638 // Index-based scans can miss a live match when an earlier process exits.
1639 SYSCALL_ERROR(Unimplemented);
1640 return -1;
1641 }
1642
1643 size_t callerGroup = 0;
1644 const bool hasCallerGroup = caller->getProcessGroupId(callerGroup);
1645 if (hasCallerGroup && (!who || static_cast<size_t>(who) == callerGroup)) {
1646 return priority;
1647 }
1648 if (who) {
1649 SYSCALL_ERROR(Unimplemented);
1650 return -1;
1651 }
1652
1653 SYSCALL_ERROR(NoSuchProcess);
1654 return -1;
1655}
1656
1657int posix_setpriority(int which, int who, int prio) {
1659 SC_NOTICE("setpriority(" << which << ", " << Dec << who << ", " << prio << ")");
1660 return 0;
1661}
1662
1663int posix_get_robust_list(int pid, struct robust_list_head** head_ptr, size_t* len_ptr,
1664 bool linuxAbi) {
1665 SC_NOTICE("get_robust_list");
1666 Thread* current = Processor::information().getCurrentThread();
1667 Thread* target = current;
1668 Process::ThreadLease targetLease;
1669 const size_t currentId = linuxAbi ? current->getUserspaceTaskId() : current->getId();
1670 if (pid < 0 || (pid && static_cast<size_t>(pid) != currentId &&
1671 !(linuxAbi ? Scheduler::instance().acquireThreadByUserspaceId(targetLease, pid)
1672 : current->getParent()->acquireThreadById(targetLease, pid)))) {
1673 SYSCALL_ERROR(NoSuchProcess);
1674 return -1;
1675 }
1676 if (targetLease) {
1677 target = targetLease.get();
1678 }
1679 if (target->getParent() != current->getParent()) {
1680 // Cross-process inspection needs a ptrace access policy which the
1681 // subsystem does not yet implement.
1682 SYSCALL_ERROR(NotEnoughPermissions);
1683 return -1;
1684 }
1685
1686 auto* head = reinterpret_cast<struct robust_list_head*>(target->getRobustList());
1687 const size_t length = 3 * sizeof(uintptr_t);
1688 if (!PosixSubsystem::copyToUser(head_ptr, &head, sizeof(head)) ||
1689 !PosixSubsystem::copyToUser(len_ptr, &length, sizeof(length))) {
1690 SYSCALL_ERROR(BadAddress);
1691 return -1;
1692 }
1693 return 0;
1694}
1695
1696int posix_set_robust_list(struct robust_list_head* head, size_t len, bool linuxAbi) {
1697 SC_NOTICE("set_robust_list");
1698
1699 if (len != 3 * sizeof(uintptr_t)) {
1700 SYSCALL_ERROR(InvalidArgument);
1701 return -1;
1702 }
1703
1704 // The list is mutable userspace state. Linux registers its address without
1705 // touching it; exit processing must bound and validate each later access.
1706 Thread* current = Processor::information().getCurrentThread();
1707 current->setRobustList(reinterpret_cast<uintptr_t>(head),
1708 linuxAbi ? current->getUserspaceTaskId() : current->getId());
1709
1710 return 0;
1711}
1712
1713int posix_ioperm(unsigned long from, unsigned long num, int turn_on) {
1714 SC_NOTICE("ioperm(" << from << ", " << num << ", " << turn_on << ")");
1715
1718 return 0;
1719}
1720
1721int posix_iopl(int level) {
1722 SC_NOTICE("iopl(" << level << ")");
1723 return 0;
1724}
1725
1726#undef SC_NOTICE
1727#define SC_NOTICE(x)
1728
1729namespace {
1730constexpr Time::Timestamp MaximumLinuxTimerNanoseconds = 0x7FFFFFFFFFFFFFFFULL;
1731
1732IntervalTimer* selectIntervalTimer(PosixProcess* process, int which) {
1733 switch (which) {
1734 case ITIMER_REAL:
1735 return &process->getRealIntervalTimer();
1736 case ITIMER_VIRTUAL:
1737 return &process->getVirtualIntervalTimer();
1738 case ITIMER_PROF:
1739 return &process->getProfileIntervalTimer();
1740 default:
1741 return nullptr;
1742 }
1743}
1744
1745bool validIntervalTimeval(const struct timeval& value) {
1746 return value.tv_sec >= 0 && value.tv_usec >= 0 && value.tv_usec < 1000000;
1747}
1748
1749Time::Timestamp intervalTimevalToNanoseconds(const struct timeval& value) {
1750 const Time::Timestamp microseconds =
1751 static_cast<Time::Timestamp>(value.tv_usec) * Time::Multiplier::Microsecond;
1752 const Time::Timestamp seconds = static_cast<Time::Timestamp>(value.tv_sec);
1753 if (seconds >= MaximumLinuxTimerNanoseconds / Time::Multiplier::Second) {
1754 return MaximumLinuxTimerNanoseconds;
1755 }
1756 return seconds * Time::Multiplier::Second + microseconds;
1757}
1758
1759struct itimerval intervalTimerToUser(Time::Timestamp interval, Time::Timestamp value) {
1760 struct itimerval result = {};
1761 result.it_interval.tv_sec = interval / Time::Multiplier::Second;
1762 result.it_interval.tv_usec =
1763 (interval % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
1764 result.it_value.tv_sec = value / Time::Multiplier::Second;
1765 result.it_value.tv_usec = (value % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
1766 return result;
1767}
1768} // namespace
1769
1770int posix_getitimer(int which, struct itimerval* curr_value) {
1771 SC_NOTICE("posix_getitimer(" << which << ", " << curr_value << ")");
1772
1773 Thread* currentThread = Processor::information().getCurrentThread();
1774 PosixProcess* pProcess = static_cast<PosixProcess*>(currentThread->getParent());
1775
1776 Time::Timestamp interval = 0;
1777 Time::Timestamp value = 0;
1778
1779 IntervalTimer* itimer = selectIntervalTimer(pProcess, which);
1780 if (!itimer) {
1781 SYSCALL_ERROR(InvalidArgument);
1782 return -1;
1783 }
1784
1785 if (which != ITIMER_REAL) {
1786 currentThread->trackTime(CpuTimeMode::Kernel);
1787 }
1788 itimer->getIntervalAndValue(interval, value);
1789
1790 const struct itimerval result = intervalTimerToUser(interval, value);
1791 if (!PosixSubsystem::copyToUser(curr_value, &result, sizeof(result))) {
1792 SYSCALL_ERROR(BadAddress);
1793 return -1;
1794 }
1795
1796 SC_NOTICE(" -> period = " << Dec << result.it_interval.tv_sec << "s "
1797 << result.it_interval.tv_usec << "us");
1798 SC_NOTICE(" -> value = " << Dec << result.it_value.tv_sec << "s " << result.it_value.tv_usec
1799 << "us");
1800
1801 return 0;
1802}
1803
1804int posix_setitimer(int which, const struct itimerval* new_value, struct itimerval* old_value) {
1805 SC_NOTICE("posix_setitimer(" << which << ", " << new_value << ", " << old_value << ")");
1806
1807 struct itimerval requested = {};
1808 if (new_value && !PosixSubsystem::copyFromUser(&requested, new_value, sizeof(requested))) {
1809 SYSCALL_ERROR(BadAddress);
1810 return -1;
1811 }
1812 if (!validIntervalTimeval(requested.it_interval) || !validIntervalTimeval(requested.it_value)) {
1813 SYSCALL_ERROR(InvalidArgument);
1814 return -1;
1815 }
1816
1817 SC_NOTICE(" -> period = " << Dec << requested.it_interval.tv_sec << "s "
1818 << requested.it_interval.tv_usec << "us");
1819 SC_NOTICE(" -> value = " << Dec << requested.it_value.tv_sec << "s " << requested.it_value.tv_usec
1820 << "us");
1821
1822 Thread* currentThread = Processor::information().getCurrentThread();
1823 PosixProcess* pProcess = static_cast<PosixProcess*>(currentThread->getParent());
1824
1825 const Time::Timestamp interval = intervalTimevalToNanoseconds(requested.it_interval);
1826 const Time::Timestamp value = intervalTimevalToNanoseconds(requested.it_value);
1827 Time::Timestamp prevInterval = 0;
1828 Time::Timestamp prevValue = 0;
1829
1830 IntervalTimer* itimer = selectIntervalTimer(pProcess, which);
1831 if (!itimer) {
1832 SYSCALL_ERROR(InvalidArgument);
1833 return -1;
1834 }
1835
1836 if (which != ITIMER_REAL) {
1837 currentThread->trackTime(CpuTimeMode::Kernel);
1838 }
1839 itimer->setIntervalAndValue(interval, value, &prevInterval, &prevValue);
1840
1841 if (old_value) {
1842 const struct itimerval previous = intervalTimerToUser(prevInterval, prevValue);
1843 if (!PosixSubsystem::copyToUser(old_value, &previous, sizeof(previous))) {
1844 SYSCALL_ERROR(BadAddress);
1845 return -1;
1846 }
1847 }
1848
1849 return 0;
1850}
Memory-mapped file interface.
Definition Group.h:32
const String & getName() const
Definition Group.h:54
size_t getId() const
Definition Group.h:50
void setIntervalAndValue(Time::Timestamp interval, Time::Timestamp value, Time::Timestamp *prevInterval=nullptr, Time::Timestamp *prevValue=nullptr)
Set both interval and value atomically.
the kernel's log
Definition Log.h:155
static EXPORTED_PUBLIC Log & instance()
Definition Log.cc:117
EXPORTED_PUBLIC size_t copyText(char *buffer, size_t capacity)
Definition Log.cc:454
void displayShutdownMessage(const char *message)
Definition Machine.cc:100
static MemoryMapManager & instance()
int64_t getUserId() const final
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
bool copyDescriptors(PosixSubsystem *pSubsystem)
static UserStringResult copyUserString(const char *userString, String &copy, size_t maxLength)
void setProcess(Process *process) override
virtual bool invoke(const char *name, Vector< String > &argv, Vector< String > &env)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
size_t getUserspaceId() const
Definition Process.h:504
@ Reaped
Terminal wait status is visible; the owner may still be on-stack.
Definition Process.h:308
MUST_USE_RESULT bool installFilesystemContext(FilesystemContextOwner &&context)
Definition Process.cc:734
Process * getParent()
Definition Process.h:620
VirtualAddressSpace * getAddressSpace()
Definition Process.h:530
size_t getNumThreads()
Definition Process.cc:1380
Time::Timestamp getUserTime() const
Definition Process.h:829
static ProcessorInformation & information()
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static void setInterrupts(bool bEnable)
static Scheduler & instance()
Definition Scheduler.h:96
static SharedPointer< T > tryAdopt(T *ptr)
static SharedPointer< T > tryAllocate(Args...)
T * get() const
static EXPORTED_PUBLIC SyscallManager & instance()
void setErrno(size_t err)
Definition Thread.h:482
void setTlsBase(uintptr_t base)
Definition Thread.cc:2722
void setUnwindState(UnwindType ut)
Definition Thread.cc:3580
@ TerminateThread
Exit only this thread during Process exit.
Definition Thread.h:519
Time::Timestamp getUserTime() const
Definition Thread.h:412
UnwindType getUnwindState()
Definition Thread.h:535
bool detach()
Definition Thread.cc:2987
void setClearChildTid(uintptr_t address)
Definition Thread.cc:653
void trackTime(CpuTimeMode mode)
Definition Thread.cc:392
bool startDetached()
Definition Thread.cc:769
Process * getParent() const
Definition Thread.h:340
size_t getId()
Definition Thread.h:465
size_t getUserspaceTaskId(const UserspacePidNamespace *space=nullptr) const
Definition Thread.cc:3743
bool start()
Definition Thread.cc:751
uintptr_t getTlsBase()
Definition Thread.cc:2644
User * getUser(size_t id)
static UserManager & instance()
Definition UserManager.h:32
Definition User.h:32
size_t getId() const
Definition User.h:60
const String & getFullName() const
Definition User.h:68
const String & getUsername() const
Definition User.h:64
bool login()
Definition User.cc:65
Group * getDefaultGroup()
Definition User.h:72
const String & getHome() const
Definition User.h:76
const String & getShell() const
Definition User.h:80
Filesystem::SyncStatus syncAll()
Definition VFS.cc:939
static VFS & instance()
Definition VFS.cc:311
A vector / dynamic array.
Definition Vector.h:33
virtual uintptr_t getKernelStart() const =0
@ Oct
Definition Log.h:128
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124