The Pedigree Project 0.1
PosixSubsystem.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/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/linker/Elf.h"
23#include "pedigree/kernel/process/PerProcessorScheduler.h"
24#include "pedigree/kernel/process/Scheduler.h"
25#include "pedigree/kernel/process/SignalEvent.h"
26#include "pedigree/kernel/process/TerminationDeferral.h"
27#include "pedigree/kernel/process/Thread.h"
28#include "pedigree/kernel/process/Uninterruptible.h"
29#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
30#include "pedigree/kernel/processor/Processor.h"
31#include "pedigree/kernel/processor/SyscallManager.h"
32#include "pedigree/kernel/processor/state.h"
33#include "pedigree/kernel/processor/types.h"
34#include "pedigree/kernel/syscallError.h"
35#include "pedigree/kernel/utilities/Pointers.h"
37#include "pedigree/kernel/utilities/String.h"
38#include "pedigree/kernel/utilities/Tree.h"
39#include "pedigree/kernel/utilities/assert.h"
40#include "pedigree/kernel/utilities/lib.h"
41
42#include <PosixSubsystem.h>
43#include <signal.h>
44#if !ARM64 && !ARMV7
45#include <vdso.h> // Header with the vdso.so binary in it.
46#endif
47
48#include "FileDescriptor.h"
49#include "PosixProcess.h"
50#include "ProcFs.h"
51#include "eventfd-syscalls.h"
52#include "file-syscalls.h"
53#include "landlock.h"
54#include "linux-amd64-signal.h"
55#include "logging.h"
56#include "modules/system/linker/DynamicLinker.h"
57#include "modules/system/vfs/File.h"
59#include "modules/system/vfs/MountView.h"
60#include "modules/system/vfs/Symlink.h"
61#include "modules/system/vfs/VFS.h"
62#include "mqueue-syscalls.h"
63#include "posix-timer-syscalls.h"
64#include "pthread-syscalls.h"
65#include "queued-signal.h"
66#include "sandbox-state.h"
67#include "signal-syscalls.h"
68#include "signalfd-syscalls.h"
69#include "system-syscalls.h"
70#include "sysv-semaphore-syscalls.h"
71#include "timerfd-syscalls.h"
72#include "user-namespace.h"
73
74#if X64 && !HOSTED
75extern char __posix_compat_vsyscall_base;
76#define POSIX_VSYSCALL_ADDRESS 0xffffffffff600000
77#endif
78
79#define O_RDONLY 0
80#define O_WRONLY 1
81#define O_RDWR 2
82
83#define FD_CLOEXEC 1
84
87
89 FdEntry(size_t number, const SharedPointer<FileDescriptor>& owner)
90 : fd(number), descriptor(owner) {}
91
92 const size_t fd;
93 const SharedPointer<FileDescriptor> descriptor;
95};
96
97ProcessGroupManager ProcessGroupManager::m_Instance;
98
99extern void pedigree_init_sigret();
100extern void pedigree_init_pthreads();
101
104 if (file)
105 file->releaseMappingUse(true, false);
106 }
107 FilesystemPathRef openingPath;
108 File* file = nullptr;
109 size_t fileSize = 0;
110 Elf::ExecutableMetadata metadata{};
111 UniqueArray<uint8_t> programHeaders;
112 uintptr_t programHeaderAddress = 0;
113 String interpreter;
114};
115
116namespace {
117bool validUserAddressRange(uintptr_t address, size_t extent) {
118 if (extent - 1 > (~static_cast<uintptr_t>(0) - address)) {
119 return false;
120 }
121 const uintptr_t end = address + extent - 1;
122 VirtualAddressSpace& va = Processor::information().getVirtualAddressSpace();
123 return address >= va.getUserStart() && address < va.getKernelStart() &&
124 end < va.getKernelStart() && va.isAddressValid(reinterpret_cast<void*>(address)) &&
125 va.isAddressValid(reinterpret_cast<void*>(end));
126}
127
128bool prepareUserCopy(uintptr_t address, size_t extent, bool write) {
129#if POSIX_NO_EFAULT
130 return true;
131#else
132 // faultInRange performs the permission checks while it makes demand-paged
133 // pages resident, so a separate complete-range mapping scan is redundant.
134 if (!validUserAddressRange(address, extent)) {
135 return false;
136 }
137 return MemoryMapManager::instance().faultInRange(address, extent, write);
138#endif
139}
140
141void ignoredSignal(int) {}
142
143bool defaultSignalActionIsIgnore(size_t signal) {
144 return signal == SIGCHLD || signal == SIGURG || signal == SIGWINCH;
145}
146
147bool defaultSignalActionIsStop(size_t signal) {
148 return signal == SIGSTOP || signal == SIGTSTP || signal == SIGTTIN || signal == SIGTTOU;
149}
150
151void stampStopDelivery(Process* process, size_t signal, SignalEvent* delivery) {
152 if (process && delivery && defaultSignalActionIsStop(signal)) {
153 delivery->setContinuationEpoch(process->getContinuationEpoch());
154 }
155}
156
157bool rebindQueuedSignalEvents(Thread& thread, size_t signal, SignalEvent& prototype) {
158 static uint64_t nextGeneration = 0;
159 const uint64_t generation = __atomic_add_fetch(&nextGeneration, 1, __ATOMIC_RELAXED);
160 // Mark replacements so every queued RT instance is rebound exactly once,
161 // including when asynchronous consumers remove entries during this pass.
162 while (true) {
163 SignalEvent* pending = static_cast<SignalEvent*>(prototype.cloneForDelivery());
164 if (!thread.replaceSignalEvent(signal, pending, -1, generation)) {
165 delete pending;
166 return true;
167 }
168 }
169}
170
171void setExecutableValidationError(Elf::ExecutableValidationResult result, bool isInterpreter) {
172 if (isInterpreter) {
173 SYSCALL_ERROR(BadSharedLibrary);
174 } else if (result == Elf::ExecutableValidationResult::MultipleInterpreters) {
175 SYSCALL_ERROR(InvalidArgument);
176 } else {
177 SYSCALL_ERROR(ExecFormatError);
178 }
179}
180} // namespace
181
182ProcessGroupManager::ProcessGroupManager() : m_GroupIds(), m_Groups(nullptr), m_GroupLock(false) {
183 m_GroupIds.set(0);
184}
185
186ProcessGroupManager::~ProcessGroupManager() {}
187
189 RecursingLockGuard<Spinlock> guard(m_GroupLock);
190 size_t bit = m_GroupIds.getFirstClear();
191 while (findGroup(bit) || m_GroupIds.test(bit))
192 ++bit;
193 m_GroupIds.set(bit);
194 return bit;
195}
196
198 RecursingLockGuard<Spinlock> guard(m_GroupLock);
199 if (m_GroupIds.test(gid)) {
200 PS_NOTICE(
201 "ProcessGroupManager: setGroupId called on a group ID that "
202 "existed already!");
203 }
204 m_GroupIds.set(gid);
205}
206
208 RecursingLockGuard<Spinlock> guard(m_GroupLock);
209 return findGroup(gid) || m_GroupIds.test(gid);
210}
211
213 RecursingLockGuard<Spinlock> guard(m_GroupLock);
214 m_GroupIds.clear(gid);
215}
216
218 RecursingLockGuard<Spinlock> guard(m_GroupLock);
219 assert(!findGroup(gid));
220 group->registryNext = m_Groups;
221 m_Groups = group;
222 group->registered = true;
223}
224
225void ProcessGroupManager::unregisterGroup(size_t gid, ProcessGroup* group) {
226 RecursingLockGuard<Spinlock> guard(m_GroupLock);
227 ProcessGroup** link = &m_Groups;
228 while (*link && *link != group)
229 link = &(*link)->registryNext;
230 if (*link) {
231 *link = group->registryNext;
232 group->registryNext = nullptr;
233 group->registered = false;
234 }
235}
236
238 for (ProcessGroup* group = m_Groups; group; group = group->registryNext)
239 if (static_cast<size_t>(group->processGroupId) == gid)
240 return group;
241 return nullptr;
242}
243
245 if (!gid) {
246 return nullptr;
247 }
248 for (ProcessGroup* group = m_Groups; group; group = group->registryNext) {
249 if (group->identity && group->identity->id(space) == gid) {
250 return group;
251 }
252 }
253 return nullptr;
254}
255
257 : Subsystem(s),
258 m_SignalHandlers(),
260 m_CallbackSchedulingDomain(s.m_CallbackSchedulingDomain),
261 m_AdvisoryOwner(AdvisoryOwner::Kind::Process),
262 m_MemoryLockAccount(s.m_MemoryLockAccount),
263 m_FdMap(),
264 m_FdEntries(),
266 m_FdLock(),
267 m_FdBitmap(),
268 m_LastFd(0),
271 m_Threads(),
273 m_NextThreadWaiter(1),
274 m_ImageMetadataLock(),
275 m_ExecutablePath(),
276 m_CommandLine(),
277 m_Abi(s.m_Abi),
278 m_bAcquired(false),
279 m_pAcquiredThread(nullptr) {
280 {
281 LockGuard<Mutex> image(s.m_ImageMetadataLock);
282 m_ExecutablePath = s.m_ExecutablePath;
283 m_CommandLine = s.m_CommandLine;
284 }
287
288 // Tree iterators store their cursor in the tree, so iterate a shallow copy.
289 sigHandlerTree signalHandlers(s.m_SignalHandlers);
290
291 // Copy all signal handlers
292 for (sigHandlerTree::Iterator it = signalHandlers.begin(); it != signalHandlers.end(); it++) {
293 size_t key = it.key();
294 void* value = it.value();
295 if (!value)
296 continue;
297
298 auto* original = reinterpret_cast<SignalHandler*>(value);
299 SignalHandler* newSig;
300 if (clearSignalHandlers && original->type != 2) {
301 newSig = new SignalHandler();
302 newSig->sig = key;
303 newSig->type = 1;
304 newSig->pEvent = new SignalEvent(pedigree_default_signal_handler(key), key, ~0UL, 0, true,
305 false, Event::HandlerPrivilege::Kernel,
306 SignalEvent::DeliveryDisposition::DefaultAction);
307 } else {
308 newSig = new SignalHandler(*original);
309 }
310 m_SignalHandlers.insert(key, newSig);
311 }
312
315
316 // Copy across waiter state.
318 for (Tree<void*, Semaphore*>::Iterator it = threadWaiters.begin(); it != threadWaiters.end();
319 ++it) {
320 void* key = it.key();
321
322 Semaphore* sem = new Semaphore(0);
323 m_ThreadWaiters.insert(key, sem);
324 }
325
326 m_NextThreadWaiter = s.m_NextThreadWaiter;
327}
328
330 Subsystem::setProcess(process);
331 if (process)
332 m_TraceContext.attach(*process);
333 m_PendingSignals->attach(m_pProcess);
334 if (process && m_Namespaces)
335 m_Namespaces->attach(*process);
336 if (process) {
337 auto& space = *process->getAddressSpace();
339 MemoryMapManager::instance().bindMemoryLockPolicy(space);
340 space.setMemoryLockAccount(&m_MemoryLockAccount);
341 }
342}
343
344bool PosixSubsystem::executablePath(String& result) const {
345 LockGuard<Mutex> image(m_ImageMetadataLock);
346 if (!m_ExecutablePath || !m_pProcess)
347 return false;
348 auto context = m_pProcess->acquireFilesystemContext();
350 auto* view = VFS::instance().mountView();
351 return context && context->snapshot(snapshot) && view &&
352 view->formatPath(snapshot, m_ExecutablePath, result);
353}
354
355bool PosixSubsystem::executablePath(FilesystemPathRef& result) const {
356 LockGuard<Mutex> image(m_ImageMetadataLock);
357 result = m_ExecutablePath;
358 return static_cast<bool>(result);
359}
360
361bool PosixSubsystem::commandLine(Vector<String>& result) const {
362 LockGuard<Mutex> image(m_ImageMetadataLock);
363 result = m_CommandLine;
364 return result.count() != 0;
365}
366
367bool PosixSubsystem::snapshotUserImage(UserImageToken& token) const {
369 token = {};
370 if (!m_UserImageActive)
371 return false;
372 token.space = m_UserImageSpace;
373 token.generation = m_UserImageGeneration;
374 return true;
375}
376
377bool PosixSubsystem::matchesUserImage(const UserImageToken& token) const {
379 return m_UserImageActive && token.space == m_UserImageSpace &&
380 token.generation == m_UserImageGeneration;
381}
382
383void PosixSubsystem::invalidateUserImage() {
385 m_UserImageActive = false;
386 m_UserImageSpace = nullptr;
387}
388
389bool PosixSubsystem::publishUserImage(VirtualAddressSpace& space) {
391 if (m_UserImageActive || !m_pProcess || m_pProcess->getAddressSpace() != &space ||
392 m_UserImageGeneration == ~uint64_t(0))
393 return false;
394 ++m_UserImageGeneration;
395 m_UserImageSpace = &space;
396 m_UserImageActive = true;
397 return true;
398}
399
401 TerminationDeferral terminationDeferral;
402 {
404 if (m_pProcess && m_pProcess->isVforkChild()) {
405 // Published children detach at exec/exit while their user hooks live.
406 // Construction rollback reaches here before creating the child Thread.
407 assert(m_pProcess->getNumThreads() == 0);
408 invalidateUserImage();
409 m_pProcess->releaseVforkAddressSpace();
410 }
411 }
412 m_TraceContext.close();
413 if (m_Namespaces)
414 m_Namespaces->close();
415 m_PendingSignals->close();
416 assert(--m_FreeCount == 0);
417
418 acquire();
419
420 // Destroy all signal handlers
421 for (sigHandlerTree::Iterator it = m_SignalHandlers.begin(); it != m_SignalHandlers.end(); it++) {
422 // Get the signal handler and remove it. Note that there shouldn't be
423 // null SignalHandlers, at all.
424 SignalHandler* sig = it.value();
425 assert(sig);
426
427 // SignalHandler's destructor will delete the Event itself
428 delete sig;
429 }
430
431 // And now that the signals are destroyed, remove them from the Tree
432 m_SignalHandlers.clear();
433
434 release();
435
436 // Process destruction may arrive with the table pre-acquired. Registry
437 // teardown must follow that release, including construction-failure fallback.
438 posix_advisory_owner_closed(m_AdvisoryOwner);
439
440 // For sanity's sake, destroy any remaining descriptors
442
443 // Remove any POSIX threads that might still be lying around
444 for (Tree<size_t, PosixThread*>::Iterator it = m_Threads.begin(); it != m_Threads.end(); it++) {
445 PosixThread* thread = it.value();
446 assert(thread); // There shouldn't have ever been a null PosixThread in
447 // there
448
449 // If the thread is still running, it should be killed
450 if (!thread->isRunning.isComplete()) {
451 WARNING("PosixSubsystem object freed when a thread is still running?");
452 // Thread will just stay running, won't be deallocated or killed
453 }
454
455 // Clean up any thread-specific data
456 for (Tree<size_t, PosixThreadKey*>::Iterator it2 = thread->m_ThreadData.begin();
457 it2 != thread->m_ThreadData.end(); it2++) {
458 PosixThreadKey* p = reinterpret_cast<PosixThreadKey*>(it.value());
459 assert(p);
460
463 delete p;
464 }
465
466 thread->m_ThreadData.clear();
467 delete thread;
468 }
469
470 m_Threads.clear();
471
472 // Clean up synchronisation objects
474 it != m_SyncObjects.end(); it++) {
475 PosixSyncObject* p = it.value();
476 assert(p);
477
478 if (p->pObject) {
479 if (p->isMutex)
480 delete reinterpret_cast<Mutex*>(p->pObject);
481 else
482 delete reinterpret_cast<Semaphore*>(p->pObject);
483 }
484 }
485
486 m_SyncObjects.clear();
487
489 ++it) {
490 // Process teardown has already quiesced every peer thread. Waking a
491 // waiter and immediately deleting its queue would manufacture a
492 // use-after-free; Semaphore/WaitQueue destruction instead verifies
493 // that the quiescence invariant is true.
494 delete it.value();
495 }
496
498
499 // Take the memory map lock before we become uninterruptible.
501 invalidateUserImage();
502
503 // Spinlock as a quick way of disabling interrupts.
504 Spinlock spinlock;
505 spinlock.acquire();
506
507 // Switch to the address space of the process we're destroying.
508 // We need to unmap memory maps, and we can't do that in our address space.
509 VirtualAddressSpace& curr = Processor::information().getVirtualAddressSpace();
510 VirtualAddressSpace* va = m_pProcess->getAddressSpace();
511
512 if (va != &curr) {
513 // Switch into the address space we want to unmap inside.
515 }
516
517 // Remove all existing mappings, if any.
519
520 if (va != &curr) {
522 }
523
524 spinlock.release();
525
526 va->rawUserMemory().clear();
527 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
528 va->setMemoryLockAccount(nullptr);
529
530 // Give back the memory map lock now - we're interruptible again.
532}
533
534void PosixSubsystem::acquireFdLock() {
536 FATAL("PosixSubsystem could not acquire its descriptor table");
537 }
538}
539
541 Thread* me = Processor::information().getCurrentThread();
542
543 m_Lock.acquire();
544 if (m_bAcquired && m_pAcquiredThread == me) {
545 m_Lock.release();
546 return; // already acquired
547 }
548 m_Lock.release();
549
550 // Exclude descriptor mutation and enumeration. Ordinary lookups retain
551 // their own leases; freeMultipleFds drains their entries during teardown.
552 acquireFdLock();
553
554 // Modifying signal handlers, ensure that they are not in use
556
557 // Safe to do without spinlock as we hold the other locks now.
559 m_bAcquired = true;
560}
561
563 // Opposite order to acquire()
564 m_Lock.acquire();
565 m_bAcquired = false;
566 m_pAcquiredThread = nullptr;
567
570
571 m_Lock.release();
572}
573
574bool PosixSubsystem::checkAddress(uintptr_t addr, size_t extent, size_t flags) {
575#if POSIX_NO_EFAULT
576 return true;
577#endif
578
579 Uninterruptible while_checking;
580
581#if VERBOSE_KERNEL
582 PS_NOTICE("PosixSubsystem::checkAddress(" << Hex << addr << ", " << Dec << extent << ", " << Hex
583 << flags << ")");
584#endif
585
586 // No memory access expected, all good.
587 if (!extent) {
588#if VERBOSE_KERNEL
589 PS_NOTICE(" -> zero extent, address is sane.");
590#endif
591 return true;
592 }
593
594 uintptr_t aa = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
595#if VERBOSE_KERNEL
596 PS_NOTICE(" -> ret: " << aa);
597#endif
598
599 // Check the complete address range.
600 VirtualAddressSpace& va = Processor::information().getVirtualAddressSpace();
601 if (!validUserAddressRange(addr, extent)) {
602#if VERBOSE_KERNEL
603 PS_NOTICE(" -> outside of user address area.");
604#endif
605 return false;
606 }
607 const uintptr_t end = addr + extent - 1;
608
609 // Keep fallback PTE inspection stable even for callers that only validate.
611 MemoryMappedObject::Permissions mmapPermissions = MemoryMappedObject::None;
612 if (flags & SafeRead) {
613 mmapPermissions |= MemoryMappedObject::Read;
614 }
615 if (flags & SafeWrite) {
616 mmapPermissions |= MemoryMappedObject::Write;
617 }
618 if (flags & SafeExecute) {
619 mmapPermissions |= MemoryMappedObject::Exec;
620 }
621
622 // Demand-paged mappings may not have PTEs yet. Accept them only when
623 // objects cover the complete range with the requested permissions.
624 if (mmapPermissions != MemoryMappedObject::None &&
625 MemoryMapManager::instance().allows(addr, extent, mmapPermissions)) {
626#if VERBOSE_KERNEL
627 PS_NOTICE(" -> inside memory map.");
628#endif
629 return true;
630 }
631
632 // Check each page touched by the range, including a short final page after
633 // an unaligned start.
634 size_t pageSize = PhysicalMemoryManager::getPageSize();
635 uintptr_t page = addr - (addr % pageSize);
636 uintptr_t finalPage = end - (end % pageSize);
637 while (true) {
638 void* pAddr = reinterpret_cast<void*>(page);
639 if (!va.isMapped(pAddr)) {
640#if VERBOSE_KERNEL
641 PS_NOTICE(" -> page " << Hex << pAddr << " is not mapped.");
642#endif
643 return false;
644 }
645
646 size_t vFlags = 0;
647 physical_uintptr_t phys = 0;
648 va.getMapping(pAddr, phys, vFlags);
649
651#if VERBOSE_KERNEL
652 PS_NOTICE(" -> not userspace-accessible.");
653#endif
654 return false;
655 }
656
657 if (flags & SafeWrite) {
660#if VERBOSE_KERNEL
661 PS_NOTICE(" -> not writeable.");
662#endif
663 return false;
664 }
665 }
666
667 if ((flags & SafeExecute) && !(vFlags & VirtualAddressSpace::Execute)) {
668#if VERBOSE_KERNEL
669 PS_NOTICE(" -> not executable.");
670#endif
671 return false;
672 }
673
674 if (page == finalPage) {
675 break;
676 }
677 page += pageSize;
678 }
679
680#if VERBOSE_KERNEL
681 PS_NOTICE(" -> mapped and available.");
682#endif
683 return true;
684}
685
686bool PosixSubsystem::checkedUserBufferSize(size_t count, size_t elementSize, size_t& extent) {
687 extent = 0;
688 if (!count || !elementSize) {
689 return true;
690 }
691
692 if (count > (~static_cast<size_t>(0) / elementSize)) {
693 return false;
694 }
695
696 extent = count * elementSize;
697 return true;
698}
699
700bool PosixSubsystem::checkUserAddressRange(uintptr_t addr, size_t count, size_t elementSize,
701 size_t* extent) {
702 if (extent) {
703 *extent = 0;
704 }
705
706 size_t byteExtent = 0;
707 if (!checkedUserBufferSize(count, elementSize, byteExtent)) {
708 return false;
709 }
710
711 if (extent) {
712 *extent = byteExtent;
713 }
714#if POSIX_NO_EFAULT
715 return true;
716#else
717 return !byteExtent || validUserAddressRange(addr, byteExtent);
718#endif
719}
720
721bool PosixSubsystem::checkUserBuffer(uintptr_t addr, size_t count, size_t elementSize, size_t flags,
722 size_t* extent) {
723 if (extent) {
724 *extent = 0;
725 }
726
727 size_t byteExtent = 0;
728 if (!checkedUserBufferSize(count, elementSize, byteExtent)) {
729 return false;
730 }
731
732 if (extent) {
733 *extent = byteExtent;
734 }
735 return checkAddress(addr, byteExtent, flags);
736}
737
738bool PosixSubsystem::copyFromUser(void* destination, const void* source, size_t count,
739 size_t elementSize) {
740 size_t extent = 0;
741 if (!checkedUserBufferSize(count, elementSize, extent)) {
742 return false;
743 }
744 if (!extent) {
745 return true;
746 }
747 if (!destination || !source) {
748 return false;
749 }
750
752 if (!prepareUserCopy(reinterpret_cast<uintptr_t>(source), extent, false)) {
753 return false;
754 }
755
756 MemoryCopy(destination, source, extent);
757 return true;
758}
759
760bool PosixSubsystem::copyToUser(void* destination, const void* source, size_t count,
761 size_t elementSize) {
762 size_t extent = 0;
763 if (!checkedUserBufferSize(count, elementSize, extent)) {
764 return false;
765 }
766 if (!extent) {
767 return true;
768 }
769 if (!destination || !source) {
770 return false;
771 }
772
774 if (!prepareUserCopy(reinterpret_cast<uintptr_t>(destination), extent, true)) {
775 return false;
776 }
777
778 MemoryCopy(destination, source, extent);
779 return true;
780}
781
782size_t PosixSubsystem::readCachedFile(File& file, uint64_t offset, void* destination,
783 size_t count) {
784 if (!count || !file.supportsRegularFileOperations() || file.isBlockDevice() ||
785 !validUserAddressRange(reinterpret_cast<uintptr_t>(destination), count)) {
786 return 0;
787 }
789 MemoryMapManager::OperationGuard mappingGuard(mappings);
790 return file.readCached(
791 offset, count, reinterpret_cast<uintptr_t>(destination), [](uintptr_t address, size_t bytes) {
792 return MemoryMapManager::instance().writableAnonymousRange(address, bytes);
793 });
794}
795
796PosixSubsystem::UserStringResult PosixSubsystem::copyUserString(const char* userString,
797 String& copy, size_t maxLength) {
798 copy.clear();
799
800 if (!userString) {
801 return UserStringBadAddress;
802 }
803
804 if (!maxLength) {
805 return UserStringTooLong;
806 }
807
809
810 const size_t pageSize = PhysicalMemoryManager::getPageSize();
811 const size_t chunkSize = 256;
812 uintptr_t current = reinterpret_cast<uintptr_t>(userString);
813 size_t copied = 0;
814
815 while (copied < maxLength) {
816 size_t length = maxLength - copied;
817 if (length > chunkSize) {
818 length = chunkSize;
819 }
820
821 const size_t pageOffset = current % pageSize;
822 const size_t pageRemaining = pageSize - pageOffset;
823 if (length > pageRemaining) {
824 length = pageRemaining;
825 }
826
827 if (!prepareUserCopy(current, length, false)) {
828 return UserStringBadAddress;
829 }
830
831 char buffer[chunkSize];
832 MemoryCopy(buffer, reinterpret_cast<const void*>(current), length);
833
834 size_t partLength = 0;
835 while (partLength < length && buffer[partLength]) {
836 ++partLength;
837 }
838
839 if (partLength != length) {
840 copy += String(buffer, partLength, true);
841 return UserStringSuccess;
842 }
843
844 copy += String(buffer, length, true);
845 copied += length;
846 if (copied == maxLength) {
847 return UserStringTooLong;
848 }
849
850 if (current > (~static_cast<uintptr_t>(0) - length)) {
851 return UserStringBadAddress;
852 }
853 current += length;
854 }
855
856 return UserStringTooLong;
857}
858
859void PosixSubsystem::exit(int code, ExitCause cause) {
861 FATAL_NOLOCK(
862 "PosixSubsystem::exit requires an IRQ-enabled thread "
863 "boundary.");
864 }
865
866 Thread* pThread = Processor::information().getCurrentThread();
867
868 Process* pProcess = pThread->getParent();
869 NOTICE("PosixSubsystem::exit(" << Dec << pProcess->getId() << ", code=" << code << ")");
870
871 m_TraceContext.close();
872 if (!pProcess->beginTermination(code, cause)) {
873 // Another thread owns or has reserved process-wide cleanup. A competitor
874 // must take only the thread exit path; the owner will retire every peer.
875 Processor::information().getScheduler().commitCurrentThreadExit();
876 }
877
878 if (cause == ExitCause::Signal) {
879 pProcess->setExitStatus(code & 0x7F);
880 } else {
881 pProcess->setExitStatus((code & 0xFF) << 8);
882 }
883 if (code) {
884 pThread->unexpectedExit();
885 }
886
887 // Exit has reached the final cleanup context. Blocking cleanup below must
888 // not recursively transfer back into exit at every WaitQueue boundary.
890
891 if (!pProcess->quiesceTermination()) {
892 FATAL("POSIX exit owner could not claim process teardown for pid " << Dec << pProcess->getId()
893 << ".");
894 }
895
896 // quiesceTermination() may block while peers leave their stacks. Its
897 // completion is the final handoff into shared process cleanup.
899 FATAL_NOLOCK(
900 "POSIX process teardown escaped its IRQ-enabled thread "
901 "boundary.");
902 }
903
904 // We're the lowest in the stack, so we can proceed with the exit function.
905
906 static_cast<PosixProcess*>(pProcess)->snapshotAccountingMemory();
907
908 posix_advisory_owner_closed(m_AdvisoryOwner);
909
910 // Peer shutdown has consumed their registrations. The final owner must
911 // retire its user-memory exit state before process teardown removes it.
912 m_PendingSignals->close();
913 posix_timer_process_exit(pProcess);
914 invalidateUserImage();
915 pThread->notifySubsystemExit();
916
917 {
919 pProcess->releaseVforkAddressSpace();
920 }
921
922 delete pProcess->getLinker();
923
925
926 {
928 auto& space = *pProcess->getAddressSpace();
929 space.rawUserMemory().clear();
930 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
931 space.setMemoryLockAccount(nullptr);
932 }
933
934 // Group membership must survive for wait's zombie selection. PosixProcess
935 // retires it after removal from lookup and drainage of retained observers.
936
937 posix_mqueue_process_exit(pProcess->getId());
938
939 // Clean up the descriptor table
941
942 // Tell some interesting info
943 NOTICE("at exit for pid " << Dec << pProcess->getId() << "...");
944
945 pProcess->finishTermination(true);
946
947 // Should NEVER get here.
948 FATAL("PosixSubsystem::exit() running after Process teardown!");
949}
950
951bool PosixSubsystem::kill(KillReason killReason, Thread* pThread) {
952 if (!pThread)
953 pThread = Processor::information().getCurrentThread();
954 Process* pProcess = pThread->getParent();
955 if (pProcess->getType() != Process::Posix) {
956 ERROR("PosixSubsystem::kill called with a non-POSIX process!");
957 return false;
958 }
959 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
960
961 int signal = SIGKILL;
962 switch (killReason) {
963 case Interrupted:
964 signal = SIGINT;
965 break;
966
967 case Terminated:
968 signal = SIGTERM;
969 break;
970
971 default:
972 break;
973 }
974
975 if (pSubsystem->queueSignalDelivery(pThread, signal, nullptr, 0, true) ==
976 SignalDeliveryResult::Queued) {
977 PS_NOTICE("PosixSubsystem - killing " << pThread->getParent()->getId());
978
979 // Allow the event to run
982 }
983
984 return true;
985}
986
987bool PosixSubsystem::resolveUserPageFault(Thread& thread, InterruptState& state,
988 uintptr_t faultAddress, uintptr_t errorCode) {
989 constexpr uintptr_t present = 1, write = 2, user = 4, fetch = 16;
990 if (state.kernelMode() || !Processor::getInterrupts() ||
991 Processor::information().getCurrentThread() != &thread || !thread.getParent() ||
992 thread.getParent()->getSubsystem() != this ||
993 thread.getParent()->getAddressSpace() != &Processor::information().getVirtualAddressSpace() ||
994 (errorCode & ~(present | write | user | fetch)) ||
995 ((errorCode & write) && (errorCode & fetch))) {
996 return false;
997 }
998#if X64 && !HOSTED
999 if (!(errorCode & user))
1000 return false;
1001#endif
1002 const auto resolution = MemoryMapManager::instance().resolveUserFault(
1003 faultAddress, errorCode & write, errorCode & present, errorCode & fetch);
1004 if (resolution == MemoryMapManager::FaultResolution::BackingFault) {
1005 threadException(&thread, FileMappingFault, &state, faultAddress, errorCode);
1006 return true;
1007 }
1008 return resolution == MemoryMapManager::FaultResolution::Resolved;
1009}
1010
1011void PosixSubsystem::threadException(Thread* pThread, ExceptionType eType, InterruptState* pState,
1012 uintptr_t faultAddress, uintptr_t errorCode) {
1013#if X64
1014 EMIT_IF(POSIX_LOG_FACILITIES & 16) {
1015 if (pState && eType == PageFault) {
1016 // Keep each entry within the log payload, including its PID/TID prefix.
1017 PS_NOTICE("USERFAULT cpu=" << Dec << Processor::id());
1018 PS_NOTICE("USERFAULT address=" << Hex << faultAddress);
1019 PS_NOTICE("USERFAULT code=" << Hex << errorCode);
1020 PS_NOTICE("USERFAULT rip=" << Hex << pState->getInstructionPointer());
1021 PS_NOTICE("USERFAULT rsp=" << Hex << pState->getStackPointer());
1022 PS_NOTICE("USERFAULT entry-fs=" << Hex << pState->getUserEntryMetadata().fsBase);
1023 PS_NOTICE("USERFAULT entry-gs=" << Hex << pState->getUserEntryMetadata().gsBase);
1024 PS_NOTICE("USERFAULT tls=" << Hex << pThread->getTlsBase());
1025 for (size_t i = 0; i < pState->getRegisterCount(); ++i) {
1026 PS_NOTICE("USERFAULT " << pState->getRegisterName(i) << "=" << Hex
1027 << pState->getRegister(i));
1028 }
1029 }
1030 }
1031#endif
1032 // The native event path does not consume machine context yet.
1033 (void)pState;
1034 (void)faultAddress;
1035 (void)errorCode;
1036
1037 PS_NOTICE("PosixSubsystem::threadException -> " << Dec << pThread->getParent()->getId() << ":"
1038 << pThread->getId());
1039
1040 // What was the exception?
1041 int signal = -1;
1042 switch (eType) {
1043 case PageFault:
1044 PS_NOTICE(" (Page fault)");
1045 // Send SIGSEGV
1046 signal = SIGSEGV;
1047 break;
1048 case FileMappingFault:
1049 signal = SIGBUS;
1050 break;
1051 case InvalidOpcode:
1052 PS_NOTICE(" (Invalid opcode)");
1053 // Send SIGILL
1054 signal = SIGILL;
1055 break;
1056 case GeneralProtectionFault:
1057 PS_NOTICE(" (General Fault)");
1058 // Send SIGBUS
1059 signal = SIGBUS;
1060 break;
1061 case DivideByZero:
1062 PS_NOTICE(" (Division by zero)");
1063 // Send SIGFPE
1064 signal = SIGFPE;
1065 break;
1066 case FpuError:
1067 PS_NOTICE(" (FPU error)");
1068 // Send SIGFPE
1069 signal = SIGFPE;
1070 break;
1071 case SpecialFpuError:
1072 PS_NOTICE(" (FPU error - special)");
1073 // Send SIGFPE
1074 signal = SIGFPE;
1075 break;
1076 case TerminalInput:
1077 PS_NOTICE(
1078 " (Attempt to read from terminal by non-foreground "
1079 "process)");
1080 // Send SIGTTIN
1081 signal = SIGTTIN;
1082 break;
1083 case TerminalOutput:
1084 PS_NOTICE(" (Output to terminal by non-foreground process)");
1085 // Send SIGTTOU
1086 signal = SIGTTOU;
1087 break;
1088 case Continue:
1089 PS_NOTICE(" (Continuing a stopped process)");
1090 // Send SIGCONT
1091 signal = SIGCONT;
1092 break;
1093 case Stop:
1094 PS_NOTICE(" (Stopping a process)");
1095 // Send SIGTSTP
1096 signal = SIGTSTP;
1097 break;
1098 case Interrupt:
1099 PS_NOTICE(" (Interrupting a process)");
1100 // Send SIGINT
1101 signal = SIGINT;
1102 break;
1103 case Quit:
1104 PS_NOTICE(" (Requesting quit)");
1105 // Send SIGTERM
1106 signal = SIGTERM;
1107 break;
1108 case Child:
1109 PS_NOTICE(" (Child status changed)");
1110 // Send SIGCHLD
1111 signal = SIGCHLD;
1112 break;
1113 case Pipe:
1114 PS_NOTICE(" (Pipe broken)");
1115 // Send SIGPIPE
1116 signal = SIGPIPE;
1117 break;
1118 default:
1119 PS_NOTICE(" (Unknown)");
1120 // Unknown exception
1121 ERROR("Unknown exception type in threadException - POSIX subsystem");
1122 break;
1123 }
1124
1125#if X64
1126 if (signal > 0 && pState && getAbi() == LinuxAbi) {
1127 if (traceException(*pThread, signal, *pState, eType, faultAddress, errorCode))
1128 return;
1129 SignalDisposition disposition;
1130 if (getSignalDisposition(signal, disposition, true) && disposition.type == 0) {
1131 LinuxAmd64Signal::DeliveryResult result = LinuxAmd64Signal::deliverSynchronous(
1132 pThread, signal, disposition, eType, *pState, faultAddress, errorCode);
1133 if (result == LinuxAmd64Signal::Delivered) {
1134 return;
1135 }
1136 if (result == LinuxAmd64Signal::Failed) {
1137 // The raw exception frame still owns interrupt accounting and
1138 // handler cleanup. Preserve the fatal status and let the
1139 // return-to-user tail enter process teardown after it unwinds.
1140 pThread->deferSignalExit(SIGSEGV);
1141 return;
1142 }
1143 }
1144 }
1145#endif
1146
1147 // A raw exception frame cannot dispatch a handler or terminal callback.
1148 // Its return-to-user tail consumes the queued signal after accounting and
1149 // handler cleanup have completed.
1150 const bool processDirected = eType == TerminalInput || eType == TerminalOutput ||
1151 eType == Continue || eType == Stop || eType == Interrupt ||
1152 eType == Quit || eType == Child;
1153 sendSignal(pThread, signal, pState == nullptr, processDirected);
1154}
1155
1156void PosixSubsystem::sendSignal(Thread* pThread, int signal, bool yield, bool processDirected) {
1157 PS_NOTICE("PosixSubsystem::sendSignal #" << signal << " -> pid:tid " << Dec
1158 << pThread->getParent()->getId() << ":"
1159 << pThread->getId());
1160
1161 Process* pProcess = pThread->getParent();
1162 if (pProcess->getType() != Process::Posix) {
1163 ERROR("PosixSubsystem::threadException called with a non-POSIX process!");
1164 return;
1165 }
1166 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
1167
1168 const SignalDeliveryResult result =
1169 pSubsystem->queueSignalDelivery(pThread, signal, nullptr, 0, processDirected);
1170 if (result == SignalDeliveryResult::Unavailable) {
1171 ERROR("Unknown signal in sendSignal - POSIX subsystem");
1172 }
1173
1174 if (result == SignalDeliveryResult::Queued && yield) {
1175 Thread* pCurrentThread = Processor::information().getCurrentThread();
1176 if (pCurrentThread == pThread) {
1177 // Attempt to execute the new event immediately.
1179 } else {
1180 // Yield so the event can fire.
1182 }
1183 } else if (result == SignalDeliveryResult::Rejected) {
1184 // PS_NOTICE("No event configured for signal #" << signal << ", silently
1185 // dropping!");
1186 NOTICE("No event configured for signal #" << signal << ", silently dropping!");
1187 }
1188}
1189
1190bool PosixSubsystem::admitLegacyUserSignals() {
1192 TraceRelationRef trace;
1193 if (m_CallbackSchedulingDomain == CallbackSchedulingDomain::Affinity ||
1194 m_TraceContext.acquireIncoming(trace))
1195 return false;
1196 // A serialized legacy handler retains a lower kernel continuation after
1197 // its Event lease retires. Its image must keep that continuation's CPU.
1198 m_CallbackSchedulingDomain = CallbackSchedulingDomain::LegacySignals;
1199 return true;
1200}
1201
1203 if (sig > MaximumSupportedSignal) {
1204 delete handler;
1205 ERROR("Cannot install unsupported signal disposition " << Dec << sig << ".");
1206 return;
1207 }
1208
1209 PendingSignalNotification notification(m_PendingSignals);
1210 LockGuard<Mutex> pendingGuard(m_PendingSignals->lock);
1212
1213 SignalHandler* removal = nullptr;
1214
1215 if (handler) {
1216 removal = m_SignalHandlers.lookup(sig);
1217 if (removal) {
1218 // Remove from the list
1219 m_SignalHandlers.remove(sig);
1220 }
1221
1222 // Insert into the signal handler table
1223 handler->sig = sig;
1224
1225 m_SignalHandlers.insert(sig, handler);
1226
1227 const bool discardPending =
1228 handler->type == 2 || (handler->type == 1 && defaultSignalActionIsIgnore(sig));
1229 if (m_pProcess) {
1230 // Descending indices remain exhaustive when an exiting thread is
1231 // removed and shifts the remaining vector entries to the left.
1232 for (size_t i = m_pProcess->getNumThreads(); i > 0; --i) {
1233 Process::ThreadLease thread;
1234 if (m_pProcess->acquireThread(thread, i - 1)) {
1235 if (discardPending) {
1236 thread->cullSignalEvent(sig);
1237 } else if (handler->pEvent) {
1238 // A concurrent dequeue already owns its old delivery. Only
1239 // events still pending must acquire the new disposition.
1240 rebindQueuedSignalEvents(*thread.get(), sig, *handler->pEvent);
1241 }
1242 }
1243 }
1244 }
1245 }
1246
1247 m_PendingSignals->recordChange();
1249
1250 // Complete the destruction of the handler (waiting for deletion) with no
1251 // lock held.
1252 if (removal) {
1253 delete removal;
1254 }
1255}
1256
1258 Thread* thread, SignalHandler* const handlers[SignalDispositionCount]) {
1259 if (!thread || thread->getParent() != m_pProcess || m_pProcess->getNumThreads() != 1) {
1260 FATAL("Exec signal reset requires the sole surviving process thread.");
1261 }
1262
1263 for (size_t signal = 0; signal < SignalDispositionCount; ++signal) {
1264 if (!handlers[signal] || !handlers[signal]->pEvent ||
1265 handlers[signal]->pEvent->getNumber() != signal) {
1266 FATAL("Exec signal reset received an incomplete disposition table.");
1267 }
1268 }
1269
1270 PendingSignalNotification notification(m_PendingSignals);
1271 LockGuard<Mutex> pendingGuard(m_PendingSignals->lock);
1272 SignalHandler* removals[SignalDispositionCount] = {};
1274
1275 for (size_t signal = 0; signal < SignalDispositionCount; ++signal) {
1276 SignalHandler* replacement = handlers[signal];
1277 replacement->sig = signal;
1278
1279 removals[signal] = m_SignalHandlers.lookup(signal);
1280 if (removals[signal]) {
1281 m_SignalHandlers.remove(signal);
1282 }
1283 m_SignalHandlers.insert(signal, replacement);
1284
1285 if (!rebindQueuedSignalEvents(*thread, signal, *replacement->pEvent)) {
1286 FATAL("Exec signal reset could not rebind a pending signal.");
1287 }
1288 }
1289
1290 m_PendingSignals->recordChange();
1292
1293 for (SignalHandler* removal : removals) {
1294 delete removal;
1295 }
1296}
1297
1299 bool beginDelivery) {
1300 if (sig > MaximumSupportedSignal) {
1301 return false;
1302 }
1303
1304 if (beginDelivery) {
1306 } else {
1308 }
1309
1310 SignalEvent* retired = nullptr;
1311 SignalHandler* handler = m_SignalHandlers.lookup(sig);
1312 if (handler) {
1313 disposition.handler = handler->pEvent ? handler->pEvent->getHandlerAddress() : 0;
1314 disposition.signalMask = handler->sigMask;
1315 disposition.flags = handler->flags;
1316 disposition.restorer = handler->restorer;
1317 disposition.type = handler->type;
1318
1319 if (beginDelivery && handler->type == 0 && (handler->flags & SA_RESETHAND)) {
1320 // Queueing and competing deliveries use this same lock. Existing
1321 // AsyncEvents also resolve here, so no queued snapshot can catch twice.
1322 retired = handler->pEvent;
1323 handler->pEvent = new SignalEvent(pedigree_default_signal_handler(sig), sig, ~0UL, 0, true,
1324 false, Event::HandlerPrivilege::Kernel,
1325 SignalEvent::DeliveryDisposition::DefaultAction);
1326 handler->type = 1;
1327 handler->sigMask = 0;
1328 handler->flags = 0;
1329 handler->restorer = 0;
1330 }
1331 }
1332
1333 if (beginDelivery) {
1335 } else {
1337 }
1338 if (retired) {
1339 retired->retire();
1340 }
1341 return handler != nullptr;
1342}
1343
1344PosixSubsystem::SignalDeliveryResult PosixSubsystem::queueSignalDelivery(
1345 Thread* target, size_t sig, uint32_t* flags, int32_t signalCode, bool processDirected,
1346 uint64_t signalValue, const SharedPointer<SignalEventState>& state) {
1347 PendingSignalNotification notification(m_PendingSignals);
1348 LockGuard<Mutex> pendingGuard(m_PendingSignals->lock);
1349 if (flags) {
1350 *flags = 0;
1351 }
1352
1353 Process::ThreadLease processTarget;
1355
1356 if (!target || !target->getParent() || target->getParent()->getSubsystem() != this || !sig ||
1357 sig > MaximumSupportedSignal) {
1359 return SignalDeliveryResult::Unavailable;
1360 }
1361
1362 constexpr size_t StopSignals[] = {SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
1363 const size_t* signalsToDiscard = nullptr;
1364 size_t signalsToDiscardCount = 0;
1365 size_t continueSignal = SIGCONT;
1366 if (sig == SIGCONT) {
1367 signalsToDiscard = StopSignals;
1368 signalsToDiscardCount = sizeof(StopSignals) / sizeof(StopSignals[0]);
1369 } else {
1370 for (size_t stopSignal : StopSignals) {
1371 if (sig == stopSignal) {
1372 signalsToDiscard = &continueSignal;
1373 signalsToDiscardCount = 1;
1374 break;
1375 }
1376 }
1377 }
1378
1379 Process* process = target->getParent();
1380 auto pidNamespace = process->pidNamespace();
1381 if (pidNamespace && pidNamespace->parent() && !pidNamespace->dead() &&
1382 process->getUserspaceId() == 1) {
1383 auto* sender = Processor::information().getCurrentThread();
1384 auto* senderProcess = sender ? sender->getParent() : nullptr;
1385 const bool ancestor = !senderProcess || !senderProcess->getUserspaceId(pidNamespace.get());
1386 const auto* disposition = m_SignalHandlers.lookup(sig);
1387 const bool blocked =
1388 (target->getSignalMask() | target->getSynchronousSignalMask()) & (uint64_t(1) << (sig - 1));
1389 if ((!disposition || disposition->type != 0) && !blocked &&
1390 !(ancestor && (sig == SIGKILL || sig == SIGSTOP))) {
1392 return SignalDeliveryResult::Rejected;
1393 }
1394 }
1395 if (processDirected) {
1396 // Exec's pending-signal handoff holds this same lock after publishing
1397 // its owner, so an old-target publication must finish before the move.
1398 if (!process->acquireProcessSignalThread(processTarget)) {
1400 return SignalDeliveryResult::Rejected;
1401 }
1402 target = processTarget.get();
1403 // A registered synchronous waiter takes priority over asynchronous delivery.
1404 for (unsigned pass = 0; pass < 2; ++pass) {
1405 bool selected = false;
1406 for (size_t i = process->getNumThreads(); i > 0; --i) {
1407 Process::ThreadLease candidate;
1408 if (!process->acquireThread(candidate, i - 1) || !candidate->acceptingEvents() ||
1409 candidate->getUnwindState() != Thread::Continue)
1410 continue;
1411 const uint64_t bit = uint64_t(1) << (sig - 1);
1412 if ((pass == 0 && (candidate->getSynchronousSignalMask() & bit)) ||
1413 (pass == 1 && !(candidate->getSignalMask() & bit))) {
1414 processTarget = pedigree_std::move(candidate);
1415 target = processTarget.get();
1416 selected = true;
1417 break;
1418 }
1419 }
1420 if (selected)
1421 break;
1422 }
1423 }
1424 if (signalsToDiscard) {
1425 // Pending stop and continue signals are mutually exclusive across the
1426 // whole process, including thread-directed signals.
1427 for (size_t i = process->getNumThreads(); i > 0; --i) {
1428 Process::ThreadLease thread;
1429 if (process->acquireThread(thread, i - 1)) {
1430 for (size_t n = 0; n < signalsToDiscardCount; ++n) {
1431 thread->cullSignalEvent(signalsToDiscard[n]);
1432 }
1433 }
1434 }
1435 }
1436
1437 // Continuation is a generation-time effect even when SIGCONT is blocked or
1438 // ignored. Publish Active before a caught handler can enter the event queue.
1439 if (sig == SIGCONT) {
1440 process->resume();
1441 TraceRelationRef trace;
1442 if (m_TraceContext.acquireIncoming(trace))
1443 trace->continued(*process);
1444 }
1445
1446 SignalHandler* handler = m_SignalHandlers.lookup(sig);
1447 SignalEvent* delivery = nullptr;
1448 const bool ignored =
1449 handler && (handler->type == 2 || (handler->type == 1 && defaultSignalActionIsIgnore(sig)));
1450 const uint64_t bit = uint64_t(1) << (sig - 1);
1451 const bool blocked = (target->getSignalMask() | target->getSynchronousSignalMask()) & bit;
1452 const bool suppressDelivery = ignored && !blocked && !target->requiresSignalFrames();
1453 // A blocked ignored signal still belongs to sigwait/sigpending. Its inert
1454 // prototype also handles a later unblock without invoking a user handler.
1455 if (ignored && !handler->pEvent) {
1456 handler->pEvent = new SignalEvent(reinterpret_cast<uintptr_t>(ignoredSignal), sig, ~0UL, 0,
1457 true, false, Event::HandlerPrivilege::Kernel,
1458 SignalEvent::DeliveryDisposition::DefaultAction);
1459 }
1460 SignalDeliveryResult result = SignalDeliveryResult::Unavailable;
1461 if (suppressDelivery) {
1462 result = SignalDeliveryResult::Ignored;
1463 } else if (handler && handler->pEvent) {
1464 if (sig < LinuxPrivateSignalFirst && !state) {
1465 bool duplicate = false;
1466 if (processDirected) {
1467 for (size_t i = process->getNumThreads(); i > 0; --i) {
1469 if (process->acquireThread(sibling, i - 1) && sibling->hasSignalEvent(sig, 1)) {
1470 duplicate = true;
1471 break;
1472 }
1473 }
1474 } else
1475 duplicate = target->hasSignalEvent(sig, 0);
1476 if (duplicate) {
1478 return SignalDeliveryResult::Queued;
1479 }
1480 }
1481 SharedPointer<SignalEventState> deliveryState = state;
1482 if (!deliveryState && (signalCode == -1 || sig >= 35)) {
1483 deliveryState = posix_signal_reserve_queue(process);
1484 if (!deliveryState) {
1486 return SignalDeliveryResult::Full;
1487 }
1488 }
1489 delivery = static_cast<SignalEvent*>(handler->pEvent->cloneForDelivery());
1490 Thread* sender = Processor::information().getCurrentThread();
1491 Process* senderProcess = sender ? sender->getParent() : nullptr;
1492 int32_t senderPid = 0;
1493 uint32_t senderUid = 0;
1494 if (senderProcess && senderProcess->getType() == Process::Posix) {
1495 senderPid =
1496 static_cast<int32_t>(senderProcess->getUserspaceId(process->pidNamespace().get()));
1497 const int64_t uid = senderProcess->getUserId();
1498 if (uid >= 0) {
1499 senderUid = static_cast<uint32_t>(uid);
1500 }
1501 }
1502 static uint64_t nextSignalSequence = 0;
1503 delivery->setQueueSequence(__atomic_add_fetch(&nextSignalSequence, 1, __ATOMIC_RELAXED));
1504 delivery->setDeliveryState(deliveryState);
1505 if (sig == SIGCHLD && signalCode == 4 && senderProcess &&
1506 senderProcess->getParent() == process) {
1507 delivery->setChildStatus(static_cast<int32_t>(signalValue),
1508 senderProcess->getUserTime() / (Time::Multiplier::Second / 100),
1509 senderProcess->getKernelTime() / (Time::Multiplier::Second / 100));
1510 } else if (sig == SIGCHLD && signalCode == 0 && senderProcess &&
1511 senderProcess->getParent() == process &&
1512 senderProcess->getState() == Process::Terminated) {
1513 const int status = senderProcess->getExitStatus();
1514 signalCode = (status & 0x7f) ? ((status & 0x80) ? 3 : 2) : 1;
1515 delivery->setChildStatus((status & 0x7f) ? (status & 0x7f) : ((status >> 8) & 0xff),
1516 senderProcess->getUserTime() / (Time::Multiplier::Second / 100),
1517 senderProcess->getKernelTime() / (Time::Multiplier::Second / 100));
1518 }
1519 delivery->setSignalOrigin(signalCode, senderPid, senderUid);
1520 delivery->setSignalValue(signalValue);
1521 delivery->setProcessDirected(processDirected);
1522 stampStopDelivery(process, sig, delivery);
1523 if (flags) {
1524 *flags = handler->flags;
1525 }
1526 while (true) {
1527 if (target->sendEvent(delivery)) {
1528 result = SignalDeliveryResult::Queued;
1529 break;
1530 }
1531 // A recipient can start ordinary thread exit after selection. Its
1532 // closed queue does not discard a signal belonging to the process.
1533 if (!processDirected || !process->acquireProcessSignalThread(processTarget)) {
1534 result = SignalDeliveryResult::Rejected;
1535 break;
1536 }
1537 target = processTarget.get();
1538 }
1539 }
1540
1542 m_PendingSignals->recordChange(result == SignalDeliveryResult::Queued ? sig : 0, target,
1543 processDirected);
1544 if (delivery && result == SignalDeliveryResult::Rejected) {
1545 delivery->rejectSignalDelivery();
1546 delete delivery;
1547 }
1548 return result;
1549}
1550
1557size_t PosixSubsystem::getFd(size_t minimum) {
1558 Uninterruptible throughout;
1559
1560 // Enter critical section for writing.
1561 acquireFdLock();
1562
1563 // Try to recycle if possible
1564 const bool advancesGlobalHint = minimum <= m_LastFd;
1565 const size_t firstCandidate = minimum > m_LastFd ? minimum : m_LastFd;
1566 for (size_t i = firstCandidate; i < m_NextFd; i++) {
1567 if (!(m_FdBitmap.test(i))) {
1568 // A constrained F_DUPFD search must not hide lower holes from the
1569 // ordinary lowest-descriptor allocator.
1570 if (advancesGlobalHint) {
1571 m_LastFd = i;
1572 }
1573 m_FdBitmap.set(i);
1574 m_FdLock.release();
1575 return i;
1576 }
1577 }
1578
1579 // Otherwise, allocate
1580 // m_NextFd will always be one beyond the highest allocated fd.
1581 const size_t ret = minimum > m_NextFd ? minimum : m_NextFd;
1582 m_FdBitmap.set(ret);
1583 m_NextFd = ret + 1;
1584 m_FdLock.release();
1585 return ret;
1586}
1587
1588void PosixSubsystem::allocateFd(size_t fdNum) {
1589 Uninterruptible throughout;
1590
1591 // Enter critical section for writing.
1592 acquireFdLock();
1593
1594 if (fdNum >= m_NextFd)
1595 m_NextFd = fdNum + 1;
1596 m_FdBitmap.set(fdNum);
1597
1598 m_FdLock.release();
1599}
1600
1601void PosixSubsystem::freeFd(size_t fdNum) {
1603
1604 {
1605 Uninterruptible throughout;
1606
1607 // Unpublish atomically. Keep a private reference so the descriptor's
1608 // teardown cannot run while the table lock is held.
1609 acquireFdLock();
1610
1611 m_FdBitmap.clear(fdNum);
1612 if (m_FdMap.take(fdNum, retiring)) {
1613 publishFdEntry(fdNum);
1614 }
1615
1616 if (fdNum < m_LastFd)
1617 m_LastFd = fdNum;
1618
1619 m_FdLock.release();
1620 }
1621
1622 // File/socket/event retirement can block and can re-enter unrelated
1623 // registries. It must happen after the descriptor-table lock is gone.
1624 if (retiring) {
1625 retireDescriptor(retiring.get());
1626 }
1627 retiring.reset();
1628}
1629
1631 assert(pSubsystem);
1632
1634
1635 // We're totally resetting our local state, ensure there's no files hanging
1636 // around.
1638
1639 {
1640 Uninterruptible throughout;
1641
1642 // Totally changing everything... Don't allow other functions to
1643 // meddle.
1644 acquireFdLock();
1645 pSubsystem->acquireFdLock();
1646
1647 // Copy each descriptor across from the original subsystem.
1648 FdMap& map = pSubsystem->m_FdMap;
1649 for (FdMap::Iterator it = map.begin(); it != map.end(); it++) {
1650 SharedPointer<FileDescriptor> pFd = it.value();
1651 if (!pFd)
1652 continue;
1653 size_t newFd = it.key();
1654
1656 assert(!pFd->networkImpl || pNewFd->networkPublished());
1657
1658 // Perform the same action as addFileDescriptor. We need to
1659 // duplicate here because we currently hold the FD lock, which will
1660 // deadlock if we call any function which attempts to acquire it.
1661 if (newFd >= m_NextFd)
1662 m_NextFd = newFd + 1;
1663 m_FdBitmap.set(newFd);
1665 if (m_FdMap.take(newFd, previous)) {
1666 retiring.pushBack(pedigree_std::move(previous));
1667 }
1668 m_FdMap.insert(newFd, pedigree_std::move(pNewFd));
1669 }
1670
1671 publishFdEntries();
1672
1673 pSubsystem->m_FdLock.release();
1674 m_FdLock.release();
1675 }
1676
1677 for (auto& descriptor : retiring) {
1678 retireDescriptor(descriptor.get());
1679 }
1680 retiring.clear(true);
1681 return true;
1682}
1683
1684void PosixSubsystem::freeMultipleFds(bool bOnlyCloExec, size_t iFirst, size_t iLast) {
1685 assert(iFirst < iLast);
1686
1687 // Table ownership is moved here before each node is erased. Destroying
1688 // this vector after unlocking performs potentially blocking descriptor
1689 // teardown outside the table critical section.
1691
1692 {
1693 Uninterruptible throughout;
1694
1695 acquireFdLock(); // Don't allow any access to the FD data
1696
1697 // Because removing FDs as we go from the Tree can actually leave the
1698 // Tree iterators in a dud state, remember all keys until traversal is
1699 // complete.
1700 List<void*> fdsToRemove;
1701
1702 // Are all FDs to be freed? Or only a selection?
1703 bool bAllToBeFreed = ((iFirst == 0 && iLast == ~0UL) && !bOnlyCloExec);
1704 if (bAllToBeFreed)
1705 m_LastFd = 0;
1706
1707 FdMap& map = m_FdMap;
1708 for (FdMap::Iterator it = map.begin(); it != map.end(); it++) {
1709 size_t Fd = it.key();
1710 SharedPointer<FileDescriptor> pFd = it.value();
1711 if (!pFd)
1712 continue;
1713
1714 if (!(Fd >= iFirst && Fd <= iLast))
1715 continue;
1716
1717 if (bOnlyCloExec) {
1718 if (!(pFd->fdflags & FD_CLOEXEC))
1719 continue;
1720 }
1721
1722 // No longer usable.
1723 m_FdBitmap.clear(Fd);
1724 fdsToRemove.pushBack(reinterpret_cast<void*>(Fd));
1725
1726 // Reset the "last freed" tracking variable, if this is lower than
1727 // it already.
1728 if (Fd < m_LastFd)
1729 m_LastFd = Fd;
1730 }
1731
1732 for (List<void*>::Iterator it = fdsToRemove.begin(); it != fdsToRemove.end(); it++) {
1734 if (m_FdMap.take(reinterpret_cast<size_t>(*it), descriptor)) {
1735 retiring.pushBack(pedigree_std::move(descriptor));
1736 }
1737 }
1738
1739 if (retiring.count()) {
1740 publishFdEntries();
1741 }
1742
1743 m_FdLock.release();
1744 }
1745
1746 for (auto& descriptor : retiring) {
1747 retireDescriptor(descriptor.get());
1748 }
1749 retiring.clear(true);
1750}
1751
1753 descriptor.reset();
1754 RcuReadGuard guard;
1755 for (auto* entry = m_FdEntries[fd % FdBuckets].load(guard); entry && entry->fd <= fd;
1756 entry = entry->next.load(guard)) {
1757 if (entry->fd == fd) {
1758 descriptor.retain(entry->descriptor);
1759 return static_cast<bool>(descriptor);
1760 }
1761 }
1762 return false;
1763}
1764
1765void PosixSubsystem::publishFdEntry(size_t fd) {
1766 auto* link = &m_FdEntries[fd % FdBuckets];
1767 FdEntry* previous = link->loadForUpdate();
1768 while (previous && previous->fd < fd) {
1769 link = &previous->next;
1770 previous = link->loadForUpdate();
1771 }
1772 FdEntry* retiring = previous && previous->fd == fd ? previous : nullptr;
1773 FdEntry* following = retiring ? retiring->next.loadForUpdate() : previous;
1774 const SharedPointer<FileDescriptor> missing;
1775 const auto& current = m_FdMap.lookupRef(fd, missing);
1776 FdEntry* replacement = following;
1777 if (current) {
1778 replacement = new FdEntry(fd, current);
1779 if (!replacement) {
1780 FATAL("PosixSubsystem could not allocate its descriptor entry");
1781 }
1782 if (following) {
1783 replacement->next.exchange(following);
1784 }
1785 }
1786
1787 link->exchange(replacement);
1788 if (retiring) {
1789 // Readers already at the removed entry still need its next link.
1790 // The caller privately owns its descriptor until after unlocking, so
1791 // releasing this entry cannot perform blocking descriptor teardown.
1792 Rcu::synchronize();
1793 delete retiring;
1794 }
1795}
1796
1797void PosixSubsystem::publishFdEntries() {
1798 RcuPointer<FdEntry> replacements[FdBuckets];
1799 RcuPointer<FdEntry>* tails[FdBuckets];
1800 FdEntry* previous[FdBuckets] = {};
1801 for (size_t bucket = 0; bucket < FdBuckets; ++bucket) {
1802 tails[bucket] = &replacements[bucket];
1803 }
1804 for (auto it = m_FdMap.begin(); it != m_FdMap.end(); ++it) {
1805 if (it.value()) {
1806 FdEntry* entry = new FdEntry(it.key(), it.value());
1807 if (!entry) {
1808 FATAL("PosixSubsystem could not allocate its descriptor entry");
1809 }
1810 const size_t bucket = it.key() % FdBuckets;
1811 tails[bucket]->exchange(entry);
1812 tails[bucket] = &entry->next;
1813 }
1814 }
1815
1816 bool reclaim = false;
1817 for (size_t bucket = 0; bucket < FdBuckets; ++bucket) {
1818 previous[bucket] = m_FdEntries[bucket].exchange(replacements[bucket].loadForUpdate());
1819 reclaim |= previous[bucket] != nullptr;
1820 }
1821 if (reclaim) {
1822 Rcu::synchronize();
1823 for (auto* entry : previous) {
1824 while (entry) {
1825 FdEntry* next = entry->next.loadForUpdate();
1826 delete entry;
1827 entry = next;
1828 }
1829 }
1830 }
1831}
1832
1833bool PosixSubsystem::acquireNextFileDescriptor(size_t minimum, size_t& fd,
1834 DescriptorLease& descriptor) {
1835 descriptor.reset();
1837 size_t selected = ~size_t(0);
1838 {
1839 Uninterruptible throughout;
1840 acquireFdLock();
1841 for (auto it = m_FdMap.begin(); it != m_FdMap.end(); ++it) {
1842 if (it.key() >= minimum && it.key() < selected && it.value()) {
1843 selected = it.key();
1844 retained = it.value();
1845 }
1846 }
1847 m_FdLock.release();
1848 }
1849 descriptor.retain(retained);
1850 if (!descriptor)
1851 return false;
1852 fd = selected;
1853 return true;
1854}
1855
1857 size_t fd, const FileDescriptor::OpenFileDescriptionLease& expected) {
1858 if (!expected) {
1859 return false;
1860 }
1861
1862 const SharedPointer<FileDescriptor> missing;
1863 Uninterruptible throughout;
1864 acquireFdLock();
1865 const SharedPointer<FileDescriptor>& current = m_FdMap.lookupRef(fd, missing);
1866 const bool matches = current && current->m_OpenFile.get() == expected.get();
1867 m_FdLock.release();
1868 return matches;
1869}
1870
1871bool PosixSubsystem::closeFileDescriptor(size_t fd, const DescriptorLease& descriptor) {
1872 if (!descriptor) {
1873 return false;
1874 }
1875
1878 bool removed = false;
1879
1880 {
1881 Uninterruptible throughout;
1882
1883 acquireFdLock();
1884 current = m_FdMap.lookup(fd);
1885 if (current == descriptor.m_Descriptor) {
1886 // Transfer the table owner rather than destroying it under the
1887 // lock. The lease supplied by close keeps the exact generation
1888 // alive while any descriptor-specific cleanup is performed.
1889 removed = m_FdMap.take(fd, retiring);
1890 if (removed) {
1891 m_FdBitmap.clear(fd);
1892 if (fd < m_LastFd) {
1893 m_LastFd = fd;
1894 }
1895 publishFdEntry(fd);
1896 }
1897 }
1898 m_FdLock.release();
1899 }
1900
1901 current.reset();
1902 if (retiring) {
1903 retireDescriptor(retiring.get());
1904 }
1905 retiring.reset();
1906 return removed;
1907}
1908
1910 SharedPointer<FileDescriptor> replacement(pFd);
1912
1913 {
1914 Uninterruptible throughout;
1915
1916 // Publish the replacement and update allocation metadata in one
1917 // critical section. The old freeFd()/allocateFd() sequence briefly
1918 // exposed fd as available and allowed another allocator to steal it.
1919 acquireFdLock();
1920
1921 m_FdMap.take(fd, retiring);
1922 if (fd >= m_NextFd)
1923 m_NextFd = fd + 1;
1924 m_FdBitmap.set(fd);
1925 m_FdMap.insert(fd, replacement);
1926 publishFdEntry(fd);
1927
1928 m_FdLock.release();
1929 }
1930
1931 if (retiring) {
1932 retireDescriptor(retiring.get());
1933 }
1934 retiring.reset();
1935}
1936
1937PosixSubsystem::DescriptorDuplicationResult PosixSubsystem::duplicateFileDescriptor(
1938 size_t sourceFd, size_t targetFd, bool closeOnExec) {
1940 SharedPointer<FileDescriptor> currentTarget;
1943 DescriptorDuplicationResult result = DescriptorDuplicationResult::BadSource;
1944
1945 {
1946 Uninterruptible throughout;
1947
1948 acquireFdLock();
1949 source = m_FdMap.lookup(sourceFd);
1950 if (source) {
1951 currentTarget = m_FdMap.lookup(targetFd);
1952 if (!currentTarget && m_FdBitmap.test(targetFd)) {
1953 // getFd reserves a number before its creator publishes the table
1954 // entry. Linux reports EBUSY rather than allowing dup3 to steal that
1955 // in-flight allocation.
1956 result = DescriptorDuplicationResult::TargetBusy;
1957 } else {
1958 replacement.reset(new FileDescriptor(*source));
1959
1960 // FileDescriptor's copy path only nests OFD/socket/eventfd owner-admission
1961 // locks, neither of which enters the descriptor table. Keeping
1962 // m_FdLock held makes final-close admission and publication atomic.
1963 if ((!source->networkImpl || replacement->networkPublished()) &&
1964 (!source->getEventFdImpl() || replacement->eventFdPublished()) &&
1965 (!source->getSignalFdImpl() || replacement->signalFdPublished()) &&
1966 (!source->getTimerFdImpl() || replacement->timerFdPublished())) {
1967 replacement->fd = targetFd;
1968 replacement->fdflags = closeOnExec ? FD_CLOEXEC : 0;
1969 m_FdMap.take(targetFd, retiring);
1970 if (targetFd >= m_NextFd) {
1971 m_NextFd = targetFd + 1;
1972 }
1973 m_FdBitmap.set(targetFd);
1974 m_FdMap.insert(targetFd, replacement);
1975 publishFdEntry(targetFd);
1976 result = DescriptorDuplicationResult::Success;
1977 }
1978 }
1979 }
1980 m_FdLock.release();
1981 }
1982
1983 source.reset();
1984 currentTarget.reset();
1985 if (retiring) {
1986 retireDescriptor(retiring.get());
1987 }
1988 retiring.reset();
1989 replacement.reset();
1990 return result;
1991}
1992
1994 size_t minimum) {
1995 SharedPointer<FileDescriptor> published(descriptor);
1996 lease.reset();
1997
1998 Uninterruptible throughout;
1999 acquireFdLock();
2000
2001 const bool advancesGlobalHint = minimum <= m_LastFd;
2002 const size_t firstCandidate = minimum > m_LastFd ? minimum : m_LastFd;
2003 size_t fd = minimum > m_NextFd ? minimum : m_NextFd;
2004 for (size_t candidate = firstCandidate; candidate < m_NextFd; ++candidate) {
2005 if (!m_FdBitmap.test(candidate)) {
2006 fd = candidate;
2007 if (advancesGlobalHint) {
2008 m_LastFd = candidate;
2009 }
2010 break;
2011 }
2012 }
2013
2014 if (fd >= m_NextFd) {
2015 m_NextFd = fd + 1;
2016 }
2017 descriptor->fd = fd;
2018 m_FdBitmap.set(fd);
2019 m_FdMap.insert(fd, published);
2020 publishFdEntry(fd);
2021 lease.retain(published);
2022
2023 m_FdLock.release();
2024 return fd;
2025}
2026
2028 PendingSignalNotification notification(m_PendingSignals);
2029 LockGuard<Mutex> pendingGuard(m_PendingSignals->lock);
2031 for (size_t i = m_pProcess->getNumThreads(); i > 0; --i) {
2032 Process::ThreadLease source;
2033 if (m_pProcess->acquireThread(source, i - 1) && source.get() != owner &&
2034 !source->transferProcessSignalsTo(*owner)) {
2035 FATAL("Exec owner rejected a pending process signal.");
2036 }
2037 }
2038 m_PendingSignals->recordChange();
2039}
2040
2042 PendingSignalNotification notification(m_PendingSignals);
2043 LockGuard<Mutex> pendingGuard(m_PendingSignals->lock);
2045 Process::ThreadLease target;
2046 while (m_pProcess->acquireProcessSignalThread(target)) {
2047 if (thread->transferProcessSignalsTo(*target.get())) {
2048 m_PendingSignals->recordChange();
2049 return;
2050 }
2051 }
2052}
2053
2054void PosixSubsystem::retireDescriptor(FileDescriptor* descriptor) {
2055 if (descriptor->getFile()) {
2056 posix_advisory_descriptor_closed(m_AdvisoryOwner, descriptor->getFile()->futexIdentity());
2057 }
2058 // Queue descriptors have no VFS backing. File retirement must not wait for
2059 // an in-flight operation holding the shared file-position mutex.
2060 if (!descriptor->getFile()) {
2061 SharedPointer<PosixMessageQueue> queue = descriptor->getMqueueImpl();
2062 if (queue && m_pProcess) {
2063 posix_mqueue_close(queue.get(), m_pProcess->getId());
2064 }
2065 }
2066 descriptor->unpublish();
2067}
2068
2070 if (!pThread) {
2071 return;
2072 }
2073 m_TraceContext.retireTask(*pThread);
2074
2075 if (m_Namespaces) {
2076 const size_t taskId = pThread->getTaskId();
2077 m_Namespaces->retireThread(*pThread);
2078 procfsInvalidateNamespaceTask(m_Namespaces, pThread->getParent()->getUserspaceId(), taskId);
2079 }
2080 m_PendingSignals->retireThread(pThread);
2081 posix_timer_thread_exit(pThread);
2082 posix_sem_thread_exit(pThread);
2083 posix_robust_list_exit(pThread);
2084
2085 clearChildTid(pThread);
2086}
2087
2088void PosixSubsystem::clearChildTid(Thread* pThread) {
2089 const uintptr_t address = pThread->takeClearChildTid();
2090 if (!address) {
2091 return;
2092 }
2093
2094 Process* process = pThread->getParent();
2095 if (!process) {
2096 return;
2097 }
2098
2099 const bool cleared = posix_clear_child_tid(process, address);
2100 if (!cleared) {
2101 PS_NOTICE("clear-child-TID could not access target at " << Hex << address << " for tid " << Dec
2102 << pThread->getId());
2103 }
2104
2105 // The registration is already consumed. Wake even if the restricted
2106 // validated store could not reach the word, so no waiter is stranded in the
2107 // kernel after an invalid registration or concurrent unmap.
2108 // Process clones can register a word in a shared file mapping. Retain the
2109 // private-key fallback used by existing pthread callers.
2110 if (!posix_futex_wake(process, reinterpret_cast<int*>(address), 1, false))
2111 posix_futex_wake(process, reinterpret_cast<int*>(address), 1);
2112}
2113
2115 for (Tree<size_t, PosixThread*>::Iterator it = m_Threads.begin(); it != m_Threads.end(); it++) {
2116 PosixThread* thread = it.value();
2117 if (thread->pThread != pThread)
2118 continue;
2119
2120 // Can safely assert that this thread is no longer running.
2121 // We do not however kill the thread object yet. It can be cleaned up
2122 // when the PosixSubsystem quits (if this was the last thread). Or, it
2123 // will be cleaned up by a join().
2124 thread->isRunning.complete();
2125 break;
2126 }
2127}
2128
2129bool PosixSubsystem::checkAccess(const DescriptorLease& pFileDescriptor, bool bRead, bool bWrite,
2130 bool bExecute) const {
2131 return VFS::checkAccess(pFileDescriptor->getFile(), bRead, bWrite, bExecute);
2132}
2133
2134bool PosixSubsystem::prepareExecutable(File* pFile, ExecutableImage& image, bool isInterpreter) {
2135 // Keep validation and all PT_LOAD segments on the same immutable contents.
2136 if (!pFile->acquireMappingUse(true, false))
2137 return false;
2138 image.file = pFile;
2139 image.fileSize = pFile->getSize();
2140
2141 uint8_t header[sizeof(Elf::ElfHeader_t)];
2142 if (pFile->read(0, sizeof(header), reinterpret_cast<uintptr_t>(header)) != sizeof(header)) {
2143 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2144 return false;
2145 }
2146
2147 Elf::ExecutableValidationResult result =
2148 Elf::validateExecutableHeader(header, sizeof(header), image.fileSize, image.metadata);
2149 if (result != Elf::ExecutableValidationResult::Valid) {
2150 setExecutableValidationError(result, isInterpreter);
2151 return false;
2152 }
2153
2154 image.programHeaders = UniqueArray<uint8_t>::allocate(image.metadata.programHeaderSize);
2155 if (!image.programHeaders) {
2156 SYSCALL_ERROR(OutOfMemory);
2157 return false;
2158 }
2159 if (pFile->read(image.metadata.programHeaderOffset, image.metadata.programHeaderSize,
2160 reinterpret_cast<uintptr_t>(image.programHeaders.get())) !=
2161 image.metadata.programHeaderSize) {
2162 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2163 return false;
2164 }
2165
2167 image.programHeaders.get(), image.metadata.programHeaderSize, image.fileSize, image.metadata);
2168 if (result != Elf::ExecutableValidationResult::Valid) {
2169 setExecutableValidationError(result, isInterpreter);
2170 return false;
2171 }
2172
2173 VirtualAddressSpace& addressSpace = Processor::information().getVirtualAddressSpace();
2174 if (image.metadata.type == ET_EXEC &&
2175 (image.metadata.loadStart < addressSpace.getUserStart() ||
2176 image.metadata.loadEnd > addressSpace.getUserReservedStart())) {
2177 setExecutableValidationError(Elf::ExecutableValidationResult::UnsupportedLayout, isInterpreter);
2178 return false;
2179 }
2180
2181 bool foundProgramHeaders = false;
2182 for (size_t i = 0; i < image.metadata.programHeaderCount; ++i) {
2183 Elf::ElfProgramHeader_t programHeader;
2184 MemoryCopy(&programHeader, image.programHeaders.get() + (i * sizeof(Elf::ElfProgramHeader_t)),
2185 sizeof(programHeader));
2186 if (programHeader.type != PT_LOAD ||
2187 image.metadata.programHeaderOffset < programHeader.offset) {
2188 continue;
2189 }
2190
2191 const size_t offsetInSegment = image.metadata.programHeaderOffset - programHeader.offset;
2192 if (offsetInSegment > programHeader.filesz ||
2193 image.metadata.programHeaderSize > programHeader.filesz - offsetInSegment ||
2194 programHeader.vaddr > ~uintptr_t{0} - offsetInSegment) {
2195 continue;
2196 }
2197
2198 image.programHeaderAddress = programHeader.vaddr + offsetInSegment;
2199 foundProgramHeaders = true;
2200 break;
2201 }
2202 if (!foundProgramHeaders) {
2203 setExecutableValidationError(Elf::ExecutableValidationResult::UnsupportedLayout, isInterpreter);
2204 return false;
2205 }
2206
2207 if (!image.metadata.hasInterpreter) {
2208 return true;
2209 }
2210
2211 UniqueArray<uint8_t> interpreter = UniqueArray<uint8_t>::allocate(image.metadata.interpreterSize);
2212 if (!interpreter) {
2213 SYSCALL_ERROR(OutOfMemory);
2214 return false;
2215 }
2216 if (pFile->read(image.metadata.interpreterOffset, image.metadata.interpreterSize,
2217 reinterpret_cast<uintptr_t>(interpreter.get())) !=
2218 image.metadata.interpreterSize) {
2219 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2220 return false;
2221 }
2222
2223 result = Elf::validateExecutableInterpreter(interpreter.get(), image.metadata.interpreterSize,
2224 image.metadata);
2225 if (result != Elf::ExecutableValidationResult::Valid) {
2226 setExecutableValidationError(result, isInterpreter);
2227 return false;
2228 }
2229 for (size_t i = 0; i + 1 < image.metadata.interpreterSize; ++i) {
2230 if (!interpreter.get()[i]) {
2231 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2232 return false;
2233 }
2234 }
2235
2236 image.interpreter.assign(reinterpret_cast<const char*>(interpreter.get()),
2237 image.metadata.interpreterSize - 1, true);
2238 return true;
2239}
2240
2241bool PosixSubsystem::loadElf(const ExecutableImage& image, uintptr_t& loadBias) {
2242 PS_NOTICE("PosixSubsystem::loadElf(" << image.file->getName() << ")");
2243
2244 Elf::ExecutableMetadata metadata = image.metadata;
2245 if (Elf::validateExecutableProgramHeaders(image.programHeaders.get(),
2246 image.metadata.programHeaderSize, image.fileSize,
2247 metadata) != Elf::ExecutableValidationResult::Valid) {
2248 return false;
2249 }
2250
2251 Process* pProcess = Processor::information().getCurrentThread()->getParent();
2252 const size_t allocationSize = metadata.loadEnd - metadata.loadStart;
2253 if (metadata.type == ET_DYN) {
2254 uintptr_t allocation = 0;
2255 if (!pProcess->allocateUserRange(Process::UserRegion::Dynamic, allocationSize, allocation) &&
2256 !pProcess->allocateUserRange(Process::UserRegion::Normal, allocationSize, allocation)) {
2257 return false;
2258 }
2259 loadBias = allocation - metadata.loadStart;
2260 } else {
2261 if (!pProcess->allocateSpecificUserRange(Process::UserRegion::Normal, metadata.loadStart,
2262 allocationSize)) {
2263 return false;
2264 }
2265 loadBias = 0;
2266 }
2267
2268 const size_t pageSize = PhysicalMemoryManager::getPageSize();
2269 const uintptr_t pageMask = pageSize - 1;
2270 for (size_t i = 0; i < metadata.programHeaderCount; ++i) {
2271 Elf::ElfProgramHeader_t programHeader;
2272 MemoryCopy(&programHeader, image.programHeaders.get() + (i * sizeof(Elf::ElfProgramHeader_t)),
2273 sizeof(programHeader));
2274 if (programHeader.type != PT_LOAD || !programHeader.memsz) {
2275 continue;
2276 }
2277
2278 if (programHeader.vaddr > ~uintptr_t{0} - loadBias) {
2279 return false;
2280 }
2281 const uintptr_t segmentAddress = loadBias + programHeader.vaddr;
2282 const uintptr_t pageOffset = segmentAddress & pageMask;
2283 if (programHeader.memsz > ~size_t{0} - pageOffset) {
2284 return false;
2285 }
2286 size_t length = programHeader.memsz + pageOffset;
2287 if (length > ~size_t{0} - pageMask) {
2288 return false;
2289 }
2290 length = (length + pageMask) & ~pageMask;
2291
2292 uintptr_t base = segmentAddress & ~pageMask;
2293 const size_t fileOffset = programHeader.offset & ~pageMask;
2294 MemoryMappedObject::Permissions perms = MemoryMappedObject::Read;
2295 if (programHeader.flags & PF_X) {
2296 perms |= MemoryMappedObject::Exec;
2297 }
2298 if (programHeader.flags & PF_W) {
2299 perms |= MemoryMappedObject::Write;
2300 }
2301
2302 const uintptr_t fileEnd = segmentAddress + programHeader.filesz;
2303 const bool hasPartialBssPage =
2304 programHeader.memsz > programHeader.filesz && (fileEnd & pageMask) != 0;
2305 MemoryMappedObject::Permissions mappingPerms = perms;
2306 if (hasPartialBssPage) {
2307 mappingPerms |= MemoryMappedObject::Write;
2308 }
2309
2310 PS_NOTICE(image.file->getName()
2311 << " PHDR[" << i << "]: @" << Hex << base << " -> " << base + length);
2312 const FileMappingOrigin origin{0, false, image.openingPath};
2313 if (!MemoryMapManager::instance().mapFile(
2314 image.file, base, length, mappingPerms, fileOffset, true,
2315 MemoryMapManager::Placement::FixedReplace, nullptr,
2316 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec,
2317 SharedPointer<MappingAttachment>(), MemoryLockMode::None, origin)) {
2318 ERROR("PosixSubsystem::loadElf: failed to map PT_LOAD section");
2319 return false;
2320 }
2321
2322 if (programHeader.memsz > programHeader.filesz) {
2323 const uintptr_t end = segmentAddress + programHeader.memsz;
2324 uintptr_t zeroStart = segmentAddress + programHeader.filesz;
2325 if (hasPartialBssPage) {
2326 const size_t numBytes = pageSize - (zeroStart & pageMask);
2327 ByteSet(reinterpret_cast<void*>(zeroStart), 0, numBytes);
2328 zeroStart += numBytes;
2329 }
2330
2331 if (zeroStart < end) {
2332 uintptr_t anonymousAddress = zeroStart;
2333 if (!MemoryMapManager::instance().mapAnon(anonymousAddress, end - zeroStart,
2334 mappingPerms)) {
2335 ERROR(
2336 "PosixSubsystem::loadElf: failed to map anonymous "
2337 "pages for filesz/memsz mismatch");
2338 return false;
2339 }
2340 }
2341 }
2342
2343 if (hasPartialBssPage && !MemoryMapManager::instance().setPermissions(base, length, perms)) {
2344 ERROR("PosixSubsystem::loadElf: failed to restore PT_LOAD permissions");
2345 return false;
2346 }
2347 }
2348
2349 return true;
2350}
2351
2352ResolvedPath::~ResolvedPath() {
2353 reset();
2354}
2355
2356void ResolvedPath::reset() {
2357 Thread* thread = Processor::information().getCurrentThread();
2358 const size_t error = thread ? thread->getErrno() : 0;
2359 m_Path.reset();
2360 if (thread)
2361 thread->setErrno(error);
2362}
2363
2364void ResolvedPath::retain(const FilesystemPathRef& path) {
2365 if (m_Path.get() == path.get())
2366 return;
2367 auto retired = pedigree_std::move(m_Path);
2368 m_Path = path;
2369 Thread* thread = Processor::information().getCurrentThread();
2370 const size_t error = thread ? thread->getErrno() : 0;
2371 retired.reset();
2372 if (thread)
2373 thread->setErrno(error);
2374}
2375
2376File* PosixSubsystem::findFileRetained(const String& path, ResolvedPath& result,
2377 const FilesystemPathRef& workingDir, bool followFinal) {
2378 auto context = m_pProcess ? m_pProcess->acquireFilesystemContext() : FilesystemContextRef();
2379 auto* view = VFS::instance().mountView();
2380 if (!context || !view) {
2381 SYSCALL_ERROR(DoesNotExist);
2382 return nullptr;
2383 }
2384 FilesystemPathRef selected;
2386 options.followFinal = followFinal;
2387 if (!view->resolve(context, workingDir, path, options, selected))
2388 return nullptr;
2389 result.retain(selected);
2390 syscallError(0);
2391 return result.get();
2392}
2393
2394File* PosixSubsystem::followFile(ResolvedPath& selected) {
2395 if (!selected) {
2396 SYSCALL_ERROR(DoesNotExist);
2397 return nullptr;
2398 }
2399 if (!selected.get()->isSymlink())
2400 return selected.get();
2401 auto context = m_pProcess ? m_pProcess->acquireFilesystemContext() : FilesystemContextRef();
2402 auto* view = VFS::instance().mountView();
2403 FilesystemPathRef followed;
2404 if (!context || !view || !view->follow(context, selected.path(), followed))
2405 return nullptr;
2406 selected.retain(followed);
2407 syscallError(0);
2408 return selected.get();
2409}
2410
2411#define STACK_PUSH(stack, value) *--stack = value
2412#define STACK_PUSH2(stack, value1, value2) \
2413 STACK_PUSH(stack, value1); \
2414 STACK_PUSH(stack, value2)
2415#define STACK_PUSH_COPY(stack, value, length) \
2416 stack = adjust_pointer(stack, -(length)); \
2417 MemoryCopy(stack, value, length)
2418#define STACK_PUSH_STRING(stack, str, length) \
2419 stack = adjust_pointer(stack, -(length)); \
2420 StringCopyN(reinterpret_cast<char*>(stack), str, length)
2421#define STACK_PUSH_ZEROES(stack, length) \
2422 stack = adjust_pointer(stack, -(length)); \
2423 ByteSet(stack, 0, length)
2424#define STACK_ALIGN(stack, to) \
2425 STACK_PUSH_ZEROES(stack, (to) - ((to) - (reinterpret_cast<uintptr_t>(stack) & ((to) - 1))))
2426
2427bool PosixSubsystem::invoke(const char* name, Vector<String>& argv, Vector<String>& env) {
2428 return invoke(name, argv, env, 0);
2429}
2430
2431bool PosixSubsystem::invoke(const char* name, Vector<String>& argv, Vector<String>& env,
2432 SyscallState& state) {
2433 return invoke(name, argv, env, &state);
2434}
2435
2436bool PosixSubsystem::parseShebang(File* pFile, String& interpreter, String& optionalArgument,
2437 bool& hasOptionalArgument) {
2438 PS_NOTICE("Attempting to parse shebang in " << pFile->getFullPath());
2439
2440 static constexpr size_t ShebangBufferSize = 256;
2441 char contents[ShebangBufferSize];
2442 const size_t bytesRead = pFile->read(0, sizeof(contents), reinterpret_cast<uintptr_t>(contents));
2443
2444 interpreter.clear();
2445 optionalArgument.clear();
2446 hasOptionalArgument = false;
2447
2448 if (bytesRead < 2 || contents[0] != '#' || contents[1] != '!') {
2449 PS_NOTICE("no shebang found");
2450 return true;
2451 }
2452
2453 size_t lineEnd = bytesRead;
2454 bool terminated = bytesRead < sizeof(contents);
2455 for (size_t i = 2; i < bytesRead; ++i) {
2456 if (contents[i] == '\n' || !contents[i]) {
2457 lineEnd = i;
2458 terminated = true;
2459 break;
2460 }
2461 }
2462
2463 const size_t boundedLineEnd = lineEnd;
2464 while (lineEnd > 2 && (contents[lineEnd - 1] == ' ' || contents[lineEnd - 1] == '\t')) {
2465 --lineEnd;
2466 }
2467
2468 size_t interpreterBegin = 2;
2469 while (interpreterBegin < lineEnd &&
2470 (contents[interpreterBegin] == ' ' || contents[interpreterBegin] == '\t')) {
2471 ++interpreterBegin;
2472 }
2473 if (interpreterBegin == lineEnd) {
2474 PS_NOTICE("empty shebang interpreter");
2475 SYSCALL_ERROR(ExecFormatError);
2476 return false;
2477 }
2478
2479 size_t interpreterEnd = interpreterBegin;
2480 while (interpreterEnd < lineEnd && contents[interpreterEnd] != ' ' &&
2481 contents[interpreterEnd] != '\t') {
2482 ++interpreterEnd;
2483 }
2484 if (interpreterEnd == lineEnd && lineEnd == boundedLineEnd && !terminated) {
2485 PS_NOTICE("truncated shebang interpreter");
2486 SYSCALL_ERROR(ExecFormatError);
2487 return false;
2488 }
2489
2490 interpreter.assign(contents + interpreterBegin, interpreterEnd - interpreterBegin, true);
2491
2492 size_t argumentBegin = interpreterEnd;
2493 while (argumentBegin < lineEnd &&
2494 (contents[argumentBegin] == ' ' || contents[argumentBegin] == '\t')) {
2495 ++argumentBegin;
2496 }
2497 if (argumentBegin < lineEnd) {
2498 optionalArgument.assign(contents + argumentBegin, lineEnd - argumentBegin, true);
2499 hasOptionalArgument = true;
2500 }
2501
2502 return true;
2503}
2504
2505static File* executableFile(File* file) {
2506 if (!file) {
2507 SYSCALL_ERROR(DoesNotExist);
2508 return nullptr;
2509 }
2510 if (file->isDirectory()) {
2511 SYSCALL_ERROR(IsADirectory);
2512 return nullptr;
2513 }
2514 // File-only callers must supply an already-selected target. Traversal needs
2515 // the opening attachment and cannot be reconstructed from an inode pointer.
2516 if (file->isSymlink()) {
2517 SYSCALL_ERROR(ExecFormatError);
2518 return nullptr;
2519 }
2520 return file;
2521}
2522
2523bool PosixSubsystem::invoke(const char* name, Vector<String>& argv, Vector<String>& env,
2524 SyscallState* state) {
2525 // Save the original name before we trash the old stack.
2526 String originalName(name);
2527
2528 // Try and find the target file we want to invoke.
2529 ResolvedPath originalLease;
2530 File* originalFile = findFileRetained(originalName, originalLease, FilesystemPathRef(), true);
2531 if (!originalFile) {
2532 PS_NOTICE("PosixSubsystem::invoke: could not find file '" << originalName << "'");
2533 SYSCALL_ERROR(DoesNotExist);
2534 return false;
2535 }
2536
2537 return invoke(originalFile, originalName, argv, env, state, false, originalLease.path());
2538}
2539
2540bool PosixSubsystem::invoke(File* originalFile, const String& originalName, Vector<String>& argv,
2541 Vector<String>& env) {
2542 return invoke(originalFile, originalName, argv, env, 0);
2543}
2544
2545bool PosixSubsystem::invoke(File* originalFile, const String& originalName, Vector<String>& argv,
2546 Vector<String>& env, SyscallState& state) {
2547 return invoke(originalFile, originalName, argv, env, &state, false);
2548}
2549
2550bool PosixSubsystem::invoke(File* originalFile, const String& originalName, Vector<String>& argv,
2551 Vector<String>& env, SyscallState& state,
2552 bool descriptorPathInaccessible) {
2553 return invoke(originalFile, originalName, argv, env, &state, descriptorPathInaccessible);
2554}
2555
2556bool PosixSubsystem::invoke(const FilesystemPathRef& originalPath, const String& originalName,
2557 Vector<String>& argv, Vector<String>& env, SyscallState& state,
2558 bool descriptorPathInaccessible) {
2559 return invoke(originalPath ? originalPath->node() : nullptr, originalName, argv, env, &state,
2560 descriptorPathInaccessible, originalPath);
2561}
2562
2563bool PosixSubsystem::invoke(File* originalFile, const String& originalName, Vector<String>& argv,
2564 Vector<String>& env, SyscallState* state,
2565 bool descriptorPathInaccessible,
2566 const FilesystemPathRef& originalPath) {
2567 PS_NOTICE("PosixSubsystem::invoke(" << originalName << ")");
2568
2569 uint8_t execRandom[16];
2570 ByteSet(execRandom, 0, sizeof(execRandom));
2571#if X64 && !HOSTED
2572 const bool hasExecRandom =
2573 secure_random_bytes(execRandom, sizeof(execRandom)) == sizeof(execRandom);
2574 if (!hasExecRandom) {
2575 PS_NOTICE("PosixSubsystem::invoke: AT_RANDOM unavailable until secure randomness is seeded");
2576 }
2577#else
2578 const bool hasExecRandom = false;
2579#endif
2580
2581 Thread* pThread = Processor::information().getCurrentThread();
2582 Process* pProcess = pThread->getParent();
2583 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
2584
2585 Process::ExecScope execScope(*pProcess, state != nullptr);
2586 if (!execScope) {
2587 SYSCALL_ERROR(NoMoreProcesses);
2588 return false;
2589 }
2590
2591 ResolvedPath originalTargetLease;
2592 originalTargetLease.retain(originalPath);
2593 originalFile = executableFile(originalFile);
2594 if (!originalFile) {
2595 return false;
2596 }
2597
2598 uint8_t magic[4];
2599 String candidateName(originalName);
2600 static constexpr size_t MaximumShebangRewrites = 4;
2601 size_t shebangRewrites = 0;
2602 bool allExecutableFilesReadable = true;
2603 while (true) {
2604 // Execute permission checks precede all format reads for every candidate,
2605 // including nested shebang interpreters.
2606 if (!VFS::checkAccess(originalFile, false, false, true)) {
2607 return false;
2608 }
2609 auto* executableView = VfsMountView::fromPath(originalTargetLease.path());
2610 if (executableView &&
2611 (executableView->mountFlags(originalTargetLease.path()) & VfsMountView::NoExec)) {
2612 SYSCALL_ERROR(PermissionDenied);
2613 return false;
2614 }
2615 if (!posix_landlock_check(originalTargetLease.path(),
2616 LandlockAccess::Execute | LandlockAccess::ReadFile)) {
2617 return false;
2618 }
2619 allExecutableFilesReadable &= posix_exec_file_readable(originalFile);
2620
2621 const size_t bytesRead =
2622 originalFile->read(0, sizeof(magic), reinterpret_cast<uintptr_t>(magic));
2623 if (bytesRead == sizeof(magic) && magic[0] == 0x7f && magic[1] == 'E' && magic[2] == 'L' &&
2624 magic[3] == 'F') {
2625 break;
2626 }
2627
2628 PS_NOTICE("PosixSubsystem::invoke: '" << originalFile->getName()
2629 << "' is not an ELF binary, looking for shebang...");
2630
2631 String shebangInterpreter;
2632 String shebangArgument;
2633 bool hasShebangArgument = false;
2634 if (!parseShebang(originalFile, shebangInterpreter, shebangArgument, hasShebangArgument)) {
2635 PS_NOTICE("PosixSubsystem::invoke: failed to parse shebang line in '"
2636 << originalFile->getName() << "'");
2637 return false;
2638 }
2639
2640 if (!shebangInterpreter.length()) {
2641 SYSCALL_ERROR(ExecFormatError);
2642 return false;
2643 }
2644
2645 if (!shebangRewrites && descriptorPathInaccessible) {
2646 // The interpreter would reopen a descriptor closed at exec commit.
2647 SYSCALL_ERROR(DoesNotExist);
2648 return false;
2649 }
2650
2651 if (shebangRewrites == MaximumShebangRewrites) {
2652 SYSCALL_ERROR(LoopExists);
2653 return false;
2654 }
2655 ++shebangRewrites;
2656
2657 String resolvedInterpreter(shebangInterpreter);
2658 String normalisedInterpreter;
2659 if (normalisePath(normalisedInterpreter, resolvedInterpreter.cstr())) {
2660 resolvedInterpreter = normalisedInterpreter;
2661 }
2662
2663 ResolvedPath nextLease;
2664 File* shebangFile = findFileRetained(resolvedInterpreter, nextLease, FilesystemPathRef(), true);
2665 if (!shebangFile) {
2666 PS_NOTICE("PosixSubsystem::invoke: could not find shebang interpreter '"
2667 << resolvedInterpreter << "'");
2668 SYSCALL_ERROR(DoesNotExist);
2669 return false;
2670 }
2671
2672 shebangFile = executableFile(shebangFile);
2673 if (!shebangFile) {
2674 return false;
2675 }
2676
2677 if (argv.count()) {
2678 argv.popFront();
2679 }
2680 argv.pushFront(candidateName);
2681 if (hasShebangArgument) {
2682 argv.pushFront(shebangArgument);
2683 }
2684 argv.pushFront(shebangInterpreter);
2685
2686 originalFile = shebangFile;
2687 candidateName = shebangInterpreter;
2688 originalTargetLease.swap(nextLease);
2689 }
2690
2691 // Recheck after shebang rewriting, which adds kernel-owned arguments.
2692 // The budget includes the vectors and AT_EXECFN's copied string.
2693 size_t argumentBytes = 2 * sizeof(uintptr_t);
2694 if (originalName.length() >= MaximumExecArgumentBytes - argumentBytes) {
2695 SYSCALL_ERROR(TooBig);
2696 return false;
2697 }
2698 argumentBytes += originalName.length() + 1;
2699 Vector<String>* argumentLists[] = {&argv, &env};
2700 for (Vector<String>* list : argumentLists) {
2701 for (size_t i = 0; i < list->count(); ++i) {
2702 const size_t remaining = MaximumExecArgumentBytes - argumentBytes;
2703 if (remaining <= sizeof(uintptr_t) || (*list)[i].length() >= remaining - sizeof(uintptr_t)) {
2704 SYSCALL_ERROR(TooBig);
2705 return false;
2706 }
2707 argumentBytes += sizeof(uintptr_t) + (*list)[i].length() + 1;
2708 }
2709 }
2710
2711 ResolvedPath interpreterLease;
2712 File* interpreterFile = 0;
2713
2714 // A failed validation path must restore both event and termination
2715 // delivery, while a successful exec keeps both deferred until the new
2716 // userspace transition has been scheduled.
2717 Uninterruptible execCriticalSection;
2718
2719 ExecutableImage originalImage;
2720 originalImage.openingPath = originalTargetLease.path();
2721 if (!prepareExecutable(originalFile, originalImage, false)) {
2722 return false;
2723 }
2724
2725 ExecutableImage interpreterImage;
2726 if (originalImage.metadata.hasInterpreter) {
2727 String interpreter(originalImage.interpreter);
2728
2729 // Existing binaries and PUP packages may still name the interpreter
2730 // using Pedigree's pre-FHS layout.
2731 String normalisedInterpreter;
2732 if (normalisePath(normalisedInterpreter, interpreter.cstr())) {
2733 interpreter = normalisedInterpreter;
2734 }
2735
2736 // Ensure we can actually find the interpreter.
2737 interpreterFile = findFileRetained(interpreter, interpreterLease, FilesystemPathRef(), true);
2738 interpreterFile = executableFile(interpreterFile);
2739 if (!interpreterFile) {
2740 PS_NOTICE("PosixSubsystem::invoke: could not find interpreter '" << interpreter << "'");
2741 return false;
2742 }
2743
2744 if (!VFS::checkAccess(interpreterFile, false, false, true)) {
2745 return false;
2746 }
2747 auto* executableView = VfsMountView::fromPath(interpreterLease.path());
2748 if (executableView &&
2749 (executableView->mountFlags(interpreterLease.path()) & VfsMountView::NoExec)) {
2750 SYSCALL_ERROR(PermissionDenied);
2751 return false;
2752 }
2753 if (!posix_landlock_check(interpreterLease.path(),
2754 LandlockAccess::Execute | LandlockAccess::ReadFile)) {
2755 return false;
2756 }
2757 allExecutableFilesReadable &= posix_exec_file_readable(interpreterFile);
2758
2759 interpreterImage.openingPath = interpreterLease.path();
2760 if (!prepareExecutable(interpreterFile, interpreterImage, true)) {
2761 return false;
2762 }
2763 if (interpreterImage.metadata.hasInterpreter) {
2764 SYSCALL_ERROR(BadSharedLibrary);
2765 return false;
2766 }
2767 } else {
2768 // Static binaries enter at their own entry point. Loading the target
2769 // again as its own interpreter would reserve every PT_LOAD range twice.
2770 interpreterFile = 0;
2771 }
2772
2773 if (interpreterFile && originalImage.metadata.type == ET_EXEC &&
2774 interpreterImage.metadata.type == ET_EXEC &&
2775 originalImage.metadata.loadStart < interpreterImage.metadata.loadEnd &&
2776 interpreterImage.metadata.loadStart < originalImage.metadata.loadEnd) {
2777 SYSCALL_ERROR(BadSharedLibrary);
2778 return false;
2779 }
2780
2783 if (!m_Namespaces || !m_Namespaces->valid()) {
2784 SYSCALL_ERROR(OutOfMemory);
2785 return false;
2786 }
2787 if (!state) {
2788 if (m_TraceContext.prepareTask(initialTrace) != TraceStatus::Success) {
2789 SYSCALL_ERROR(OutOfMemory);
2790 return false;
2791 }
2792 UtsRef currentUts;
2793 if (!m_Namespaces->acquireThread(*pThread, currentUts)) {
2794 posix_uts_error(UtsStatus::Missing);
2795 return false;
2796 }
2797 const UtsStatus prepared = posix_uts_prepare_thread(currentUts, false, initialUts);
2798 if (prepared != UtsStatus::Success) {
2799 posix_uts_error(prepared);
2800 return false;
2801 }
2802 }
2803
2804 Vector<String> committedCommandLine = argv;
2805
2806 // Validation leaves the old process intact. Siblings must finish their
2807 // user-memory exit hooks and release their mappings before replacement.
2808 if (!execScope.commit()) {
2809 SYSCALL_ERROR(Interrupted);
2810 return false;
2811 }
2812
2813 if (pProcess->getType() == Process::Posix)
2814 static_cast<PosixProcess*>(pProcess)->markExecCommitted();
2815
2816 {
2817 LockGuard<Mutex> image(m_ImageMetadataLock);
2818 m_ExecutablePath = originalTargetLease.path();
2819 m_CommandLine = pedigree_std::move(committedCommandLine);
2820 }
2821
2822 invalidateUserImage();
2823
2824 posix_timer_process_exit(pProcess);
2825
2826 // A descriptor can survive exec after clearing FD_CLOEXEC, but its old
2827 // image's notification registration must not target the replacement image.
2828 posix_mqueue_process_exit(pProcess->getId());
2829
2830 // Wipe out old address space.
2831 // Earlier failures preserve the registration. From this irreversible
2832 // point onward its target belongs to the discarded image.
2833 if (pProcess->isVforkChild())
2834 clearChildTid(pThread);
2835 else
2836 pThread->setClearChildTid(0);
2837 posix_robust_list_exit(pThread);
2838 const size_t previousTaskId = pThread->getTaskId();
2839 execScope.adoptLeaderIdentity();
2840 m_Namespaces->promoteExec(*pThread);
2841 m_TraceContext.promoteExec(*pThread);
2842 {
2843 TraceRelationRef trace;
2844 if (m_TraceContext.acquireIncoming(trace))
2845 trace->imageCommitted();
2846 }
2847 procfsInvalidateNamespaceTask(m_Namespaces, pProcess->getUserspaceId(), previousTaskId);
2848 procfsInvalidateNamespaceTask(m_Namespaces, pProcess->getUserspaceId(), pProcess->getId());
2849 DynamicLinker* oldLinker = pProcess->getLinker();
2850 pProcess->setLinker(nullptr);
2851 {
2853 // Exec is irreversible here. Old continuations cannot resume, and the
2854 // clean user-return gate runs only after their remaining cleanup.
2855 if (m_CallbackSchedulingDomain == CallbackSchedulingDomain::LegacySignals)
2856 m_CallbackSchedulingDomain = CallbackSchedulingDomain::Unrestricted;
2857 pProcess->releaseVforkAddressSpace();
2859 delete oldLinker;
2860
2861 // We now need to clean up the process' address space.
2862 pProcess->resetUserReservations();
2863 pProcess->getAddressSpace()->rawUserMemory().clear();
2864 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
2866 pProcess->getAddressSpace()->rawUserMemory().setCompleteInventory(X64 && !HOSTED);
2867 }
2868
2869 // The old mappings are gone, but Thread state levels still own their Stack
2870 // descriptors. Drop only that metadata: freeStack could otherwise unmap a
2871 // replacement mapping which reuses an old stack address.
2873
2874 // Pending signal deliveries must no longer refer to handlers in the old
2875 // image before any post-commit operation can fail and unwind this call.
2876 pedigree_init_sigret();
2877
2878 auto failAfterCommit = [pThread](Error::PosixError error) {
2879 syscallError(error);
2880 pThread->deferSignalExit(SIGSEGV);
2881 return false;
2882 };
2883
2884 // Load the target application first.
2885 uintptr_t originalLoadBias = 0;
2886 if (!loadElf(originalImage, originalLoadBias)) {
2887 PS_NOTICE("PosixSubsystem::invoke: failed to load target");
2888 return failAfterCommit(Error::OutOfMemory);
2889 }
2890
2891 // Now load the interpreter.
2892 uintptr_t interpreterLoadBias = 0;
2893 if (interpreterFile && !loadElf(interpreterImage, interpreterLoadBias)) {
2894 PS_NOTICE("PosixSubsystem::invoke: failed to load interpreter");
2895 return failAfterCommit(Error::OutOfMemory);
2896 }
2897
2898 const uintptr_t originalEntryPoint = originalLoadBias + originalImage.metadata.entryPoint;
2899 uintptr_t interpreterEntryPoint = 0;
2900 if (interpreterFile) {
2901 interpreterEntryPoint = interpreterLoadBias + interpreterImage.metadata.entryPoint;
2902 }
2903 if (!interpreterFile) {
2904 interpreterEntryPoint = originalEntryPoint;
2905 }
2906
2907 // Past point of no return, so set up the process for the new image.
2908 pProcess->description() = originalName;
2909 pProcess->resetCounts();
2910 pThread->resetTlsBase();
2911 if (pSubsystem)
2912 pSubsystem->freeMultipleFds(true);
2913 PosixProcess::CredentialSnapshot execCredentials;
2914 if (pProcess->getType() == Process::Posix) {
2915 PosixProcess* p = static_cast<PosixProcess*>(pProcess);
2917 p->commitExecCredentials(*pThread, allExecutableFilesReadable);
2918 execCredentials = p->snapshotCredentials();
2919 if (!posix_capabilities_exec(*pThread, execCredentials.euid)) {
2920 return failAfterCommit(Error::OutOfMemory);
2921 }
2922 } else {
2923 execCredentials.ruid = pProcess->getUserId();
2924 execCredentials.euid = pProcess->getEffectiveUserId();
2925 execCredentials.rgid = pProcess->getGroupId();
2926 execCredentials.egid = pProcess->getEffectiveGroupId();
2927 }
2928
2929#if !ARM64 && !ARMV7
2930 // Allocate some space for the VDSO
2932 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec;
2933 uintptr_t vdsoAddress = 0;
2935 vdsoAddress, __vdso_so_pages * PhysicalMemoryManager::getPageSize(), vdsoPerms);
2936 if (!pVdso) {
2937 PS_NOTICE("PosixSubsystem::invoke: failed to map VDSO");
2938 } else {
2939 // All good, copy in the VDSO ELF image now.
2940 MemoryCopy(reinterpret_cast<void*>(vdsoAddress), __vdso_so, __vdso_so_len);
2941
2942 // Readjust permissions to remove write access now that the image is
2943 // loaded.
2944 MemoryMapManager::instance().setPermissions(
2945 vdsoAddress, __vdso_so_pages * PhysicalMemoryManager::getPageSize(),
2946 vdsoPerms & ~MemoryMappedObject::Write);
2947 }
2948#endif
2949
2950// The hosted process owns the Linux host's fixed vsyscall address. Its musl
2951// userspace uses the syscall bridge instead.
2952#if X64 && !HOSTED
2953 // Map in the vsyscall space.
2954 if (!Processor::information().getVirtualAddressSpace().isMapped(
2955 reinterpret_cast<void*>(POSIX_VSYSCALL_ADDRESS))) {
2956 physical_uintptr_t vsyscallBase = 0;
2957 size_t vsyscallFlags = 0;
2958 Processor::information().getVirtualAddressSpace().getMapping(&__posix_compat_vsyscall_base,
2959 vsyscallBase, vsyscallFlags);
2960 Processor::information().getVirtualAddressSpace().map(
2961 vsyscallBase, reinterpret_cast<void*>(POSIX_VSYSCALL_ADDRESS),
2963 }
2964#endif
2965
2966 // We can now build the auxiliary vector to pass to the dynamic linker.
2968 Processor::information().getVirtualAddressSpace().allocateStack();
2969 if (!stack || !stack->getTop()) {
2970 delete stack;
2971 ERROR("PosixSubsystem::invoke: failed to allocate initial user stack");
2972 return failAfterCommit(Error::OutOfMemory);
2973 }
2974 // Auxiliary vectors, fixed strings, argc, and alignment consume fewer
2975 // than 512 bytes in addition to the already bounded argument payload.
2976 if (stack->getSize() < argumentBytes + 512) {
2977 Processor::information().getVirtualAddressSpace().freeStack(stack);
2978 return failAfterCommit(Error::TooBig);
2979 }
2980 if (state) {
2981 pThread->adoptInitialUserStackForExec(stack);
2982 }
2983 uintptr_t* loaderStack = reinterpret_cast<uintptr_t*>(stack->getTop());
2984
2985 // Top of stack = zero to mark end
2986 STACK_PUSH(loaderStack, 0);
2987
2988 // Align to 16 byte stack
2989 STACK_ALIGN(loaderStack, 16);
2990
2991 // Push argv/env.
2992 char** envs = new char*[env.count()];
2993 size_t envc = 0;
2994 for (size_t i = 0; i < env.count(); ++i) {
2995 String& str = env[i];
2996 STACK_PUSH_STRING(loaderStack, str.length() ? str.cstr() : "", str.length() + 1);
2997 PS_NOTICE("env[" << envc << "]: " << str);
2998 envs[envc++] = reinterpret_cast<char*>(loaderStack);
2999 }
3000
3001 // Align to 16 bytes between env and argv
3002 STACK_ALIGN(loaderStack, 16);
3003
3004 char** argvs = new char*[argv.count()];
3005 size_t argc = 0;
3006 for (size_t i = 0; i < argv.count(); ++i) {
3007 String& str = argv[i];
3008 STACK_PUSH_STRING(loaderStack, str.length() ? str.cstr() : "", str.length() + 1);
3009 PS_NOTICE("argv[" << argc << "]: " << str);
3010 argvs[argc++] = reinterpret_cast<char*>(loaderStack);
3011 }
3012
3013 // Align to 16 bytes between argv and remaining strings
3014 STACK_ALIGN(loaderStack, 16);
3015
3016#if ARM64
3017 STACK_PUSH_STRING(loaderStack, "aarch64", 8);
3018#elif ARMV7
3019 STACK_PUSH_STRING(loaderStack, "v7l", 4);
3020#else
3021 STACK_PUSH_STRING(loaderStack, "x86_64", 7);
3022#endif
3023 void* platform = loaderStack;
3024
3025 STACK_PUSH_STRING(loaderStack, originalName.cstr(), originalName.length() + 1);
3026 void* execfn = loaderStack;
3027
3028 // Align to 16 bytes to prepare for the auxv entries
3029 STACK_ALIGN(loaderStack, 16);
3030
3031 STACK_PUSH_COPY(loaderStack, execRandom, sizeof(execRandom));
3032 void* random = loaderStack;
3033
3034 // Ensure argc aligns to 16 bytes.
3035 if (((argc + envc) % 2) == 0) {
3036 STACK_PUSH_ZEROES(loaderStack, 8);
3037 }
3038
3039 // Build the aux vector now.
3040 STACK_PUSH2(loaderStack, 0, 0); // AT_NULL
3041 STACK_PUSH2(loaderStack, reinterpret_cast<uintptr_t>(platform), 15); // AT_PLATFORM
3042 if (hasExecRandom) {
3043 STACK_PUSH2(loaderStack, reinterpret_cast<uintptr_t>(random), 25); // AT_RANDOM
3044 } else {
3045 STACK_PUSH2(loaderStack, 0, 1); // AT_IGNORE
3046 }
3047 STACK_PUSH2(loaderStack, 0, 23);
3048 STACK_PUSH2(loaderStack, execCredentials.egid, 14); // AT_EGID
3049 STACK_PUSH2(loaderStack, execCredentials.rgid, 13); // AT_GID
3050 STACK_PUSH2(loaderStack, execCredentials.euid, 12); // AT_EUID
3051 STACK_PUSH2(loaderStack, execCredentials.ruid, 11); // AT_UID
3052 STACK_PUSH2(loaderStack, reinterpret_cast<uintptr_t>(execfn), 31); // AT_EXECFN
3053
3054 // The hosted vDSO artifact is not a loadable DSO, so advertising it makes
3055 // musl attempt to decode a nonexistent dynamic table.
3056#if !HOSTED && !ARM64 && !ARMV7
3057 // Push the vDSO shared object.
3058 if (pVdso) {
3059 STACK_PUSH2(loaderStack, 0, 32); // AT_SYSINFO - not present
3060 STACK_PUSH2(loaderStack, vdsoAddress, 33); // AT_SYSINFO_EHDR
3061 }
3062#endif
3063
3064 // ELF parts in the aux vector.
3065 STACK_PUSH2(loaderStack, originalEntryPoint, 9); // AT_ENTRY
3066 STACK_PUSH2(loaderStack, interpreterLoadBias, 7); // AT_BASE
3067 STACK_PUSH2(loaderStack, PhysicalMemoryManager::getPageSize(), 6); // AT_PAGESZ
3068 STACK_PUSH2(loaderStack, originalImage.metadata.programHeaderCount, 5); // AT_PHNUM
3069 STACK_PUSH2(loaderStack, sizeof(Elf::ElfProgramHeader_t), 4); // AT_PHENT
3070 STACK_PUSH2(loaderStack, originalLoadBias + originalImage.programHeaderAddress,
3071 3); // AT_PHDR
3072
3073 // env
3074 STACK_PUSH(loaderStack, 0); // env[N]
3075 for (size_t i = envc; i > 0; --i) {
3076 STACK_PUSH(loaderStack, reinterpret_cast<uintptr_t>(envs[i - 1]));
3077 }
3078 delete[] envs;
3079
3080 // argv
3081 STACK_PUSH(loaderStack, 0); // argv[N]
3082 for (ssize_t i = argc - 1; i >= 0; --i) {
3083 STACK_PUSH(loaderStack, reinterpret_cast<uintptr_t>(argvs[i]));
3084 }
3085 delete[] argvs;
3086
3087 // argc
3088 STACK_PUSH(loaderStack, argc);
3089
3090 // pedigree_init_pthreads();
3091
3093
3094 if (!state) {
3095 if (!publishUserImage(*pProcess->getAddressSpace())) {
3096 delete stack;
3097 return failAfterCommit(Error::ValueTooLarge);
3098 }
3099 // Publish the user Thread only after its initial stack has an owner.
3100 const ThreadPlacement placement = ThreadPlacement::initialUser();
3101 Thread* pNewThread =
3102 new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(interpreterEntryPoint), 0,
3103 loaderStack, false, false, true, &placement);
3104 if (!pNewThread) {
3105 invalidateUserImage();
3106 delete stack;
3107 return failAfterCommit(Error::OutOfMemory);
3108 }
3109 posix_sandbox_inherit(*pNewThread, *pThread);
3110 m_Namespaces->publishThread(initialUts, *pNewThread, true);
3111 if (m_TraceContext.publishTask(initialTrace, *pNewThread) != TraceStatus::Success &&
3112 pNewThread->getUnwindState() != Thread::TerminateThread)
3113 FATAL("Initial trace task publication failed");
3114 pNewThread->adoptInitialUserStackForExec(stack);
3115 pNewThread->setName("ld.so thread");
3116 if (!pNewThread->startDetached()) {
3117 FATAL("PosixSubsystem::invoke: initial user Thread could not be started.");
3118 }
3119
3120 return true;
3121 } else {
3122 // This is a replace and requires a jump to userspace.
3123 SchedulerState s;
3124 ByteSet(&s, 0, sizeof(s));
3125 pThread->state() = s;
3126
3127 if (!SyscallManager::instance().requestUserJump(interpreterEntryPoint,
3128 reinterpret_cast<uintptr_t>(loaderStack))) {
3129 ERROR("PosixSubsystem::invoke: exec userspace jump was not dispatched");
3130 return failAfterCommit(Error::IoError);
3131 }
3132 if (!publishUserImage(*pProcess->getAddressSpace()))
3133 return failAfterCommit(Error::ValueTooLarge);
3134 return true;
3135 }
3136
3137 // unreachable
3138}
Memory-mapped file interface.
Implements a Radix Tree, a kind of Trie with compressed keys.
bool complete()
Definition Completion.cc:43
static ExecutableValidationResult validateExecutableProgramHeaders(const uint8_t *pBuffer, size_t length, size_t fileSize, ExecutableMetadata &metadata)
static ExecutableValidationResult validateExecutableInterpreter(const uint8_t *pBuffer, size_t length, const ExecutableMetadata &metadata)
static ExecutableValidationResult validateExecutableHeader(const uint8_t *pBuffer, size_t length, size_t fileSize, ExecutableMetadata &metadata)
void retire()
Definition Event.cc:479
uintptr_t getHandlerAddress()
Definition Event.h:231
bool test(size_t n) const
void clear(size_t n)
void set(size_t n)
size_t fd
Descriptor number.
Definition File.h:75
virtual void getFullPath(String &result, bool bWithMount=true)
Definition File.cc:1535
size_t readCached(uint64_t location, size_t size, uintptr_t buffer, bool(*prepare)(uintptr_t, size_t)=nullptr)
Definition File.cc:319
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:239
bool supportsRegularFileOperations()
Definition File.cc:824
String getName() const
Definition File.cc:782
virtual bool isSymlink()
Definition File.cc:800
virtual bool isDirectory()
Definition File.cc:804
virtual uintptr_t futexIdentity()
Definition File.cc:75
bool acquireMappingUse(bool executable, bool sharedWrite)
Definition File.cc:1181
Definition List.h:61
Iterator begin()
Definition List.h:122
::Iterator< T, node_t > Iterator
Definition List.h:67
Iterator end()
Definition List.h:132
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
static MemoryMapManager & instance()
bool faultInRange(uintptr_t address, size_t length, bool write)
bool writableAnonymousRange(uintptr_t address, size_t length)
Definition Mutex.h:56
void checkEventState(uintptr_t userStack)
Definition Pipe.h:36
Tree< size_t, PosixThreadKey * > m_ThreadData
virtual void threadExiting(Thread *pThread)
virtual void threadRemoved(Thread *pThread)
virtual void threadException(Thread *pThread, ExceptionType eType, InterruptState *pState=nullptr, uintptr_t faultAddress=0, uintptr_t errorCode=0)
bool acquireFileDescriptor(size_t fd, DescriptorLease &descriptor)
Tree< size_t, PosixSyncObject * > m_SyncObjects
void resetSignalHandlersForExec(Thread *thread, SignalHandler *const handlers[SignalDispositionCount])
bool descriptorMatchesOpenDescription(size_t fd, const FileDescriptor::OpenFileDescriptionLease &expected)
bool closeFileDescriptor(size_t fd, const DescriptorLease &descriptor)
bool loadElf(const ExecutableImage &image, uintptr_t &loadBias)
bool prepareExecutable(File *pFile, ExecutableImage &image, bool isInterpreter)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
Tree< void *, Semaphore * > m_ThreadWaiters
virtual ~PosixSubsystem()
bool resolveUserPageFault(Thread &thread, InterruptState &state, uintptr_t faultAddress, uintptr_t errorCode) override
static size_t readCachedFile(File &file, uint64_t offset, void *destination, size_t count)
void exit(int code, ExitCause cause=ExitCause::Normal) NORETURN
void allocateFd(size_t fdNum)
bool copyDescriptors(PosixSubsystem *pSubsystem)
Thread * m_pAcquiredThread
static bool checkedUserBufferSize(size_t count, size_t elementSize, size_t &extent)
static constexpr size_t LinuxPrivateSignalFirst
Abi getAbi() const
UnlikelyLock m_SignalHandlersLock
size_t getFd(size_t minimum=0)
static UserStringResult copyUserString(const char *userString, String &copy, size_t maxLength)
void freeFd(size_t fdNum)
virtual void sendSignal(Thread *pThread, int signal, bool yield=true, bool processDirected=false)
void setProcess(Process *process) override
virtual bool invoke(const char *name, Vector< String > &argv, Vector< String > &env)
size_t installFileDescriptor(FileDescriptor *descriptor, DescriptorLease &lease, size_t minimum=0)
SignalDeliveryResult queueSignalDelivery(Thread *target, size_t sig, uint32_t *flags=nullptr, int32_t signalCode=0, bool processDirected=false, uint64_t signalValue=0, const SharedPointer< SignalEventState > &state=SharedPointer< SignalEventState >())
static bool checkUserAddressRange(uintptr_t addr, size_t count, size_t elementSize, size_t *extent=nullptr)
virtual void preserveProcessSignalsForThreadExit(Thread *thread)
virtual bool kill(KillReason killReason, Thread *pThread)
static bool checkUserBuffer(uintptr_t addr, size_t count, size_t elementSize, size_t flags, size_t *extent=nullptr)
bool acquireNextFileDescriptor(size_t minimum, size_t &fd, DescriptorLease &descriptor)
void freeMultipleFds(bool bOnlyCloExec=false, size_t iFirst=0, size_t iLast=-1)
ExtensibleBitmap m_FdBitmap
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
void addFileDescriptor(size_t fd, FileDescriptor *pFd)
PosixTraceContext m_TraceContext
void setSignalHandler(size_t sig, SignalHandler *handler)
bool parseShebang(File *pFile, String &interpreter, String &optionalArgument, bool &hasOptionalArgument)
DescriptorDuplicationResult duplicateFileDescriptor(size_t source, size_t target, bool closeOnExec)
bool getSignalDisposition(size_t sig, SignalDisposition &disposition, bool beginDelivery=false)
virtual void prepareThreadsForExec(Thread *owner)
Tree< size_t, SharedPointer< FileDescriptor > > m_FdMap
virtual void release()
Tree< size_t, PosixThread * > m_Threads
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
virtual void acquire()
Acquire full mutual exclusion for all Subsystem resources.
bool isGroupIdValid(size_t gid) const
void returnGroupId(size_t gid)
void registerGroup(size_t gid, ProcessGroup *group)
void setGroupId(size_t gid)
ProcessGroup * findGroup(size_t gid) const
size_t getUserspaceId() const
Definition Process.h:504
void setExitStatus(int code)
Definition Process.h:556
bool beginTermination(int code=0, Subsystem::ExitCause cause=Subsystem::ExitCause::Normal)
Definition Process.cc:1685
bool quiesceTermination()
Definition Process.cc:1875
size_t getId()
Definition Process.h:499
MUST_USE_RESULT bool acquireProcessSignalThread(ThreadLease &lease)
Definition Process.cc:1407
int getExitStatus()
Definition Process.h:560
Process * getParent()
Definition Process.h:620
VirtualAddressSpace * getAddressSpace()
Definition Process.h:530
size_t getNumThreads()
Definition Process.cc:1380
LargeStaticString & description()
Definition Process.h:525
void releaseVforkAddressSpace()
Definition Process.cc:711
MUST_USE_RESULT bool acquireThread(ThreadLease &lease, size_t n)
Definition Process.cc:1385
void resume()
Definition Process.cc:2155
Time::Timestamp getUserTime() const
Definition Process.h:829
virtual int64_t getUserId() const
Definition Process.cc:2238
size_t getContinuationEpoch()
Definition Process.cc:2150
void finishTermination(bool notifyParent=false) NORETURN
Definition Process.cc:1925
static bool getInterrupts()
static ProcessorId id()
static ProcessorInformation & information()
static bool inDeviceHardIrq()
Definition Processor.h:581
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static void setInterrupts(bool bEnable)
T * exchange(T *replacement)
Definition Rcu.h:44
static Scheduler & instance()
Definition Scheduler.h:96
void yield()
Definition Scheduler.cc:236
void release(size_t n=1)
Definition Semaphore.cc:549
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:372
T * get() const
void setSignalOrigin(int32_t signalCode, int32_t senderProcess, uint32_t senderUser)
void setContinuationEpoch(size_t continuationEpoch)
virtual Event * cloneForDelivery()
void release()
Definition Spinlock.cc:168
bool acquire(bool recurse=false, bool safe=true)
Definition Spinlock.cc:36
virtual void setProcess(Process *p)
Definition Subsystem.h:156
static EXPORTED_PUBLIC SyscallManager & instance()
void discardUserStackMetadataForExec()
Definition Thread.cc:981
void setErrno(size_t err)
Definition Thread.h:482
void unexpectedExit()
Definition Thread.cc:2642
void setUnwindState(UnwindType ut)
Definition Thread.cc:3580
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:517
@ TerminateThread
Exit only this thread during Process exit.
Definition Thread.h:519
SchedulerState & state()
Definition Thread.cc:832
bool transferProcessSignalsTo(Thread &target)
Definition Thread.cc:2238
bool replaceSignalEvent(size_t signalNumber, Event *replacement, int processDirected=-1, uint64_t rebindGeneration=0)
Definition Thread.cc:2270
bool hasSignalEvent(size_t signalNumber, int processDirected=-1)
Definition Thread.cc:2345
uint64_t getSignalMask()
Definition Thread.cc:1981
void deferSignalExit(int signal)
Definition Thread.cc:3612
size_t getErrno()
Definition Thread.h:477
int(* ThreadStartFunc)(void *)
Definition Thread.h:189
UnwindType getUnwindState()
Definition Thread.h:535
void setClearChildTid(uintptr_t address)
Definition Thread.cc:653
uintptr_t takeClearChildTid()
Definition Thread.h:348
bool startDetached()
Definition Thread.cc:769
Process * getParent() const
Definition Thread.h:340
size_t getId()
Definition Thread.h:465
void cullSignalEvent(size_t signalNumber)
Definition Thread.cc:2216
class PerProcessorScheduler * getScheduler() const
Definition Thread.h:929
bool sendEvent(Event *pEvent)
Definition Thread.cc:1115
uintptr_t getTlsBase()
Definition Thread.cc:2644
void notifySubsystemExit()
Definition Thread.cc:547
void resetTlsBase()
Definition Thread.cc:2691
void adoptInitialUserStackForExec(VirtualAddressSpace::Stack *stack)
Definition Thread.cc:1018
An iterator applicable for many data structures.
Definition Iterator.h:147
A key/value dictionary.
Definition Tree.h:33
Iterator begin()
Definition Tree.h:402
E lookup(const K &key) const
Definition Tree.h:193
void clear()
Definition Tree.h:383
void insert(const K &key, const E &value)
Definition Tree.h:149
const E & lookupRef(const K &key, const E &failed=E()) const
Definition Tree.h:223
Iterator end()
Definition Tree.h:427
bool take(const K &key, E &element)
Definition Tree.h:363
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
Definition VFS.cc:1502
static VFS & instance()
Definition VFS.cc:311
A vector / dynamic array.
Definition Vector.h:33
virtual uintptr_t getUserReservedStart() const =0
virtual bool isMapped(void *virtualAddress)=0
virtual void revertToKernelAddressSpace()=0
virtual uintptr_t getUserStart() const =0
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual uintptr_t getKernelStart() const =0
virtual bool isAddressValid(void *virtualAddress)=0
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
void pushBack(const T &value)
Definition List.h:216
void pushFront(const T &value)
Definition Vector.h:313
void pushBack(const T &value)
Definition Vector.h:275
void clear(bool freeMem=false)
Definition Vector.h:378
T popFront()
Definition Vector.h:357
size_t count() const
Definition Vector.h:270
int type
Type - 0 = normal, 1 = SIG_DFL, 2 = SIG_IGN.
SignalEvent * pEvent
Event for the signal handler.
uintptr_t restorer
Userspace restorer for Linux-compatible signal delivery.
uint64_t sigMask
Signal mask to set when this signal handler is called.
uint32_t flags
Signal handler flags.