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