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"
42#include <PosixSubsystem.h>
48#include "FileDescriptor.h"
49#include "PosixProcess.h"
51#include "eventfd-syscalls.h"
52#include "file-syscalls.h"
53#include "linux-amd64-signal.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"
72extern char __posix_compat_vsyscall_base;
73#define POSIX_VSYSCALL_ADDRESS 0xffffffffff600000
87 : fd(number), descriptor(owner) {}
96extern void pedigree_init_sigret();
97extern void pedigree_init_pthreads();
102 file->releaseMappingUse(
true,
false);
105 File* file =
nullptr;
109 uintptr_t programHeaderAddress = 0;
114bool validUserAddressRange(uintptr_t address,
size_t extent) {
115 if (extent - 1 > (~
static_cast<uintptr_t
>(0) - address)) {
118 const uintptr_t end = address + extent - 1;
125bool prepareUserCopy(uintptr_t address,
size_t extent,
bool write) {
131 if (!validUserAddressRange(address, extent)) {
138void ignoredSignal(
int) {}
140bool defaultSignalActionIsIgnore(
size_t signal) {
141 return signal == SIGCHLD || signal == SIGURG || signal == SIGWINCH;
144bool defaultSignalActionIsStop(
size_t signal) {
145 return signal == SIGSTOP || signal == SIGTSTP || signal == SIGTTIN || signal == SIGTTOU;
149 if (process && delivery && defaultSignalActionIsStop(signal)) {
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);
168void setExecutableValidationError(Elf::ExecutableValidationResult result,
bool isInterpreter) {
170 SYSCALL_ERROR(BadSharedLibrary);
171 }
else if (result == Elf::ExecutableValidationResult::MultipleInterpreters) {
172 SYSCALL_ERROR(InvalidArgument);
174 SYSCALL_ERROR(ExecFormatError);
179ProcessGroupManager::ProcessGroupManager() : m_GroupIds(), m_Groups(nullptr), m_GroupLock(false) {
183ProcessGroupManager::~ProcessGroupManager() {}
187 size_t bit = m_GroupIds.getFirstClear();
188 while (findGroup(bit) || m_GroupIds.test(bit))
196 if (m_GroupIds.test(gid)) {
198 "ProcessGroupManager: setGroupId called on a group ID that "
206 return findGroup(gid) || m_GroupIds.test(gid);
211 m_GroupIds.clear(gid);
217 group->registryNext = m_Groups;
219 group->registered =
true;
222void ProcessGroupManager::unregisterGroup(
size_t gid,
ProcessGroup* group) {
225 while (*link && *link != group)
226 link = &(*link)->registryNext;
228 *link = group->registryNext;
229 group->registryNext =
nullptr;
230 group->registered =
false;
235 for (
ProcessGroup* group = m_Groups; group; group = group->registryNext)
236 if (
static_cast<size_t>(group->processGroupId) == gid)
245 m_CallbackSchedulingDomain(s.m_CallbackSchedulingDomain),
247 m_MemoryLockAccount(s.m_MemoryLockAccount),
258 m_NextThreadWaiter(1),
259 m_ImageMetadataLock(),
267 m_ExecutablePath = s.m_ExecutablePath;
268 m_CommandLine = s.m_CommandLine;
278 size_t key = it.key();
279 void* value = it.value();
285 if (clearSignalHandlers && original->type != 2) {
289 newSig->
pEvent =
new SignalEvent(pedigree_default_signal_handler(key), key, ~0UL, 0,
true,
290 false, Event::HandlerPrivilege::Kernel,
291 SignalEvent::DeliveryDisposition::DefaultAction);
295 m_SignalHandlers.insert(key, newSig);
305 void* key = it.key();
311 m_NextThreadWaiter = s.m_NextThreadWaiter;
318 m_PendingSignals->attach(m_pProcess);
319 if (process && m_Namespaces)
320 m_Namespaces->attach(*process);
325 space.setMemoryLockAccount(&m_MemoryLockAccount);
329bool PosixSubsystem::executablePath(
String& result)
const {
331 if (!m_ExecutablePath || !m_pProcess)
333 auto context = m_pProcess->acquireFilesystemContext();
336 return context && context->snapshot(snapshot) && view &&
337 view->formatPath(snapshot, m_ExecutablePath, result);
342 result = m_ExecutablePath;
343 return static_cast<bool>(result);
348 result = m_CommandLine;
349 return result.
count() != 0;
352bool PosixSubsystem::snapshotUserImage(UserImageToken& token)
const {
355 if (!m_UserImageActive)
357 token.space = m_UserImageSpace;
358 token.generation = m_UserImageGeneration;
362bool PosixSubsystem::matchesUserImage(
const UserImageToken& token)
const {
364 return m_UserImageActive && token.space == m_UserImageSpace &&
365 token.generation == m_UserImageGeneration;
368void PosixSubsystem::invalidateUserImage() {
370 m_UserImageActive =
false;
371 m_UserImageSpace =
nullptr;
376 if (m_UserImageActive || !m_pProcess || m_pProcess->
getAddressSpace() != &space ||
377 m_UserImageGeneration == ~uint64_t(0))
379 ++m_UserImageGeneration;
380 m_UserImageSpace = &space;
381 m_UserImageActive =
true;
389 if (m_pProcess && m_pProcess->isVforkChild()) {
393 invalidateUserImage();
399 m_Namespaces->close();
400 m_PendingSignals->close();
417 m_SignalHandlers.clear();
423 posix_advisory_owner_closed(m_AdvisoryOwner);
435 if (!thread->isRunning.isComplete()) {
436 WARNING(
"PosixSubsystem object freed when a thread is still running?");
465 delete reinterpret_cast<Mutex*
>(p->pObject);
467 delete reinterpret_cast<Semaphore*
>(p->pObject);
486 invalidateUserImage();
511 va->rawUserMemory().clear();
512 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
513 va->setMemoryLockAccount(
nullptr);
519void PosixSubsystem::acquireFdLock() {
521 FATAL(
"PosixSubsystem could not acquire its descriptor table");
567 PS_NOTICE(
"PosixSubsystem::checkAddress(" <<
Hex << addr <<
", " <<
Dec << extent <<
", " <<
Hex
574 PS_NOTICE(
" -> zero extent, address is sane.");
579 uintptr_t aa =
reinterpret_cast<uintptr_t
>(__builtin_return_address(0));
581 PS_NOTICE(
" -> ret: " << aa);
586 if (!validUserAddressRange(addr, extent)) {
588 PS_NOTICE(
" -> outside of user address area.");
592 const uintptr_t end = addr + extent - 1;
597 if (flags & SafeRead) {
598 mmapPermissions |= MemoryMappedObject::Read;
600 if (flags & SafeWrite) {
601 mmapPermissions |= MemoryMappedObject::Write;
603 if (flags & SafeExecute) {
604 mmapPermissions |= MemoryMappedObject::Exec;
609 if (mmapPermissions != MemoryMappedObject::None &&
612 PS_NOTICE(
" -> inside memory map.");
620 uintptr_t page = addr - (addr % pageSize);
621 uintptr_t finalPage = end - (end % pageSize);
623 void* pAddr =
reinterpret_cast<void*
>(page);
626 PS_NOTICE(
" -> page " <<
Hex << pAddr <<
" is not mapped.");
632 physical_uintptr_t phys = 0;
637 PS_NOTICE(
" -> not userspace-accessible.");
642 if (flags & SafeWrite) {
646 PS_NOTICE(
" -> not writeable.");
654 PS_NOTICE(
" -> not executable.");
659 if (page == finalPage) {
666 PS_NOTICE(
" -> mapped and available.");
673 if (!count || !elementSize) {
677 if (count > (~
static_cast<size_t>(0) / elementSize)) {
681 extent = count * elementSize;
691 size_t byteExtent = 0;
697 *extent = byteExtent;
702 return !byteExtent || validUserAddressRange(addr, byteExtent);
712 size_t byteExtent = 0;
718 *extent = byteExtent;
724 size_t elementSize) {
732 if (!destination || !source) {
737 if (!prepareUserCopy(
reinterpret_cast<uintptr_t
>(source), extent,
false)) {
741 MemoryCopy(destination, source, extent);
746 size_t elementSize) {
754 if (!destination || !source) {
759 if (!prepareUserCopy(
reinterpret_cast<uintptr_t
>(destination), extent,
true)) {
763 MemoryCopy(destination, source, extent);
770 !validUserAddressRange(
reinterpret_cast<uintptr_t
>(destination), count)) {
776 offset, count,
reinterpret_cast<uintptr_t
>(destination), [](uintptr_t address,
size_t bytes) {
782 String& copy,
size_t maxLength) {
786 return UserStringBadAddress;
790 return UserStringTooLong;
796 const size_t chunkSize = 256;
797 uintptr_t current =
reinterpret_cast<uintptr_t
>(userString);
800 while (copied < maxLength) {
801 size_t length = maxLength - copied;
802 if (length > chunkSize) {
806 const size_t pageOffset = current % pageSize;
807 const size_t pageRemaining = pageSize - pageOffset;
808 if (length > pageRemaining) {
809 length = pageRemaining;
812 if (!prepareUserCopy(current, length,
false)) {
813 return UserStringBadAddress;
816 char buffer[chunkSize];
817 MemoryCopy(buffer,
reinterpret_cast<const void*
>(current), length);
819 size_t partLength = 0;
820 while (partLength < length && buffer[partLength]) {
824 if (partLength != length) {
825 copy +=
String(buffer, partLength,
true);
826 return UserStringSuccess;
829 copy +=
String(buffer, length,
true);
831 if (copied == maxLength) {
832 return UserStringTooLong;
835 if (current > (~
static_cast<uintptr_t
>(0) - length)) {
836 return UserStringBadAddress;
841 return UserStringTooLong;
847 "PosixSubsystem::exit requires an IRQ-enabled thread "
854 NOTICE(
"PosixSubsystem::exit(" <<
Dec << pProcess->
getId() <<
", code=" << code <<
")");
863 if (cause == ExitCause::Signal) {
877 FATAL(
"POSIX exit owner could not claim process teardown for pid " <<
Dec << pProcess->
getId()
885 "POSIX process teardown escaped its IRQ-enabled thread "
891 static_cast<PosixProcess*
>(pProcess)->snapshotAccountingMemory();
893 posix_advisory_owner_closed(m_AdvisoryOwner);
897 m_PendingSignals->close();
898 posix_timer_process_exit(pProcess);
899 invalidateUserImage();
907 delete pProcess->getLinker();
914 space.rawUserMemory().clear();
915 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
916 space.setMemoryLockAccount(
nullptr);
928 NOTICE(
"at exit for pid " <<
Dec << pProcess->
getId() <<
"...");
933 FATAL(
"PosixSubsystem::exit() running after Process teardown!");
940 if (pProcess->getType() != Process::Posix) {
941 ERROR(
"PosixSubsystem::kill called with a non-POSIX process!");
946 int signal = SIGKILL;
947 switch (killReason) {
961 SignalDeliveryResult::Queued) {
962 PS_NOTICE(
"PosixSubsystem - killing " << pThread->
getParent()->
getId());
973 uintptr_t faultAddress, uintptr_t errorCode) {
974 constexpr uintptr_t present = 1, write = 2, user = 4, fetch = 16;
977 thread.
getParent()->getSubsystem() !=
this ||
979 (errorCode & ~(present | write | user | fetch)) ||
980 ((errorCode & write) && (errorCode & fetch))) {
984 if (!(errorCode & user))
988 faultAddress, errorCode & write, errorCode & present, errorCode & fetch);
989 if (resolution == MemoryMapManager::FaultResolution::BackingFault) {
990 threadException(&thread, FileMappingFault, &state, faultAddress, errorCode);
993 return resolution == MemoryMapManager::FaultResolution::Resolved;
997 uintptr_t faultAddress, uintptr_t errorCode) {
999 EMIT_IF(POSIX_LOG_FACILITIES & 16) {
1000 if (pState && eType == PageFault) {
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));
1022 PS_NOTICE(
"PosixSubsystem::threadException -> " <<
Dec << pThread->
getParent()->
getId() <<
":"
1023 << pThread->
getId());
1029 PS_NOTICE(
" (Page fault)");
1033 case FileMappingFault:
1037 PS_NOTICE(
" (Invalid opcode)");
1041 case GeneralProtectionFault:
1042 PS_NOTICE(
" (General Fault)");
1047 PS_NOTICE(
" (Division by zero)");
1052 PS_NOTICE(
" (FPU error)");
1056 case SpecialFpuError:
1057 PS_NOTICE(
" (FPU error - special)");
1063 " (Attempt to read from terminal by non-foreground "
1068 case TerminalOutput:
1069 PS_NOTICE(
" (Output to terminal by non-foreground process)");
1074 PS_NOTICE(
" (Continuing a stopped process)");
1079 PS_NOTICE(
" (Stopping a process)");
1084 PS_NOTICE(
" (Interrupting a process)");
1089 PS_NOTICE(
" (Requesting quit)");
1094 PS_NOTICE(
" (Child status changed)");
1099 PS_NOTICE(
" (Pipe broken)");
1104 PS_NOTICE(
" (Unknown)");
1106 ERROR(
"Unknown exception type in threadException - POSIX subsystem");
1111 if (signal > 0 && pState &&
getAbi() == LinuxAbi) {
1112 if (traceException(*pThread, signal, *pState, eType, faultAddress, errorCode))
1116 LinuxAmd64Signal::DeliveryResult result = LinuxAmd64Signal::deliverSynchronous(
1117 pThread, signal, disposition, eType, *pState, faultAddress, errorCode);
1118 if (result == LinuxAmd64Signal::Delivered) {
1121 if (result == LinuxAmd64Signal::Failed) {
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);
1142 PS_NOTICE(
"PosixSubsystem::sendSignal #" << signal <<
" -> pid:tid " <<
Dec
1144 << pThread->
getId());
1147 if (pProcess->getType() != Process::Posix) {
1148 ERROR(
"PosixSubsystem::threadException called with a non-POSIX process!");
1153 const SignalDeliveryResult result =
1155 if (result == SignalDeliveryResult::Unavailable) {
1156 ERROR(
"Unknown signal in sendSignal - POSIX subsystem");
1159 if (result == SignalDeliveryResult::Queued && yield) {
1161 if (pCurrentThread == pThread) {
1168 }
else if (result == SignalDeliveryResult::Rejected) {
1171 NOTICE(
"No event configured for signal #" << signal <<
", silently dropping!");
1175bool PosixSubsystem::admitLegacyUserSignals() {
1178 if (m_CallbackSchedulingDomain == CallbackSchedulingDomain::Affinity ||
1183 m_CallbackSchedulingDomain = CallbackSchedulingDomain::LegacySignals;
1188 if (sig > MaximumSupportedSignal) {
1190 ERROR(
"Cannot install unsupported signal disposition " <<
Dec << sig <<
".");
1201 removal = m_SignalHandlers.lookup(sig);
1204 m_SignalHandlers.remove(sig);
1210 m_SignalHandlers.insert(sig, handler);
1212 const bool discardPending =
1213 handler->
type == 2 || (handler->
type == 1 && defaultSignalActionIsIgnore(sig));
1220 if (discardPending) {
1222 }
else if (handler->
pEvent) {
1225 rebindQueuedSignalEvents(*thread.get(), sig, *handler->
pEvent);
1232 m_PendingSignals->recordChange();
1245 FATAL(
"Exec signal reset requires the sole surviving process thread.");
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.");
1260 for (
size_t signal = 0; signal < SignalDispositionCount; ++signal) {
1262 replacement->
sig = signal;
1264 removals[signal] = m_SignalHandlers.lookup(signal);
1265 if (removals[signal]) {
1266 m_SignalHandlers.remove(signal);
1268 m_SignalHandlers.insert(signal, replacement);
1270 if (!rebindQueuedSignalEvents(*thread, signal, *replacement->
pEvent)) {
1271 FATAL(
"Exec signal reset could not rebind a pending signal.");
1275 m_PendingSignals->recordChange();
1284 bool beginDelivery) {
1285 if (sig > MaximumSupportedSignal) {
1289 if (beginDelivery) {
1299 disposition.signalMask = handler->
sigMask;
1300 disposition.flags = handler->
flags;
1301 disposition.restorer = handler->
restorer;
1302 disposition.type = handler->
type;
1304 if (beginDelivery && handler->
type == 0 && (handler->
flags & SA_RESETHAND)) {
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);
1318 if (beginDelivery) {
1326 return handler !=
nullptr;
1330 Thread* target,
size_t sig, uint32_t* flags, int32_t signalCode,
bool processDirected,
1341 if (!target || !target->
getParent() || target->
getParent()->getSubsystem() !=
this || !sig ||
1342 sig > MaximumSupportedSignal) {
1344 return SignalDeliveryResult::Unavailable;
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]);
1355 for (
size_t stopSignal : StopSignals) {
1356 if (sig == stopSignal) {
1357 signalsToDiscard = &continueSignal;
1358 signalsToDiscardCount = 1;
1365 if (processDirected) {
1370 return SignalDeliveryResult::Rejected;
1372 target = processTarget.get();
1374 for (
unsigned pass = 0; pass < 2; ++pass) {
1375 bool selected =
false;
1378 if (!process->
acquireThread(candidate, i - 1) || !candidate->acceptingEvents() ||
1381 const uint64_t bit = uint64_t(1) << (sig - 1);
1382 if ((pass == 0 && (candidate->getSynchronousSignalMask() & bit)) ||
1384 processTarget = pedigree_std::move(candidate);
1385 target = processTarget.get();
1394 if (signalsToDiscard) {
1400 for (
size_t n = 0; n < signalsToDiscardCount; ++n) {
1409 if (sig == SIGCONT) {
1413 trace->continued(*process);
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();
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);
1430 SignalDeliveryResult result = SignalDeliveryResult::Unavailable;
1431 if (suppressDelivery) {
1432 result = SignalDeliveryResult::Ignored;
1433 }
else if (handler && handler->
pEvent) {
1435 bool duplicate =
false;
1436 if (processDirected) {
1448 return SignalDeliveryResult::Queued;
1452 if (!deliveryState && (signalCode == -1 || sig >= 35)) {
1453 deliveryState = posix_signal_reserve_queue(process);
1454 if (!deliveryState) {
1456 return SignalDeliveryResult::Full;
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();
1468 senderUid =
static_cast<uint32_t
>(uid);
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) {
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));
1489 delivery->setSignalValue(signalValue);
1490 delivery->setProcessDirected(processDirected);
1491 stampStopDelivery(process, sig, delivery);
1493 *flags = handler->
flags;
1497 result = SignalDeliveryResult::Queued;
1503 result = SignalDeliveryResult::Rejected;
1506 target = processTarget.get();
1511 m_PendingSignals->recordChange(result == SignalDeliveryResult::Queued ? sig : 0, target,
1513 if (delivery && result == SignalDeliveryResult::Rejected) {
1514 delivery->rejectSignalDelivery();
1533 const bool advancesGlobalHint = minimum <=
m_LastFd;
1535 for (
size_t i = firstCandidate; i <
m_NextFd; i++) {
1539 if (advancesGlobalHint) {
1582 publishFdEntry(fdNum);
1594 retireDescriptor(retiring.
get());
1614 pSubsystem->acquireFdLock();
1622 size_t newFd = it.key();
1625 assert(!pFd->networkImpl || pNewFd->networkPublished());
1635 retiring.
pushBack(pedigree_std::move(previous));
1646 for (
auto& descriptor : retiring) {
1647 retireDescriptor(descriptor.get());
1649 retiring.
clear(
true);
1672 bool bAllToBeFreed = ((iFirst == 0 && iLast == ~0UL) && !bOnlyCloExec);
1678 size_t Fd = it.key();
1683 if (!(Fd >= iFirst && Fd <= iLast))
1687 if (!(pFd->fdflags & FD_CLOEXEC))
1693 fdsToRemove.
pushBack(
reinterpret_cast<void*
>(Fd));
1703 if (
m_FdMap.
take(
reinterpret_cast<size_t>(*it), descriptor)) {
1704 retiring.
pushBack(pedigree_std::move(descriptor));
1708 if (retiring.
count()) {
1715 for (
auto& descriptor : retiring) {
1716 retireDescriptor(descriptor.get());
1718 retiring.
clear(
true);
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);
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();
1741 FdEntry* retiring = previous && previous->fd == fd ? previous :
nullptr;
1742 FdEntry* following = retiring ? retiring->next.loadForUpdate() : previous;
1745 FdEntry* replacement = following;
1747 replacement =
new FdEntry(fd, current);
1749 FATAL(
"PosixSubsystem could not allocate its descriptor entry");
1752 replacement->next.exchange(following);
1756 link->exchange(replacement);
1766void PosixSubsystem::publishFdEntries() {
1769 FdEntry* previous[FdBuckets] = {};
1770 for (
size_t bucket = 0; bucket < FdBuckets; ++bucket) {
1771 tails[bucket] = &replacements[bucket];
1775 FdEntry* entry =
new FdEntry(it.key(), it.value());
1777 FATAL(
"PosixSubsystem could not allocate its descriptor entry");
1779 const size_t bucket = it.key() % FdBuckets;
1781 tails[bucket] = &entry->next;
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;
1792 for (
auto* entry : previous) {
1794 FdEntry* next = entry->next.loadForUpdate();
1806 size_t selected = ~size_t(0);
1811 if (it.key() >= minimum && it.key() < selected && it.value()) {
1812 selected = it.key();
1813 retained = it.value();
1818 descriptor.retain(retained);
1835 const bool matches = current && current->m_OpenFile.
get() == expected.
get();
1847 bool removed =
false;
1854 if (current == descriptor.m_Descriptor) {
1872 retireDescriptor(retiring.
get());
1901 retireDescriptor(retiring.
get());
1907 size_t sourceFd,
size_t targetFd,
bool closeOnExec) {
1912 DescriptorDuplicationResult result = DescriptorDuplicationResult::BadSource;
1925 result = DescriptorDuplicationResult::TargetBusy;
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;
1944 publishFdEntry(targetFd);
1945 result = DescriptorDuplicationResult::Success;
1953 currentTarget.
reset();
1955 retireDescriptor(retiring.
get());
1958 replacement.
reset();
1970 const bool advancesGlobalHint = minimum <=
m_LastFd;
1973 for (
size_t candidate = firstCandidate; candidate <
m_NextFd; ++candidate) {
1976 if (advancesGlobalHint) {
1986 descriptor->
fd = fd;
1990 lease.retain(published);
2002 if (m_pProcess->
acquireThread(source, i - 1) && source.get() != owner &&
2004 FATAL(
"Exec owner rejected a pending process signal.");
2007 m_PendingSignals->recordChange();
2017 m_PendingSignals->recordChange();
2023void PosixSubsystem::retireDescriptor(
FileDescriptor* descriptor) {
2024 if (descriptor->getFile()) {
2025 posix_advisory_descriptor_closed(m_AdvisoryOwner, descriptor->getFile()->
futexIdentity());
2029 if (!descriptor->getFile()) {
2031 if (queue && m_pProcess) {
2045 const size_t taskId = pThread->
getTaskId();
2046 m_Namespaces->retireThread(*pThread);
2049 m_PendingSignals->retireThread(pThread);
2050 posix_timer_thread_exit(pThread);
2051 posix_sem_thread_exit(pThread);
2052 posix_robust_list_exit(pThread);
2054 clearChildTid(pThread);
2057void PosixSubsystem::clearChildTid(
Thread* pThread) {
2068 const bool cleared = posix_clear_child_tid(process, address);
2070 PS_NOTICE(
"clear-child-TID could not access target at " <<
Hex << address <<
" for tid " <<
Dec
2071 << pThread->
getId());
2079 if (!posix_futex_wake(process,
reinterpret_cast<int*
>(address), 1,
false))
2080 posix_futex_wake(process,
reinterpret_cast<int*
>(address), 1);
2086 if (thread->pThread != pThread)
2098bool PosixSubsystem::checkAccess(
const DescriptorLease& pFileDescriptor,
bool bRead,
bool bWrite,
2099 bool bExecute)
const {
2100 return VFS::checkAccess(pFileDescriptor->getFile(), bRead, bWrite, bExecute);
2108 image.fileSize = pFile->getSize();
2111 if (pFile->
read(0,
sizeof(header),
reinterpret_cast<uintptr_t
>(header)) !=
sizeof(header)) {
2112 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2116 Elf::ExecutableValidationResult result =
2118 if (result != Elf::ExecutableValidationResult::Valid) {
2119 setExecutableValidationError(result, isInterpreter);
2124 if (!image.programHeaders) {
2125 SYSCALL_ERROR(OutOfMemory);
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);
2136 image.programHeaders.get(), image.metadata.programHeaderSize, image.fileSize, image.metadata);
2137 if (result != Elf::ExecutableValidationResult::Valid) {
2138 setExecutableValidationError(result, isInterpreter);
2143 if (image.metadata.type == ET_EXEC &&
2144 (image.metadata.loadStart < addressSpace.
getUserStart() ||
2146 setExecutableValidationError(Elf::ExecutableValidationResult::UnsupportedLayout, isInterpreter);
2150 bool foundProgramHeaders =
false;
2151 for (
size_t i = 0; i < image.metadata.programHeaderCount; ++i) {
2154 sizeof(programHeader));
2155 if (programHeader.type != PT_LOAD ||
2156 image.metadata.programHeaderOffset < programHeader.offset) {
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) {
2167 image.programHeaderAddress = programHeader.vaddr + offsetInSegment;
2168 foundProgramHeaders =
true;
2171 if (!foundProgramHeaders) {
2172 setExecutableValidationError(Elf::ExecutableValidationResult::UnsupportedLayout, isInterpreter);
2176 if (!image.metadata.hasInterpreter) {
2182 SYSCALL_ERROR(OutOfMemory);
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);
2194 if (result != Elf::ExecutableValidationResult::Valid) {
2195 setExecutableValidationError(result, isInterpreter);
2198 for (
size_t i = 0; i + 1 < image.metadata.interpreterSize; ++i) {
2199 if (!interpreter.get()[i]) {
2200 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2205 image.interpreter.assign(
reinterpret_cast<const char*
>(interpreter.get()),
2206 image.metadata.interpreterSize - 1,
true);
2211 PS_NOTICE(
"PosixSubsystem::loadElf(" << image.file->
getName() <<
")");
2215 image.metadata.programHeaderSize, image.fileSize,
2216 metadata) != Elf::ExecutableValidationResult::Valid) {
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)) {
2228 loadBias = allocation - metadata.loadStart;
2230 if (!pProcess->allocateSpecificUserRange(Process::UserRegion::Normal, metadata.loadStart,
2238 const uintptr_t pageMask = pageSize - 1;
2239 for (
size_t i = 0; i < metadata.programHeaderCount; ++i) {
2242 sizeof(programHeader));
2243 if (programHeader.type != PT_LOAD || !programHeader.memsz) {
2247 if (programHeader.vaddr > ~uintptr_t{0} - loadBias) {
2250 const uintptr_t segmentAddress = loadBias + programHeader.vaddr;
2251 const uintptr_t pageOffset = segmentAddress & pageMask;
2252 if (programHeader.memsz > ~
size_t{0} - pageOffset) {
2255 size_t length = programHeader.memsz + pageOffset;
2256 if (length > ~
size_t{0} - pageMask) {
2259 length = (length + pageMask) & ~pageMask;
2261 uintptr_t base = segmentAddress & ~pageMask;
2262 const size_t fileOffset = programHeader.offset & ~pageMask;
2264 if (programHeader.flags & PF_X) {
2265 perms |= MemoryMappedObject::Exec;
2267 if (programHeader.flags & PF_W) {
2268 perms |= MemoryMappedObject::Write;
2271 const uintptr_t fileEnd = segmentAddress + programHeader.filesz;
2272 const bool hasPartialBssPage =
2273 programHeader.memsz > programHeader.filesz && (fileEnd & pageMask) != 0;
2275 if (hasPartialBssPage) {
2276 mappingPerms |= MemoryMappedObject::Write;
2279 PS_NOTICE(image.file->
getName()
2280 <<
" PHDR[" << i <<
"]: @" <<
Hex << base <<
" -> " << base + length);
2283 image.file, base, length, mappingPerms, fileOffset,
true,
2284 MemoryMapManager::Placement::FixedReplace,
nullptr,
2285 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec,
2287 ERROR(
"PosixSubsystem::loadElf: failed to map PT_LOAD section");
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;
2300 if (zeroStart < end) {
2301 uintptr_t anonymousAddress = zeroStart;
2305 "PosixSubsystem::loadElf: failed to map anonymous "
2306 "pages for filesz/memsz mismatch");
2313 ERROR(
"PosixSubsystem::loadElf: failed to restore PT_LOAD permissions");
2321ResolvedPath::~ResolvedPath() {
2325void ResolvedPath::reset() {
2327 const size_t error = thread ? thread->
getErrno() : 0;
2334 if (m_Path.
get() == path.
get())
2336 auto retired = pedigree_std::move(m_Path);
2339 const size_t error = thread ? thread->
getErrno() : 0;
2349 if (!context || !view) {
2350 SYSCALL_ERROR(DoesNotExist);
2355 options.followFinal = followFinal;
2356 if (!view->resolve(context, workingDir, path,
options, selected))
2358 result.retain(selected);
2360 return result.get();
2365 SYSCALL_ERROR(DoesNotExist);
2369 return selected.get();
2373 if (!context || !view || !view->follow(context, selected.path(), followed))
2375 selected.retain(followed);
2377 return selected.get();
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))))
2397 return invoke(name, argv, env, 0);
2401 SyscallState& state) {
2402 return invoke(name, argv, env, &state);
2406 bool& hasOptionalArgument) {
2407 PS_NOTICE(
"Attempting to parse shebang in " << pFile->
getFullPath());
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));
2413 interpreter.clear();
2414 optionalArgument.clear();
2415 hasOptionalArgument =
false;
2417 if (bytesRead < 2 || contents[0] !=
'#' || contents[1] !=
'!') {
2418 PS_NOTICE(
"no shebang found");
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]) {
2432 const size_t boundedLineEnd = lineEnd;
2433 while (lineEnd > 2 && (contents[lineEnd - 1] ==
' ' || contents[lineEnd - 1] ==
'\t')) {
2437 size_t interpreterBegin = 2;
2438 while (interpreterBegin < lineEnd &&
2439 (contents[interpreterBegin] ==
' ' || contents[interpreterBegin] ==
'\t')) {
2442 if (interpreterBegin == lineEnd) {
2443 PS_NOTICE(
"empty shebang interpreter");
2444 SYSCALL_ERROR(ExecFormatError);
2448 size_t interpreterEnd = interpreterBegin;
2449 while (interpreterEnd < lineEnd && contents[interpreterEnd] !=
' ' &&
2450 contents[interpreterEnd] !=
'\t') {
2453 if (interpreterEnd == lineEnd && lineEnd == boundedLineEnd && !terminated) {
2454 PS_NOTICE(
"truncated shebang interpreter");
2455 SYSCALL_ERROR(ExecFormatError);
2459 interpreter.assign(contents + interpreterBegin, interpreterEnd - interpreterBegin,
true);
2461 size_t argumentBegin = interpreterEnd;
2462 while (argumentBegin < lineEnd &&
2463 (contents[argumentBegin] ==
' ' || contents[argumentBegin] ==
'\t')) {
2466 if (argumentBegin < lineEnd) {
2467 optionalArgument.assign(contents + argumentBegin, lineEnd - argumentBegin,
true);
2468 hasOptionalArgument =
true;
2474static File* executableFile(
File* file) {
2476 SYSCALL_ERROR(DoesNotExist);
2480 SYSCALL_ERROR(IsADirectory);
2486 SYSCALL_ERROR(ExecFormatError);
2493 SyscallState* state) {
2495 String originalName(name);
2500 if (!originalFile) {
2501 PS_NOTICE(
"PosixSubsystem::invoke: could not find file '" << originalName <<
"'");
2502 SYSCALL_ERROR(DoesNotExist);
2506 return invoke(originalFile, originalName, argv, env, state,
false, originalLease.path());
2511 return invoke(originalFile, originalName, argv, env, 0);
2516 return invoke(originalFile, originalName, argv, env, &state,
false);
2521 bool descriptorPathInaccessible) {
2522 return invoke(originalFile, originalName, argv, env, &state, descriptorPathInaccessible);
2527 bool descriptorPathInaccessible) {
2528 return invoke(originalPath ? originalPath->node() : nullptr, originalName, argv, env, &state,
2529 descriptorPathInaccessible, originalPath);
2534 bool descriptorPathInaccessible,
2536 PS_NOTICE(
"PosixSubsystem::invoke(" << originalName <<
")");
2538 uint8_t execRandom[16];
2539 ByteSet(execRandom, 0,
sizeof(execRandom));
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");
2547 const bool hasExecRandom =
false;
2556 SYSCALL_ERROR(NoMoreProcesses);
2561 originalTargetLease.retain(originalPath);
2562 originalFile = executableFile(originalFile);
2563 if (!originalFile) {
2568 String candidateName(originalName);
2569 static constexpr size_t MaximumShebangRewrites = 4;
2570 size_t shebangRewrites = 0;
2571 bool allExecutableFilesReadable =
true;
2578 allExecutableFilesReadable &= posix_exec_file_readable(originalFile);
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' &&
2587 PS_NOTICE(
"PosixSubsystem::invoke: '" << originalFile->
getName()
2588 <<
"' is not an ELF binary, looking for shebang...");
2590 String shebangInterpreter;
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() <<
"'");
2599 if (!shebangInterpreter.length()) {
2600 SYSCALL_ERROR(ExecFormatError);
2604 if (!shebangRewrites && descriptorPathInaccessible) {
2606 SYSCALL_ERROR(DoesNotExist);
2610 if (shebangRewrites == MaximumShebangRewrites) {
2611 SYSCALL_ERROR(LoopExists);
2616 String resolvedInterpreter(shebangInterpreter);
2617 String normalisedInterpreter;
2618 if (normalisePath(normalisedInterpreter, resolvedInterpreter.cstr())) {
2619 resolvedInterpreter = normalisedInterpreter;
2625 PS_NOTICE(
"PosixSubsystem::invoke: could not find shebang interpreter '"
2626 << resolvedInterpreter <<
"'");
2627 SYSCALL_ERROR(DoesNotExist);
2631 shebangFile = executableFile(shebangFile);
2640 if (hasShebangArgument) {
2645 originalFile = shebangFile;
2646 candidateName = shebangInterpreter;
2647 originalTargetLease.swap(nextLease);
2652 size_t argumentBytes = 2 *
sizeof(uintptr_t);
2653 if (originalName.length() >= MaximumExecArgumentBytes - argumentBytes) {
2654 SYSCALL_ERROR(TooBig);
2657 argumentBytes += originalName.length() + 1;
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);
2666 argumentBytes +=
sizeof(uintptr_t) + (*list)[i].length() + 1;
2671 File* interpreterFile = 0;
2679 originalImage.openingPath = originalTargetLease.path();
2685 if (originalImage.metadata.hasInterpreter) {
2686 String interpreter(originalImage.interpreter);
2690 String normalisedInterpreter;
2691 if (normalisePath(normalisedInterpreter, interpreter.cstr())) {
2692 interpreter = normalisedInterpreter;
2696 interpreterFile = findFileRetained(interpreter, interpreterLease,
FilesystemPathRef(),
true);
2697 interpreterFile = executableFile(interpreterFile);
2698 if (!interpreterFile) {
2699 PS_NOTICE(
"PosixSubsystem::invoke: could not find interpreter '" << interpreter <<
"'");
2706 allExecutableFilesReadable &= posix_exec_file_readable(interpreterFile);
2708 interpreterImage.openingPath = interpreterLease.path();
2712 if (interpreterImage.metadata.hasInterpreter) {
2713 SYSCALL_ERROR(BadSharedLibrary);
2719 interpreterFile = 0;
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);
2732 if (!m_Namespaces || !m_Namespaces->valid()) {
2733 SYSCALL_ERROR(OutOfMemory);
2737 if (
m_TraceContext.prepareTask(initialTrace) != TraceStatus::Success) {
2738 SYSCALL_ERROR(OutOfMemory);
2742 if (!m_Namespaces->acquireThread(*pThread, currentUts)) {
2743 posix_uts_error(UtsStatus::Missing);
2746 const UtsStatus prepared = posix_uts_prepare_thread(currentUts,
false, initialUts);
2747 if (prepared != UtsStatus::Success) {
2748 posix_uts_error(prepared);
2757 if (!execScope.commit()) {
2758 SYSCALL_ERROR(Interrupted);
2762 if (pProcess->getType() == Process::Posix)
2763 static_cast<PosixProcess*
>(pProcess)->markExecCommitted();
2767 m_ExecutablePath = originalTargetLease.path();
2768 m_CommandLine = pedigree_std::move(committedCommandLine);
2771 invalidateUserImage();
2773 posix_timer_process_exit(pProcess);
2782 if (pProcess->isVforkChild())
2783 clearChildTid(pThread);
2786 posix_robust_list_exit(pThread);
2787 const size_t previousTaskId = pThread->
getTaskId();
2788 execScope.adoptLeaderIdentity();
2789 m_Namespaces->promoteExec(*pThread);
2794 trace->imageCommitted();
2796 procfsInvalidateNamespaceTask(m_Namespaces, pProcess->
getUserspaceId(), previousTaskId);
2797 procfsInvalidateNamespaceTask(m_Namespaces, pProcess->
getUserspaceId(), pProcess->
getId());
2799 pProcess->setLinker(
nullptr);
2804 if (m_CallbackSchedulingDomain == CallbackSchedulingDomain::LegacySignals)
2805 m_CallbackSchedulingDomain = CallbackSchedulingDomain::Unrestricted;
2811 pProcess->resetUserReservations();
2813 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
2815 pProcess->
getAddressSpace()->rawUserMemory().setCompleteInventory(X64 && !HOSTED);
2825 pedigree_init_sigret();
2827 auto failAfterCommit = [pThread](Error::PosixError error) {
2828 syscallError(error);
2834 uintptr_t originalLoadBias = 0;
2835 if (!
loadElf(originalImage, originalLoadBias)) {
2836 PS_NOTICE(
"PosixSubsystem::invoke: failed to load target");
2837 return failAfterCommit(Error::OutOfMemory);
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);
2847 const uintptr_t originalEntryPoint = originalLoadBias + originalImage.metadata.entryPoint;
2848 uintptr_t interpreterEntryPoint = 0;
2849 if (interpreterFile) {
2850 interpreterEntryPoint = interpreterLoadBias + interpreterImage.metadata.entryPoint;
2852 if (!interpreterFile) {
2853 interpreterEntryPoint = originalEntryPoint;
2858 pProcess->resetCounts();
2863 if (pProcess->getType() == Process::Posix) {
2866 p->commitExecCredentials(*pThread, allExecutableFilesReadable);
2867 execCredentials = p->snapshotCredentials();
2869 execCredentials.ruid = pProcess->
getUserId();
2870 execCredentials.euid = pProcess->getEffectiveUserId();
2871 execCredentials.rgid = pProcess->getGroupId();
2872 execCredentials.egid = pProcess->getEffectiveGroupId();
2878 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec;
2879 uintptr_t vdsoAddress = 0;
2883 PS_NOTICE(
"PosixSubsystem::invoke: failed to map VDSO");
2886 MemoryCopy(
reinterpret_cast<void*
>(vdsoAddress), __vdso_so, __vdso_so_len);
2892 vdsoPerms & ~MemoryMappedObject::Write);
2901 reinterpret_cast<void*
>(POSIX_VSYSCALL_ADDRESS))) {
2902 physical_uintptr_t vsyscallBase = 0;
2903 size_t vsyscallFlags = 0;
2905 vsyscallBase, vsyscallFlags);
2907 vsyscallBase,
reinterpret_cast<void*
>(POSIX_VSYSCALL_ADDRESS),
2915 if (!stack || !stack->getTop()) {
2917 ERROR(
"PosixSubsystem::invoke: failed to allocate initial user stack");
2918 return failAfterCommit(Error::OutOfMemory);
2922 if (stack->getSize() < argumentBytes + 512) {
2924 return failAfterCommit(Error::TooBig);
2929 uintptr_t* loaderStack =
reinterpret_cast<uintptr_t*
>(stack->getTop());
2932 STACK_PUSH(loaderStack, 0);
2935 STACK_ALIGN(loaderStack, 16);
2938 char** envs =
new char*[env.
count()];
2940 for (
size_t i = 0; i < env.
count(); ++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);
2948 STACK_ALIGN(loaderStack, 16);
2950 char** argvs =
new char*[argv.
count()];
2952 for (
size_t i = 0; i < argv.
count(); ++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);
2960 STACK_ALIGN(loaderStack, 16);
2963 STACK_PUSH_STRING(loaderStack,
"aarch64", 8);
2965 STACK_PUSH_STRING(loaderStack,
"v7l", 4);
2967 STACK_PUSH_STRING(loaderStack,
"x86_64", 7);
2969 void* platform = loaderStack;
2971 STACK_PUSH_STRING(loaderStack, originalName.cstr(), originalName.length() + 1);
2972 void* execfn = loaderStack;
2975 STACK_ALIGN(loaderStack, 16);
2977 STACK_PUSH_COPY(loaderStack, execRandom,
sizeof(execRandom));
2978 void* random = loaderStack;
2981 if (((argc + envc) % 2) == 0) {
2982 STACK_PUSH_ZEROES(loaderStack, 8);
2986 STACK_PUSH2(loaderStack, 0, 0);
2987 STACK_PUSH2(loaderStack,
reinterpret_cast<uintptr_t
>(platform), 15);
2988 if (hasExecRandom) {
2989 STACK_PUSH2(loaderStack,
reinterpret_cast<uintptr_t
>(random), 25);
2991 STACK_PUSH2(loaderStack, 0, 1);
2993 STACK_PUSH2(loaderStack, 0, 23);
2994 STACK_PUSH2(loaderStack, execCredentials.egid, 14);
2995 STACK_PUSH2(loaderStack, execCredentials.rgid, 13);
2996 STACK_PUSH2(loaderStack, execCredentials.euid, 12);
2997 STACK_PUSH2(loaderStack, execCredentials.ruid, 11);
2998 STACK_PUSH2(loaderStack,
reinterpret_cast<uintptr_t
>(execfn), 31);
3002#if !HOSTED && !ARM64 && !ARMV7
3005 STACK_PUSH2(loaderStack, 0, 32);
3006 STACK_PUSH2(loaderStack, vdsoAddress, 33);
3011 STACK_PUSH2(loaderStack, originalEntryPoint, 9);
3012 STACK_PUSH2(loaderStack, interpreterLoadBias, 7);
3014 STACK_PUSH2(loaderStack, originalImage.metadata.programHeaderCount, 5);
3016 STACK_PUSH2(loaderStack, originalLoadBias + originalImage.programHeaderAddress,
3020 STACK_PUSH(loaderStack, 0);
3021 for (
size_t i = 0; i < envc; ++i) {
3022 STACK_PUSH(loaderStack,
reinterpret_cast<uintptr_t
>(envs[i]));
3027 STACK_PUSH(loaderStack, 0);
3028 for (ssize_t i = argc - 1; i >= 0; --i) {
3029 STACK_PUSH(loaderStack,
reinterpret_cast<uintptr_t
>(argvs[i]));
3034 STACK_PUSH(loaderStack, argc);
3043 return failAfterCommit(Error::ValueTooLarge);
3049 loaderStack,
false,
false,
true, &placement);
3051 invalidateUserImage();
3053 return failAfterCommit(Error::OutOfMemory);
3055 m_Namespaces->publishThread(initialUts, *pNewThread,
true);
3056 if (
m_TraceContext.publishTask(initialTrace, *pNewThread) != TraceStatus::Success &&
3058 FATAL(
"Initial trace task publication failed");
3060 pNewThread->setName(
"ld.so thread");
3062 FATAL(
"PosixSubsystem::invoke: initial user Thread could not be started.");
3069 ByteSet(&s, 0,
sizeof(s));
3070 pThread->
state() = s;
3073 reinterpret_cast<uintptr_t
>(loaderStack))) {
3074 ERROR(
"PosixSubsystem::invoke: exec userspace jump was not dispatched");
3075 return failAfterCommit(Error::IoError);
3078 return failAfterCommit(Error::ValueTooLarge);
Memory-mapped file interface.
Implements a Radix Tree, a kind of Trie with compressed keys.
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)
uintptr_t getHandlerAddress()
bool test(size_t n) const
size_t fd
Descriptor number.
virtual void getFullPath(String &result, bool bWithMount=true)
size_t readCached(uint64_t location, size_t size, uintptr_t buffer, bool(*prepare)(uintptr_t, size_t)=nullptr)
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
bool supportsRegularFileOperations()
virtual bool isDirectory()
virtual uintptr_t futexIdentity()
bool acquireMappingUse(bool executable, bool sharedWrite)
::Iterator< T, node_t > Iterator
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)
void checkEventState(uintptr_t userStack)
static constexpr size_t getPageSize() PURE
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
UnlikelyLock m_SignalHandlersLock
size_t getFd(size_t minimum=0)
static UserStringResult copyUserString(const char *userString, String ©, 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
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
void setExitStatus(int code)
bool beginTermination(int code=0, Subsystem::ExitCause cause=Subsystem::ExitCause::Normal)
bool quiesceTermination()
MUST_USE_RESULT bool acquireProcessSignalThread(ThreadLease &lease)
VirtualAddressSpace * getAddressSpace()
LargeStaticString & description()
void releaseVforkAddressSpace()
MUST_USE_RESULT bool acquireThread(ThreadLease &lease, size_t n)
Time::Timestamp getUserTime() const
virtual int64_t getUserId() const
size_t getContinuationEpoch()
void finishTermination(bool notifyParent=false) NORETURN
static bool getInterrupts()
static ProcessorInformation & information()
static bool inDeviceHardIrq()
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static void setInterrupts(bool bEnable)
T * exchange(T *replacement)
static Scheduler & instance()
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
void setSignalOrigin(int32_t signalCode, int32_t senderProcess, uint32_t senderUser)
void setContinuationEpoch(size_t continuationEpoch)
virtual Event * cloneForDelivery()
bool acquire(bool recurse=false, bool safe=true)
virtual void setProcess(Process *p)
static EXPORTED_PUBLIC SyscallManager & instance()
void discardUserStackMetadataForExec()
void setErrno(size_t err)
void setUnwindState(UnwindType ut)
@ Continue
No unwind necessary, carry on as normal.
@ TerminateThread
Exit only this thread during Process exit.
bool transferProcessSignalsTo(Thread &target)
bool replaceSignalEvent(size_t signalNumber, Event *replacement, int processDirected=-1, uint64_t rebindGeneration=0)
bool hasSignalEvent(size_t signalNumber, int processDirected=-1)
void deferSignalExit(int signal)
int(* ThreadStartFunc)(void *)
UnwindType getUnwindState()
void setClearChildTid(uintptr_t address)
uintptr_t takeClearChildTid()
Process * getParent() const
void cullSignalEvent(size_t signalNumber)
class PerProcessorScheduler * getScheduler() const
bool sendEvent(Event *pEvent)
void notifySubsystemExit()
void adoptInitialUserStackForExec(VirtualAddressSpace::Stack *stack)
An iterator applicable for many data structures.
E lookup(const K &key) const
void insert(const K &key, const E &value)
const E & lookupRef(const K &key, const E &failed=E()) const
bool take(const K &key, E &element)
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
A vector / dynamic array.
static const size_t CopyOnWrite
virtual uintptr_t getUserReservedStart() const =0
virtual bool isMapped(void *virtualAddress)=0
virtual void revertToKernelAddressSpace()=0
virtual uintptr_t getUserStart() const =0
static const size_t KernelMode
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
static const size_t NoAccess
static const size_t Write
static const size_t WriteProtected
static const size_t Execute
virtual uintptr_t getKernelStart() const =0
virtual bool isAddressValid(void *virtualAddress)=0
void pushBack(const T &value)
void pushFront(const T &value)
void pushBack(const T &value)
void clear(bool freeMem=false)
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.