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"
54#include "linux-amd64-signal.h"
56#include "modules/system/linker/DynamicLinker.h"
57#include "modules/system/vfs/File.h"
59#include "modules/system/vfs/MountView.h"
60#include "modules/system/vfs/Symlink.h"
61#include "modules/system/vfs/VFS.h"
62#include "mqueue-syscalls.h"
63#include "posix-timer-syscalls.h"
64#include "pthread-syscalls.h"
65#include "queued-signal.h"
66#include "sandbox-state.h"
67#include "signal-syscalls.h"
68#include "signalfd-syscalls.h"
69#include "system-syscalls.h"
70#include "sysv-semaphore-syscalls.h"
71#include "timerfd-syscalls.h"
72#include "user-namespace.h"
75extern char __posix_compat_vsyscall_base;
76#define POSIX_VSYSCALL_ADDRESS 0xffffffffff600000
90 : fd(number), descriptor(owner) {}
99extern void pedigree_init_sigret();
100extern void pedigree_init_pthreads();
105 file->releaseMappingUse(
true,
false);
108 File* file =
nullptr;
112 uintptr_t programHeaderAddress = 0;
117bool validUserAddressRange(uintptr_t address,
size_t extent) {
118 if (extent - 1 > (~
static_cast<uintptr_t
>(0) - address)) {
121 const uintptr_t end = address + extent - 1;
128bool prepareUserCopy(uintptr_t address,
size_t extent,
bool write) {
134 if (!validUserAddressRange(address, extent)) {
141void ignoredSignal(
int) {}
143bool defaultSignalActionIsIgnore(
size_t signal) {
144 return signal == SIGCHLD || signal == SIGURG || signal == SIGWINCH;
147bool defaultSignalActionIsStop(
size_t signal) {
148 return signal == SIGSTOP || signal == SIGTSTP || signal == SIGTTIN || signal == SIGTTOU;
152 if (process && delivery && defaultSignalActionIsStop(signal)) {
157bool rebindQueuedSignalEvents(
Thread& thread,
size_t signal,
SignalEvent& prototype) {
158 static uint64_t nextGeneration = 0;
159 const uint64_t generation = __atomic_add_fetch(&nextGeneration, 1, __ATOMIC_RELAXED);
171void setExecutableValidationError(Elf::ExecutableValidationResult result,
bool isInterpreter) {
173 SYSCALL_ERROR(BadSharedLibrary);
174 }
else if (result == Elf::ExecutableValidationResult::MultipleInterpreters) {
175 SYSCALL_ERROR(InvalidArgument);
177 SYSCALL_ERROR(ExecFormatError);
182ProcessGroupManager::ProcessGroupManager() : m_GroupIds(), m_Groups(nullptr), m_GroupLock(false) {
186ProcessGroupManager::~ProcessGroupManager() {}
190 size_t bit = m_GroupIds.getFirstClear();
191 while (findGroup(bit) || m_GroupIds.test(bit))
199 if (m_GroupIds.test(gid)) {
201 "ProcessGroupManager: setGroupId called on a group ID that "
209 return findGroup(gid) || m_GroupIds.test(gid);
214 m_GroupIds.clear(gid);
219 assert(!findGroup(gid));
220 group->registryNext = m_Groups;
222 group->registered =
true;
225void ProcessGroupManager::unregisterGroup(
size_t gid,
ProcessGroup* group) {
228 while (*link && *link != group)
229 link = &(*link)->registryNext;
231 *link = group->registryNext;
232 group->registryNext =
nullptr;
233 group->registered =
false;
238 for (
ProcessGroup* group = m_Groups; group; group = group->registryNext)
239 if (
static_cast<size_t>(group->processGroupId) == gid)
248 for (
ProcessGroup* group = m_Groups; group; group = group->registryNext) {
249 if (group->identity && group->identity->id(space) == gid) {
260 m_CallbackSchedulingDomain(s.m_CallbackSchedulingDomain),
262 m_MemoryLockAccount(s.m_MemoryLockAccount),
273 m_NextThreadWaiter(1),
274 m_ImageMetadataLock(),
282 m_ExecutablePath = s.m_ExecutablePath;
283 m_CommandLine = s.m_CommandLine;
293 size_t key = it.key();
294 void* value = it.value();
300 if (clearSignalHandlers && original->type != 2) {
304 newSig->
pEvent =
new SignalEvent(pedigree_default_signal_handler(key), key, ~0UL, 0,
true,
305 false, Event::HandlerPrivilege::Kernel,
306 SignalEvent::DeliveryDisposition::DefaultAction);
310 m_SignalHandlers.insert(key, newSig);
320 void* key = it.key();
326 m_NextThreadWaiter = s.m_NextThreadWaiter;
333 m_PendingSignals->attach(m_pProcess);
334 if (process && m_Namespaces)
335 m_Namespaces->attach(*process);
340 space.setMemoryLockAccount(&m_MemoryLockAccount);
344bool PosixSubsystem::executablePath(
String& result)
const {
346 if (!m_ExecutablePath || !m_pProcess)
348 auto context = m_pProcess->acquireFilesystemContext();
351 return context && context->snapshot(snapshot) && view &&
352 view->formatPath(snapshot, m_ExecutablePath, result);
357 result = m_ExecutablePath;
358 return static_cast<bool>(result);
363 result = m_CommandLine;
364 return result.
count() != 0;
367bool PosixSubsystem::snapshotUserImage(UserImageToken& token)
const {
370 if (!m_UserImageActive)
372 token.space = m_UserImageSpace;
373 token.generation = m_UserImageGeneration;
377bool PosixSubsystem::matchesUserImage(
const UserImageToken& token)
const {
379 return m_UserImageActive && token.space == m_UserImageSpace &&
380 token.generation == m_UserImageGeneration;
383void PosixSubsystem::invalidateUserImage() {
385 m_UserImageActive =
false;
386 m_UserImageSpace =
nullptr;
391 if (m_UserImageActive || !m_pProcess || m_pProcess->
getAddressSpace() != &space ||
392 m_UserImageGeneration == ~uint64_t(0))
394 ++m_UserImageGeneration;
395 m_UserImageSpace = &space;
396 m_UserImageActive =
true;
404 if (m_pProcess && m_pProcess->isVforkChild()) {
408 invalidateUserImage();
414 m_Namespaces->close();
415 m_PendingSignals->close();
432 m_SignalHandlers.clear();
438 posix_advisory_owner_closed(m_AdvisoryOwner);
450 if (!thread->isRunning.isComplete()) {
451 WARNING(
"PosixSubsystem object freed when a thread is still running?");
480 delete reinterpret_cast<Mutex*
>(p->pObject);
482 delete reinterpret_cast<Semaphore*
>(p->pObject);
501 invalidateUserImage();
526 va->rawUserMemory().clear();
527 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
528 va->setMemoryLockAccount(
nullptr);
534void PosixSubsystem::acquireFdLock() {
536 FATAL(
"PosixSubsystem could not acquire its descriptor table");
582 PS_NOTICE(
"PosixSubsystem::checkAddress(" <<
Hex << addr <<
", " <<
Dec << extent <<
", " <<
Hex
589 PS_NOTICE(
" -> zero extent, address is sane.");
594 uintptr_t aa =
reinterpret_cast<uintptr_t
>(__builtin_return_address(0));
596 PS_NOTICE(
" -> ret: " << aa);
601 if (!validUserAddressRange(addr, extent)) {
603 PS_NOTICE(
" -> outside of user address area.");
607 const uintptr_t end = addr + extent - 1;
612 if (flags & SafeRead) {
613 mmapPermissions |= MemoryMappedObject::Read;
615 if (flags & SafeWrite) {
616 mmapPermissions |= MemoryMappedObject::Write;
618 if (flags & SafeExecute) {
619 mmapPermissions |= MemoryMappedObject::Exec;
624 if (mmapPermissions != MemoryMappedObject::None &&
627 PS_NOTICE(
" -> inside memory map.");
635 uintptr_t page = addr - (addr % pageSize);
636 uintptr_t finalPage = end - (end % pageSize);
638 void* pAddr =
reinterpret_cast<void*
>(page);
641 PS_NOTICE(
" -> page " <<
Hex << pAddr <<
" is not mapped.");
647 physical_uintptr_t phys = 0;
652 PS_NOTICE(
" -> not userspace-accessible.");
657 if (flags & SafeWrite) {
661 PS_NOTICE(
" -> not writeable.");
669 PS_NOTICE(
" -> not executable.");
674 if (page == finalPage) {
681 PS_NOTICE(
" -> mapped and available.");
688 if (!count || !elementSize) {
692 if (count > (~
static_cast<size_t>(0) / elementSize)) {
696 extent = count * elementSize;
706 size_t byteExtent = 0;
712 *extent = byteExtent;
717 return !byteExtent || validUserAddressRange(addr, byteExtent);
727 size_t byteExtent = 0;
733 *extent = byteExtent;
739 size_t elementSize) {
747 if (!destination || !source) {
752 if (!prepareUserCopy(
reinterpret_cast<uintptr_t
>(source), extent,
false)) {
756 MemoryCopy(destination, source, extent);
761 size_t elementSize) {
769 if (!destination || !source) {
774 if (!prepareUserCopy(
reinterpret_cast<uintptr_t
>(destination), extent,
true)) {
778 MemoryCopy(destination, source, extent);
785 !validUserAddressRange(
reinterpret_cast<uintptr_t
>(destination), count)) {
791 offset, count,
reinterpret_cast<uintptr_t
>(destination), [](uintptr_t address,
size_t bytes) {
797 String& copy,
size_t maxLength) {
801 return UserStringBadAddress;
805 return UserStringTooLong;
811 const size_t chunkSize = 256;
812 uintptr_t current =
reinterpret_cast<uintptr_t
>(userString);
815 while (copied < maxLength) {
816 size_t length = maxLength - copied;
817 if (length > chunkSize) {
821 const size_t pageOffset = current % pageSize;
822 const size_t pageRemaining = pageSize - pageOffset;
823 if (length > pageRemaining) {
824 length = pageRemaining;
827 if (!prepareUserCopy(current, length,
false)) {
828 return UserStringBadAddress;
831 char buffer[chunkSize];
832 MemoryCopy(buffer,
reinterpret_cast<const void*
>(current), length);
834 size_t partLength = 0;
835 while (partLength < length && buffer[partLength]) {
839 if (partLength != length) {
840 copy +=
String(buffer, partLength,
true);
841 return UserStringSuccess;
844 copy +=
String(buffer, length,
true);
846 if (copied == maxLength) {
847 return UserStringTooLong;
850 if (current > (~
static_cast<uintptr_t
>(0) - length)) {
851 return UserStringBadAddress;
856 return UserStringTooLong;
862 "PosixSubsystem::exit requires an IRQ-enabled thread "
869 NOTICE(
"PosixSubsystem::exit(" <<
Dec << pProcess->
getId() <<
", code=" << code <<
")");
878 if (cause == ExitCause::Signal) {
892 FATAL(
"POSIX exit owner could not claim process teardown for pid " <<
Dec << pProcess->
getId()
900 "POSIX process teardown escaped its IRQ-enabled thread "
906 static_cast<PosixProcess*
>(pProcess)->snapshotAccountingMemory();
908 posix_advisory_owner_closed(m_AdvisoryOwner);
912 m_PendingSignals->close();
913 posix_timer_process_exit(pProcess);
914 invalidateUserImage();
922 delete pProcess->getLinker();
929 space.rawUserMemory().clear();
930 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
931 space.setMemoryLockAccount(
nullptr);
937 posix_mqueue_process_exit(pProcess->
getId());
943 NOTICE(
"at exit for pid " <<
Dec << pProcess->
getId() <<
"...");
948 FATAL(
"PosixSubsystem::exit() running after Process teardown!");
955 if (pProcess->getType() != Process::Posix) {
956 ERROR(
"PosixSubsystem::kill called with a non-POSIX process!");
961 int signal = SIGKILL;
962 switch (killReason) {
976 SignalDeliveryResult::Queued) {
977 PS_NOTICE(
"PosixSubsystem - killing " << pThread->
getParent()->
getId());
988 uintptr_t faultAddress, uintptr_t errorCode) {
989 constexpr uintptr_t present = 1, write = 2, user = 4, fetch = 16;
992 thread.
getParent()->getSubsystem() !=
this ||
994 (errorCode & ~(present | write | user | fetch)) ||
995 ((errorCode & write) && (errorCode & fetch))) {
999 if (!(errorCode & user))
1003 faultAddress, errorCode & write, errorCode & present, errorCode & fetch);
1004 if (resolution == MemoryMapManager::FaultResolution::BackingFault) {
1005 threadException(&thread, FileMappingFault, &state, faultAddress, errorCode);
1008 return resolution == MemoryMapManager::FaultResolution::Resolved;
1012 uintptr_t faultAddress, uintptr_t errorCode) {
1014 EMIT_IF(POSIX_LOG_FACILITIES & 16) {
1015 if (pState && eType == PageFault) {
1018 PS_NOTICE(
"USERFAULT address=" <<
Hex << faultAddress);
1019 PS_NOTICE(
"USERFAULT code=" <<
Hex << errorCode);
1020 PS_NOTICE(
"USERFAULT rip=" <<
Hex << pState->getInstructionPointer());
1021 PS_NOTICE(
"USERFAULT rsp=" <<
Hex << pState->getStackPointer());
1022 PS_NOTICE(
"USERFAULT entry-fs=" <<
Hex << pState->getUserEntryMetadata().fsBase);
1023 PS_NOTICE(
"USERFAULT entry-gs=" <<
Hex << pState->getUserEntryMetadata().gsBase);
1024 PS_NOTICE(
"USERFAULT tls=" <<
Hex << pThread->
getTlsBase());
1025 for (
size_t i = 0; i < pState->getRegisterCount(); ++i) {
1026 PS_NOTICE(
"USERFAULT " << pState->getRegisterName(i) <<
"=" <<
Hex
1027 << pState->getRegister(i));
1037 PS_NOTICE(
"PosixSubsystem::threadException -> " <<
Dec << pThread->
getParent()->
getId() <<
":"
1038 << pThread->
getId());
1044 PS_NOTICE(
" (Page fault)");
1048 case FileMappingFault:
1052 PS_NOTICE(
" (Invalid opcode)");
1056 case GeneralProtectionFault:
1057 PS_NOTICE(
" (General Fault)");
1062 PS_NOTICE(
" (Division by zero)");
1067 PS_NOTICE(
" (FPU error)");
1071 case SpecialFpuError:
1072 PS_NOTICE(
" (FPU error - special)");
1078 " (Attempt to read from terminal by non-foreground "
1083 case TerminalOutput:
1084 PS_NOTICE(
" (Output to terminal by non-foreground process)");
1089 PS_NOTICE(
" (Continuing a stopped process)");
1094 PS_NOTICE(
" (Stopping a process)");
1099 PS_NOTICE(
" (Interrupting a process)");
1104 PS_NOTICE(
" (Requesting quit)");
1109 PS_NOTICE(
" (Child status changed)");
1114 PS_NOTICE(
" (Pipe broken)");
1119 PS_NOTICE(
" (Unknown)");
1121 ERROR(
"Unknown exception type in threadException - POSIX subsystem");
1126 if (signal > 0 && pState &&
getAbi() == LinuxAbi) {
1127 if (traceException(*pThread, signal, *pState, eType, faultAddress, errorCode))
1131 LinuxAmd64Signal::DeliveryResult result = LinuxAmd64Signal::deliverSynchronous(
1132 pThread, signal, disposition, eType, *pState, faultAddress, errorCode);
1133 if (result == LinuxAmd64Signal::Delivered) {
1136 if (result == LinuxAmd64Signal::Failed) {
1150 const bool processDirected = eType == TerminalInput || eType == TerminalOutput ||
1151 eType == Continue || eType == Stop || eType == Interrupt ||
1152 eType == Quit || eType == Child;
1153 sendSignal(pThread, signal, pState ==
nullptr, processDirected);
1157 PS_NOTICE(
"PosixSubsystem::sendSignal #" << signal <<
" -> pid:tid " <<
Dec
1159 << pThread->
getId());
1162 if (pProcess->getType() != Process::Posix) {
1163 ERROR(
"PosixSubsystem::threadException called with a non-POSIX process!");
1168 const SignalDeliveryResult result =
1170 if (result == SignalDeliveryResult::Unavailable) {
1171 ERROR(
"Unknown signal in sendSignal - POSIX subsystem");
1174 if (result == SignalDeliveryResult::Queued && yield) {
1176 if (pCurrentThread == pThread) {
1183 }
else if (result == SignalDeliveryResult::Rejected) {
1186 NOTICE(
"No event configured for signal #" << signal <<
", silently dropping!");
1190bool PosixSubsystem::admitLegacyUserSignals() {
1193 if (m_CallbackSchedulingDomain == CallbackSchedulingDomain::Affinity ||
1198 m_CallbackSchedulingDomain = CallbackSchedulingDomain::LegacySignals;
1203 if (sig > MaximumSupportedSignal) {
1205 ERROR(
"Cannot install unsupported signal disposition " <<
Dec << sig <<
".");
1216 removal = m_SignalHandlers.lookup(sig);
1219 m_SignalHandlers.remove(sig);
1225 m_SignalHandlers.insert(sig, handler);
1227 const bool discardPending =
1228 handler->
type == 2 || (handler->
type == 1 && defaultSignalActionIsIgnore(sig));
1235 if (discardPending) {
1237 }
else if (handler->
pEvent) {
1240 rebindQueuedSignalEvents(*thread.get(), sig, *handler->
pEvent);
1247 m_PendingSignals->recordChange();
1260 FATAL(
"Exec signal reset requires the sole surviving process thread.");
1263 for (
size_t signal = 0; signal < SignalDispositionCount; ++signal) {
1264 if (!handlers[signal] || !handlers[signal]->pEvent ||
1265 handlers[signal]->pEvent->getNumber() != signal) {
1266 FATAL(
"Exec signal reset received an incomplete disposition table.");
1275 for (
size_t signal = 0; signal < SignalDispositionCount; ++signal) {
1277 replacement->
sig = signal;
1279 removals[signal] = m_SignalHandlers.lookup(signal);
1280 if (removals[signal]) {
1281 m_SignalHandlers.remove(signal);
1283 m_SignalHandlers.insert(signal, replacement);
1285 if (!rebindQueuedSignalEvents(*thread, signal, *replacement->
pEvent)) {
1286 FATAL(
"Exec signal reset could not rebind a pending signal.");
1290 m_PendingSignals->recordChange();
1299 bool beginDelivery) {
1300 if (sig > MaximumSupportedSignal) {
1304 if (beginDelivery) {
1314 disposition.signalMask = handler->
sigMask;
1315 disposition.flags = handler->
flags;
1316 disposition.restorer = handler->
restorer;
1317 disposition.type = handler->
type;
1319 if (beginDelivery && handler->
type == 0 && (handler->
flags & SA_RESETHAND)) {
1322 retired = handler->
pEvent;
1323 handler->
pEvent =
new SignalEvent(pedigree_default_signal_handler(sig), sig, ~0UL, 0,
true,
1324 false, Event::HandlerPrivilege::Kernel,
1325 SignalEvent::DeliveryDisposition::DefaultAction);
1333 if (beginDelivery) {
1341 return handler !=
nullptr;
1345 Thread* target,
size_t sig, uint32_t* flags, int32_t signalCode,
bool processDirected,
1356 if (!target || !target->
getParent() || target->
getParent()->getSubsystem() !=
this || !sig ||
1357 sig > MaximumSupportedSignal) {
1359 return SignalDeliveryResult::Unavailable;
1362 constexpr size_t StopSignals[] = {SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
1363 const size_t* signalsToDiscard =
nullptr;
1364 size_t signalsToDiscardCount = 0;
1365 size_t continueSignal = SIGCONT;
1366 if (sig == SIGCONT) {
1367 signalsToDiscard = StopSignals;
1368 signalsToDiscardCount =
sizeof(StopSignals) /
sizeof(StopSignals[0]);
1370 for (
size_t stopSignal : StopSignals) {
1371 if (sig == stopSignal) {
1372 signalsToDiscard = &continueSignal;
1373 signalsToDiscardCount = 1;
1380 auto pidNamespace = process->pidNamespace();
1381 if (pidNamespace && pidNamespace->parent() && !pidNamespace->dead() &&
1384 auto* senderProcess = sender ? sender->getParent() :
nullptr;
1385 const bool ancestor = !senderProcess || !senderProcess->getUserspaceId(pidNamespace.get());
1386 const auto* disposition = m_SignalHandlers.lookup(sig);
1387 const bool blocked =
1388 (target->
getSignalMask() | target->getSynchronousSignalMask()) & (uint64_t(1) << (sig - 1));
1389 if ((!disposition || disposition->type != 0) && !blocked &&
1390 !(ancestor && (sig == SIGKILL || sig == SIGSTOP))) {
1392 return SignalDeliveryResult::Rejected;
1395 if (processDirected) {
1400 return SignalDeliveryResult::Rejected;
1402 target = processTarget.get();
1404 for (
unsigned pass = 0; pass < 2; ++pass) {
1405 bool selected =
false;
1408 if (!process->
acquireThread(candidate, i - 1) || !candidate->acceptingEvents() ||
1411 const uint64_t bit = uint64_t(1) << (sig - 1);
1412 if ((pass == 0 && (candidate->getSynchronousSignalMask() & bit)) ||
1414 processTarget = pedigree_std::move(candidate);
1415 target = processTarget.get();
1424 if (signalsToDiscard) {
1430 for (
size_t n = 0; n < signalsToDiscardCount; ++n) {
1439 if (sig == SIGCONT) {
1443 trace->continued(*process);
1448 const bool ignored =
1449 handler && (handler->
type == 2 || (handler->
type == 1 && defaultSignalActionIsIgnore(sig)));
1450 const uint64_t bit = uint64_t(1) << (sig - 1);
1451 const bool blocked = (target->
getSignalMask() | target->getSynchronousSignalMask()) & bit;
1452 const bool suppressDelivery = ignored && !blocked && !target->requiresSignalFrames();
1455 if (ignored && !handler->
pEvent) {
1456 handler->
pEvent =
new SignalEvent(
reinterpret_cast<uintptr_t
>(ignoredSignal), sig, ~0UL, 0,
1457 true,
false, Event::HandlerPrivilege::Kernel,
1458 SignalEvent::DeliveryDisposition::DefaultAction);
1460 SignalDeliveryResult result = SignalDeliveryResult::Unavailable;
1461 if (suppressDelivery) {
1462 result = SignalDeliveryResult::Ignored;
1463 }
else if (handler && handler->
pEvent) {
1465 bool duplicate =
false;
1466 if (processDirected) {
1478 return SignalDeliveryResult::Queued;
1482 if (!deliveryState && (signalCode == -1 || sig >= 35)) {
1483 deliveryState = posix_signal_reserve_queue(process);
1484 if (!deliveryState) {
1486 return SignalDeliveryResult::Full;
1492 int32_t senderPid = 0;
1493 uint32_t senderUid = 0;
1494 if (senderProcess && senderProcess->getType() == Process::Posix) {
1496 static_cast<int32_t
>(senderProcess->
getUserspaceId(process->pidNamespace().
get()));
1497 const int64_t uid = senderProcess->
getUserId();
1499 senderUid =
static_cast<uint32_t
>(uid);
1502 static uint64_t nextSignalSequence = 0;
1503 delivery->setQueueSequence(__atomic_add_fetch(&nextSignalSequence, 1, __ATOMIC_RELAXED));
1504 delivery->setDeliveryState(deliveryState);
1505 if (sig == SIGCHLD && signalCode == 4 && senderProcess &&
1506 senderProcess->
getParent() == process) {
1507 delivery->setChildStatus(
static_cast<int32_t
>(signalValue),
1508 senderProcess->
getUserTime() / (Time::Multiplier::Second / 100),
1509 senderProcess->getKernelTime() / (Time::Multiplier::Second / 100));
1510 }
else if (sig == SIGCHLD && signalCode == 0 && senderProcess &&
1511 senderProcess->
getParent() == process &&
1512 senderProcess->getState() == Process::Terminated) {
1514 signalCode = (status & 0x7f) ? ((status & 0x80) ? 3 : 2) : 1;
1515 delivery->setChildStatus((status & 0x7f) ? (status & 0x7f) : ((status >> 8) & 0xff),
1516 senderProcess->
getUserTime() / (Time::Multiplier::Second / 100),
1517 senderProcess->getKernelTime() / (Time::Multiplier::Second / 100));
1520 delivery->setSignalValue(signalValue);
1521 delivery->setProcessDirected(processDirected);
1522 stampStopDelivery(process, sig, delivery);
1524 *flags = handler->
flags;
1528 result = SignalDeliveryResult::Queued;
1534 result = SignalDeliveryResult::Rejected;
1537 target = processTarget.get();
1542 m_PendingSignals->recordChange(result == SignalDeliveryResult::Queued ? sig : 0, target,
1544 if (delivery && result == SignalDeliveryResult::Rejected) {
1545 delivery->rejectSignalDelivery();
1564 const bool advancesGlobalHint = minimum <=
m_LastFd;
1566 for (
size_t i = firstCandidate; i <
m_NextFd; i++) {
1570 if (advancesGlobalHint) {
1613 publishFdEntry(fdNum);
1625 retireDescriptor(retiring.
get());
1645 pSubsystem->acquireFdLock();
1653 size_t newFd = it.key();
1656 assert(!pFd->networkImpl || pNewFd->networkPublished());
1666 retiring.
pushBack(pedigree_std::move(previous));
1677 for (
auto& descriptor : retiring) {
1678 retireDescriptor(descriptor.get());
1680 retiring.
clear(
true);
1685 assert(iFirst < iLast);
1703 bool bAllToBeFreed = ((iFirst == 0 && iLast == ~0UL) && !bOnlyCloExec);
1709 size_t Fd = it.key();
1714 if (!(Fd >= iFirst && Fd <= iLast))
1718 if (!(pFd->fdflags & FD_CLOEXEC))
1724 fdsToRemove.
pushBack(
reinterpret_cast<void*
>(Fd));
1734 if (
m_FdMap.
take(
reinterpret_cast<size_t>(*it), descriptor)) {
1735 retiring.
pushBack(pedigree_std::move(descriptor));
1739 if (retiring.
count()) {
1746 for (
auto& descriptor : retiring) {
1747 retireDescriptor(descriptor.get());
1749 retiring.
clear(
true);
1755 for (
auto* entry = m_FdEntries[fd % FdBuckets].load(guard); entry && entry->fd <= fd;
1756 entry = entry->next.load(guard)) {
1757 if (entry->fd == fd) {
1758 descriptor.retain(entry->descriptor);
1759 return static_cast<bool>(descriptor);
1765void PosixSubsystem::publishFdEntry(
size_t fd) {
1766 auto* link = &m_FdEntries[fd % FdBuckets];
1767 FdEntry* previous = link->loadForUpdate();
1768 while (previous && previous->fd < fd) {
1769 link = &previous->next;
1770 previous = link->loadForUpdate();
1772 FdEntry* retiring = previous && previous->fd == fd ? previous :
nullptr;
1773 FdEntry* following = retiring ? retiring->next.loadForUpdate() : previous;
1776 FdEntry* replacement = following;
1778 replacement =
new FdEntry(fd, current);
1780 FATAL(
"PosixSubsystem could not allocate its descriptor entry");
1783 replacement->next.exchange(following);
1787 link->exchange(replacement);
1797void PosixSubsystem::publishFdEntries() {
1800 FdEntry* previous[FdBuckets] = {};
1801 for (
size_t bucket = 0; bucket < FdBuckets; ++bucket) {
1802 tails[bucket] = &replacements[bucket];
1806 FdEntry* entry =
new FdEntry(it.key(), it.value());
1808 FATAL(
"PosixSubsystem could not allocate its descriptor entry");
1810 const size_t bucket = it.key() % FdBuckets;
1812 tails[bucket] = &entry->next;
1816 bool reclaim =
false;
1817 for (
size_t bucket = 0; bucket < FdBuckets; ++bucket) {
1818 previous[bucket] = m_FdEntries[bucket].exchange(replacements[bucket].loadForUpdate());
1819 reclaim |= previous[bucket] !=
nullptr;
1823 for (
auto* entry : previous) {
1825 FdEntry* next = entry->next.loadForUpdate();
1837 size_t selected = ~size_t(0);
1842 if (it.key() >= minimum && it.key() < selected && it.value()) {
1843 selected = it.key();
1844 retained = it.value();
1849 descriptor.retain(retained);
1866 const bool matches = current && current->m_OpenFile.
get() == expected.
get();
1878 bool removed =
false;
1885 if (current == descriptor.m_Descriptor) {
1903 retireDescriptor(retiring.
get());
1932 retireDescriptor(retiring.
get());
1938 size_t sourceFd,
size_t targetFd,
bool closeOnExec) {
1943 DescriptorDuplicationResult result = DescriptorDuplicationResult::BadSource;
1956 result = DescriptorDuplicationResult::TargetBusy;
1963 if ((!source->networkImpl || replacement->networkPublished()) &&
1964 (!source->getEventFdImpl() || replacement->eventFdPublished()) &&
1965 (!source->getSignalFdImpl() || replacement->signalFdPublished()) &&
1966 (!source->getTimerFdImpl() || replacement->timerFdPublished())) {
1967 replacement->fd = targetFd;
1968 replacement->fdflags = closeOnExec ? FD_CLOEXEC : 0;
1975 publishFdEntry(targetFd);
1976 result = DescriptorDuplicationResult::Success;
1984 currentTarget.
reset();
1986 retireDescriptor(retiring.
get());
1989 replacement.
reset();
2001 const bool advancesGlobalHint = minimum <=
m_LastFd;
2004 for (
size_t candidate = firstCandidate; candidate <
m_NextFd; ++candidate) {
2007 if (advancesGlobalHint) {
2017 descriptor->
fd = fd;
2021 lease.retain(published);
2033 if (m_pProcess->
acquireThread(source, i - 1) && source.get() != owner &&
2035 FATAL(
"Exec owner rejected a pending process signal.");
2038 m_PendingSignals->recordChange();
2048 m_PendingSignals->recordChange();
2054void PosixSubsystem::retireDescriptor(
FileDescriptor* descriptor) {
2055 if (descriptor->getFile()) {
2056 posix_advisory_descriptor_closed(m_AdvisoryOwner, descriptor->getFile()->
futexIdentity());
2060 if (!descriptor->getFile()) {
2062 if (queue && m_pProcess) {
2063 posix_mqueue_close(queue.
get(), m_pProcess->
getId());
2076 const size_t taskId = pThread->getTaskId();
2077 m_Namespaces->retireThread(*pThread);
2080 m_PendingSignals->retireThread(pThread);
2081 posix_timer_thread_exit(pThread);
2082 posix_sem_thread_exit(pThread);
2083 posix_robust_list_exit(pThread);
2085 clearChildTid(pThread);
2088void PosixSubsystem::clearChildTid(
Thread* pThread) {
2099 const bool cleared = posix_clear_child_tid(process, address);
2101 PS_NOTICE(
"clear-child-TID could not access target at " <<
Hex << address <<
" for tid " <<
Dec
2102 << pThread->
getId());
2110 if (!posix_futex_wake(process,
reinterpret_cast<int*
>(address), 1,
false))
2111 posix_futex_wake(process,
reinterpret_cast<int*
>(address), 1);
2117 if (thread->pThread != pThread)
2129bool PosixSubsystem::checkAccess(
const DescriptorLease& pFileDescriptor,
bool bRead,
bool bWrite,
2130 bool bExecute)
const {
2131 return VFS::checkAccess(pFileDescriptor->getFile(), bRead, bWrite, bExecute);
2139 image.fileSize = pFile->getSize();
2142 if (pFile->
read(0,
sizeof(header),
reinterpret_cast<uintptr_t
>(header)) !=
sizeof(header)) {
2143 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2147 Elf::ExecutableValidationResult result =
2149 if (result != Elf::ExecutableValidationResult::Valid) {
2150 setExecutableValidationError(result, isInterpreter);
2155 if (!image.programHeaders) {
2156 SYSCALL_ERROR(OutOfMemory);
2159 if (pFile->
read(image.metadata.programHeaderOffset, image.metadata.programHeaderSize,
2160 reinterpret_cast<uintptr_t
>(image.programHeaders.get())) !=
2161 image.metadata.programHeaderSize) {
2162 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2167 image.programHeaders.get(), image.metadata.programHeaderSize, image.fileSize, image.metadata);
2168 if (result != Elf::ExecutableValidationResult::Valid) {
2169 setExecutableValidationError(result, isInterpreter);
2174 if (image.metadata.type == ET_EXEC &&
2175 (image.metadata.loadStart < addressSpace.
getUserStart() ||
2177 setExecutableValidationError(Elf::ExecutableValidationResult::UnsupportedLayout, isInterpreter);
2181 bool foundProgramHeaders =
false;
2182 for (
size_t i = 0; i < image.metadata.programHeaderCount; ++i) {
2185 sizeof(programHeader));
2186 if (programHeader.type != PT_LOAD ||
2187 image.metadata.programHeaderOffset < programHeader.offset) {
2191 const size_t offsetInSegment = image.metadata.programHeaderOffset - programHeader.offset;
2192 if (offsetInSegment > programHeader.filesz ||
2193 image.metadata.programHeaderSize > programHeader.filesz - offsetInSegment ||
2194 programHeader.vaddr > ~uintptr_t{0} - offsetInSegment) {
2198 image.programHeaderAddress = programHeader.vaddr + offsetInSegment;
2199 foundProgramHeaders =
true;
2202 if (!foundProgramHeaders) {
2203 setExecutableValidationError(Elf::ExecutableValidationResult::UnsupportedLayout, isInterpreter);
2207 if (!image.metadata.hasInterpreter) {
2213 SYSCALL_ERROR(OutOfMemory);
2216 if (pFile->
read(image.metadata.interpreterOffset, image.metadata.interpreterSize,
2217 reinterpret_cast<uintptr_t
>(interpreter.get())) !=
2218 image.metadata.interpreterSize) {
2219 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2225 if (result != Elf::ExecutableValidationResult::Valid) {
2226 setExecutableValidationError(result, isInterpreter);
2229 for (
size_t i = 0; i + 1 < image.metadata.interpreterSize; ++i) {
2230 if (!interpreter.get()[i]) {
2231 setExecutableValidationError(Elf::ExecutableValidationResult::Malformed, isInterpreter);
2236 image.interpreter.assign(
reinterpret_cast<const char*
>(interpreter.get()),
2237 image.metadata.interpreterSize - 1,
true);
2242 PS_NOTICE(
"PosixSubsystem::loadElf(" << image.file->
getName() <<
")");
2246 image.metadata.programHeaderSize, image.fileSize,
2247 metadata) != Elf::ExecutableValidationResult::Valid) {
2252 const size_t allocationSize = metadata.loadEnd - metadata.loadStart;
2253 if (metadata.type == ET_DYN) {
2254 uintptr_t allocation = 0;
2255 if (!pProcess->allocateUserRange(Process::UserRegion::Dynamic, allocationSize, allocation) &&
2256 !pProcess->allocateUserRange(Process::UserRegion::Normal, allocationSize, allocation)) {
2259 loadBias = allocation - metadata.loadStart;
2261 if (!pProcess->allocateSpecificUserRange(Process::UserRegion::Normal, metadata.loadStart,
2269 const uintptr_t pageMask = pageSize - 1;
2270 for (
size_t i = 0; i < metadata.programHeaderCount; ++i) {
2273 sizeof(programHeader));
2274 if (programHeader.type != PT_LOAD || !programHeader.memsz) {
2278 if (programHeader.vaddr > ~uintptr_t{0} - loadBias) {
2281 const uintptr_t segmentAddress = loadBias + programHeader.vaddr;
2282 const uintptr_t pageOffset = segmentAddress & pageMask;
2283 if (programHeader.memsz > ~
size_t{0} - pageOffset) {
2286 size_t length = programHeader.memsz + pageOffset;
2287 if (length > ~
size_t{0} - pageMask) {
2290 length = (length + pageMask) & ~pageMask;
2292 uintptr_t base = segmentAddress & ~pageMask;
2293 const size_t fileOffset = programHeader.offset & ~pageMask;
2295 if (programHeader.flags & PF_X) {
2296 perms |= MemoryMappedObject::Exec;
2298 if (programHeader.flags & PF_W) {
2299 perms |= MemoryMappedObject::Write;
2302 const uintptr_t fileEnd = segmentAddress + programHeader.filesz;
2303 const bool hasPartialBssPage =
2304 programHeader.memsz > programHeader.filesz && (fileEnd & pageMask) != 0;
2306 if (hasPartialBssPage) {
2307 mappingPerms |= MemoryMappedObject::Write;
2310 PS_NOTICE(image.file->
getName()
2311 <<
" PHDR[" << i <<
"]: @" <<
Hex << base <<
" -> " << base + length);
2314 image.file, base, length, mappingPerms, fileOffset,
true,
2315 MemoryMapManager::Placement::FixedReplace,
nullptr,
2316 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec,
2318 ERROR(
"PosixSubsystem::loadElf: failed to map PT_LOAD section");
2322 if (programHeader.memsz > programHeader.filesz) {
2323 const uintptr_t end = segmentAddress + programHeader.memsz;
2324 uintptr_t zeroStart = segmentAddress + programHeader.filesz;
2325 if (hasPartialBssPage) {
2326 const size_t numBytes = pageSize - (zeroStart & pageMask);
2327 ByteSet(
reinterpret_cast<void*
>(zeroStart), 0, numBytes);
2328 zeroStart += numBytes;
2331 if (zeroStart < end) {
2332 uintptr_t anonymousAddress = zeroStart;
2336 "PosixSubsystem::loadElf: failed to map anonymous "
2337 "pages for filesz/memsz mismatch");
2344 ERROR(
"PosixSubsystem::loadElf: failed to restore PT_LOAD permissions");
2352ResolvedPath::~ResolvedPath() {
2356void ResolvedPath::reset() {
2358 const size_t error = thread ? thread->
getErrno() : 0;
2365 if (m_Path.
get() == path.
get())
2367 auto retired = pedigree_std::move(m_Path);
2370 const size_t error = thread ? thread->
getErrno() : 0;
2380 if (!context || !view) {
2381 SYSCALL_ERROR(DoesNotExist);
2386 options.followFinal = followFinal;
2387 if (!view->resolve(context, workingDir, path,
options, selected))
2389 result.retain(selected);
2391 return result.get();
2396 SYSCALL_ERROR(DoesNotExist);
2400 return selected.get();
2404 if (!context || !view || !view->follow(context, selected.path(), followed))
2406 selected.retain(followed);
2408 return selected.get();
2411#define STACK_PUSH(stack, value) *--stack = value
2412#define STACK_PUSH2(stack, value1, value2) \
2413 STACK_PUSH(stack, value1); \
2414 STACK_PUSH(stack, value2)
2415#define STACK_PUSH_COPY(stack, value, length) \
2416 stack = adjust_pointer(stack, -(length)); \
2417 MemoryCopy(stack, value, length)
2418#define STACK_PUSH_STRING(stack, str, length) \
2419 stack = adjust_pointer(stack, -(length)); \
2420 StringCopyN(reinterpret_cast<char*>(stack), str, length)
2421#define STACK_PUSH_ZEROES(stack, length) \
2422 stack = adjust_pointer(stack, -(length)); \
2423 ByteSet(stack, 0, length)
2424#define STACK_ALIGN(stack, to) \
2425 STACK_PUSH_ZEROES(stack, (to) - ((to) - (reinterpret_cast<uintptr_t>(stack) & ((to) - 1))))
2428 return invoke(name, argv, env, 0);
2432 SyscallState& state) {
2433 return invoke(name, argv, env, &state);
2437 bool& hasOptionalArgument) {
2438 PS_NOTICE(
"Attempting to parse shebang in " << pFile->
getFullPath());
2440 static constexpr size_t ShebangBufferSize = 256;
2441 char contents[ShebangBufferSize];
2442 const size_t bytesRead = pFile->
read(0,
sizeof(contents),
reinterpret_cast<uintptr_t
>(contents));
2444 interpreter.clear();
2445 optionalArgument.clear();
2446 hasOptionalArgument =
false;
2448 if (bytesRead < 2 || contents[0] !=
'#' || contents[1] !=
'!') {
2449 PS_NOTICE(
"no shebang found");
2453 size_t lineEnd = bytesRead;
2454 bool terminated = bytesRead <
sizeof(contents);
2455 for (
size_t i = 2; i < bytesRead; ++i) {
2456 if (contents[i] ==
'\n' || !contents[i]) {
2463 const size_t boundedLineEnd = lineEnd;
2464 while (lineEnd > 2 && (contents[lineEnd - 1] ==
' ' || contents[lineEnd - 1] ==
'\t')) {
2468 size_t interpreterBegin = 2;
2469 while (interpreterBegin < lineEnd &&
2470 (contents[interpreterBegin] ==
' ' || contents[interpreterBegin] ==
'\t')) {
2473 if (interpreterBegin == lineEnd) {
2474 PS_NOTICE(
"empty shebang interpreter");
2475 SYSCALL_ERROR(ExecFormatError);
2479 size_t interpreterEnd = interpreterBegin;
2480 while (interpreterEnd < lineEnd && contents[interpreterEnd] !=
' ' &&
2481 contents[interpreterEnd] !=
'\t') {
2484 if (interpreterEnd == lineEnd && lineEnd == boundedLineEnd && !terminated) {
2485 PS_NOTICE(
"truncated shebang interpreter");
2486 SYSCALL_ERROR(ExecFormatError);
2490 interpreter.assign(contents + interpreterBegin, interpreterEnd - interpreterBegin,
true);
2492 size_t argumentBegin = interpreterEnd;
2493 while (argumentBegin < lineEnd &&
2494 (contents[argumentBegin] ==
' ' || contents[argumentBegin] ==
'\t')) {
2497 if (argumentBegin < lineEnd) {
2498 optionalArgument.assign(contents + argumentBegin, lineEnd - argumentBegin,
true);
2499 hasOptionalArgument =
true;
2505static File* executableFile(
File* file) {
2507 SYSCALL_ERROR(DoesNotExist);
2511 SYSCALL_ERROR(IsADirectory);
2517 SYSCALL_ERROR(ExecFormatError);
2524 SyscallState* state) {
2526 String originalName(name);
2531 if (!originalFile) {
2532 PS_NOTICE(
"PosixSubsystem::invoke: could not find file '" << originalName <<
"'");
2533 SYSCALL_ERROR(DoesNotExist);
2537 return invoke(originalFile, originalName, argv, env, state,
false, originalLease.path());
2542 return invoke(originalFile, originalName, argv, env, 0);
2547 return invoke(originalFile, originalName, argv, env, &state,
false);
2552 bool descriptorPathInaccessible) {
2553 return invoke(originalFile, originalName, argv, env, &state, descriptorPathInaccessible);
2558 bool descriptorPathInaccessible) {
2559 return invoke(originalPath ? originalPath->node() : nullptr, originalName, argv, env, &state,
2560 descriptorPathInaccessible, originalPath);
2565 bool descriptorPathInaccessible,
2567 PS_NOTICE(
"PosixSubsystem::invoke(" << originalName <<
")");
2569 uint8_t execRandom[16];
2570 ByteSet(execRandom, 0,
sizeof(execRandom));
2572 const bool hasExecRandom =
2573 secure_random_bytes(execRandom,
sizeof(execRandom)) ==
sizeof(execRandom);
2574 if (!hasExecRandom) {
2575 PS_NOTICE(
"PosixSubsystem::invoke: AT_RANDOM unavailable until secure randomness is seeded");
2578 const bool hasExecRandom =
false;
2587 SYSCALL_ERROR(NoMoreProcesses);
2592 originalTargetLease.retain(originalPath);
2593 originalFile = executableFile(originalFile);
2594 if (!originalFile) {
2599 String candidateName(originalName);
2600 static constexpr size_t MaximumShebangRewrites = 4;
2601 size_t shebangRewrites = 0;
2602 bool allExecutableFilesReadable =
true;
2609 auto* executableView = VfsMountView::fromPath(originalTargetLease.path());
2610 if (executableView &&
2611 (executableView->mountFlags(originalTargetLease.path()) & VfsMountView::NoExec)) {
2612 SYSCALL_ERROR(PermissionDenied);
2615 if (!posix_landlock_check(originalTargetLease.path(),
2616 LandlockAccess::Execute | LandlockAccess::ReadFile)) {
2619 allExecutableFilesReadable &= posix_exec_file_readable(originalFile);
2621 const size_t bytesRead =
2622 originalFile->
read(0,
sizeof(magic),
reinterpret_cast<uintptr_t
>(magic));
2623 if (bytesRead ==
sizeof(magic) && magic[0] == 0x7f && magic[1] ==
'E' && magic[2] ==
'L' &&
2628 PS_NOTICE(
"PosixSubsystem::invoke: '" << originalFile->
getName()
2629 <<
"' is not an ELF binary, looking for shebang...");
2631 String shebangInterpreter;
2633 bool hasShebangArgument =
false;
2634 if (!
parseShebang(originalFile, shebangInterpreter, shebangArgument, hasShebangArgument)) {
2635 PS_NOTICE(
"PosixSubsystem::invoke: failed to parse shebang line in '"
2636 << originalFile->
getName() <<
"'");
2640 if (!shebangInterpreter.length()) {
2641 SYSCALL_ERROR(ExecFormatError);
2645 if (!shebangRewrites && descriptorPathInaccessible) {
2647 SYSCALL_ERROR(DoesNotExist);
2651 if (shebangRewrites == MaximumShebangRewrites) {
2652 SYSCALL_ERROR(LoopExists);
2657 String resolvedInterpreter(shebangInterpreter);
2658 String normalisedInterpreter;
2659 if (normalisePath(normalisedInterpreter, resolvedInterpreter.cstr())) {
2660 resolvedInterpreter = normalisedInterpreter;
2666 PS_NOTICE(
"PosixSubsystem::invoke: could not find shebang interpreter '"
2667 << resolvedInterpreter <<
"'");
2668 SYSCALL_ERROR(DoesNotExist);
2672 shebangFile = executableFile(shebangFile);
2681 if (hasShebangArgument) {
2686 originalFile = shebangFile;
2687 candidateName = shebangInterpreter;
2688 originalTargetLease.swap(nextLease);
2693 size_t argumentBytes = 2 *
sizeof(uintptr_t);
2694 if (originalName.length() >= MaximumExecArgumentBytes - argumentBytes) {
2695 SYSCALL_ERROR(TooBig);
2698 argumentBytes += originalName.length() + 1;
2701 for (
size_t i = 0; i < list->count(); ++i) {
2702 const size_t remaining = MaximumExecArgumentBytes - argumentBytes;
2703 if (remaining <=
sizeof(uintptr_t) || (*list)[i].length() >= remaining -
sizeof(uintptr_t)) {
2704 SYSCALL_ERROR(TooBig);
2707 argumentBytes +=
sizeof(uintptr_t) + (*list)[i].length() + 1;
2712 File* interpreterFile = 0;
2720 originalImage.openingPath = originalTargetLease.path();
2726 if (originalImage.metadata.hasInterpreter) {
2727 String interpreter(originalImage.interpreter);
2731 String normalisedInterpreter;
2732 if (normalisePath(normalisedInterpreter, interpreter.cstr())) {
2733 interpreter = normalisedInterpreter;
2737 interpreterFile = findFileRetained(interpreter, interpreterLease,
FilesystemPathRef(),
true);
2738 interpreterFile = executableFile(interpreterFile);
2739 if (!interpreterFile) {
2740 PS_NOTICE(
"PosixSubsystem::invoke: could not find interpreter '" << interpreter <<
"'");
2747 auto* executableView = VfsMountView::fromPath(interpreterLease.path());
2748 if (executableView &&
2749 (executableView->mountFlags(interpreterLease.path()) & VfsMountView::NoExec)) {
2750 SYSCALL_ERROR(PermissionDenied);
2753 if (!posix_landlock_check(interpreterLease.path(),
2754 LandlockAccess::Execute | LandlockAccess::ReadFile)) {
2757 allExecutableFilesReadable &= posix_exec_file_readable(interpreterFile);
2759 interpreterImage.openingPath = interpreterLease.path();
2763 if (interpreterImage.metadata.hasInterpreter) {
2764 SYSCALL_ERROR(BadSharedLibrary);
2770 interpreterFile = 0;
2773 if (interpreterFile && originalImage.metadata.type == ET_EXEC &&
2774 interpreterImage.metadata.type == ET_EXEC &&
2775 originalImage.metadata.loadStart < interpreterImage.metadata.loadEnd &&
2776 interpreterImage.metadata.loadStart < originalImage.metadata.loadEnd) {
2777 SYSCALL_ERROR(BadSharedLibrary);
2783 if (!m_Namespaces || !m_Namespaces->valid()) {
2784 SYSCALL_ERROR(OutOfMemory);
2788 if (
m_TraceContext.prepareTask(initialTrace) != TraceStatus::Success) {
2789 SYSCALL_ERROR(OutOfMemory);
2793 if (!m_Namespaces->acquireThread(*pThread, currentUts)) {
2794 posix_uts_error(UtsStatus::Missing);
2797 const UtsStatus prepared = posix_uts_prepare_thread(currentUts,
false, initialUts);
2798 if (prepared != UtsStatus::Success) {
2799 posix_uts_error(prepared);
2808 if (!execScope.commit()) {
2809 SYSCALL_ERROR(Interrupted);
2813 if (pProcess->getType() == Process::Posix)
2814 static_cast<PosixProcess*
>(pProcess)->markExecCommitted();
2818 m_ExecutablePath = originalTargetLease.path();
2819 m_CommandLine = pedigree_std::move(committedCommandLine);
2822 invalidateUserImage();
2824 posix_timer_process_exit(pProcess);
2828 posix_mqueue_process_exit(pProcess->
getId());
2833 if (pProcess->isVforkChild())
2834 clearChildTid(pThread);
2837 posix_robust_list_exit(pThread);
2838 const size_t previousTaskId = pThread->getTaskId();
2839 execScope.adoptLeaderIdentity();
2840 m_Namespaces->promoteExec(*pThread);
2845 trace->imageCommitted();
2847 procfsInvalidateNamespaceTask(m_Namespaces, pProcess->
getUserspaceId(), previousTaskId);
2848 procfsInvalidateNamespaceTask(m_Namespaces, pProcess->
getUserspaceId(), pProcess->
getId());
2850 pProcess->setLinker(
nullptr);
2855 if (m_CallbackSchedulingDomain == CallbackSchedulingDomain::LegacySignals)
2856 m_CallbackSchedulingDomain = CallbackSchedulingDomain::Unrestricted;
2862 pProcess->resetUserReservations();
2864 m_MemoryLockAccount.publish({}, MemoryLockMode::None);
2866 pProcess->
getAddressSpace()->rawUserMemory().setCompleteInventory(X64 && !HOSTED);
2876 pedigree_init_sigret();
2878 auto failAfterCommit = [pThread](Error::PosixError error) {
2879 syscallError(error);
2885 uintptr_t originalLoadBias = 0;
2886 if (!
loadElf(originalImage, originalLoadBias)) {
2887 PS_NOTICE(
"PosixSubsystem::invoke: failed to load target");
2888 return failAfterCommit(Error::OutOfMemory);
2892 uintptr_t interpreterLoadBias = 0;
2893 if (interpreterFile && !
loadElf(interpreterImage, interpreterLoadBias)) {
2894 PS_NOTICE(
"PosixSubsystem::invoke: failed to load interpreter");
2895 return failAfterCommit(Error::OutOfMemory);
2898 const uintptr_t originalEntryPoint = originalLoadBias + originalImage.metadata.entryPoint;
2899 uintptr_t interpreterEntryPoint = 0;
2900 if (interpreterFile) {
2901 interpreterEntryPoint = interpreterLoadBias + interpreterImage.metadata.entryPoint;
2903 if (!interpreterFile) {
2904 interpreterEntryPoint = originalEntryPoint;
2909 pProcess->resetCounts();
2914 if (pProcess->getType() == Process::Posix) {
2917 p->commitExecCredentials(*pThread, allExecutableFilesReadable);
2918 execCredentials = p->snapshotCredentials();
2919 if (!posix_capabilities_exec(*pThread, execCredentials.euid)) {
2920 return failAfterCommit(Error::OutOfMemory);
2923 execCredentials.ruid = pProcess->
getUserId();
2924 execCredentials.euid = pProcess->getEffectiveUserId();
2925 execCredentials.rgid = pProcess->getGroupId();
2926 execCredentials.egid = pProcess->getEffectiveGroupId();
2932 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec;
2933 uintptr_t vdsoAddress = 0;
2937 PS_NOTICE(
"PosixSubsystem::invoke: failed to map VDSO");
2940 MemoryCopy(
reinterpret_cast<void*
>(vdsoAddress), __vdso_so, __vdso_so_len);
2946 vdsoPerms & ~MemoryMappedObject::Write);
2955 reinterpret_cast<void*
>(POSIX_VSYSCALL_ADDRESS))) {
2956 physical_uintptr_t vsyscallBase = 0;
2957 size_t vsyscallFlags = 0;
2959 vsyscallBase, vsyscallFlags);
2961 vsyscallBase,
reinterpret_cast<void*
>(POSIX_VSYSCALL_ADDRESS),
2969 if (!stack || !stack->getTop()) {
2971 ERROR(
"PosixSubsystem::invoke: failed to allocate initial user stack");
2972 return failAfterCommit(Error::OutOfMemory);
2976 if (stack->getSize() < argumentBytes + 512) {
2978 return failAfterCommit(Error::TooBig);
2983 uintptr_t* loaderStack =
reinterpret_cast<uintptr_t*
>(stack->getTop());
2986 STACK_PUSH(loaderStack, 0);
2989 STACK_ALIGN(loaderStack, 16);
2992 char** envs =
new char*[env.
count()];
2994 for (
size_t i = 0; i < env.
count(); ++i) {
2996 STACK_PUSH_STRING(loaderStack, str.length() ? str.cstr() :
"", str.length() + 1);
2997 PS_NOTICE(
"env[" << envc <<
"]: " << str);
2998 envs[envc++] =
reinterpret_cast<char*
>(loaderStack);
3002 STACK_ALIGN(loaderStack, 16);
3004 char** argvs =
new char*[argv.
count()];
3006 for (
size_t i = 0; i < argv.
count(); ++i) {
3008 STACK_PUSH_STRING(loaderStack, str.length() ? str.cstr() :
"", str.length() + 1);
3009 PS_NOTICE(
"argv[" << argc <<
"]: " << str);
3010 argvs[argc++] =
reinterpret_cast<char*
>(loaderStack);
3014 STACK_ALIGN(loaderStack, 16);
3017 STACK_PUSH_STRING(loaderStack,
"aarch64", 8);
3019 STACK_PUSH_STRING(loaderStack,
"v7l", 4);
3021 STACK_PUSH_STRING(loaderStack,
"x86_64", 7);
3023 void* platform = loaderStack;
3025 STACK_PUSH_STRING(loaderStack, originalName.cstr(), originalName.length() + 1);
3026 void* execfn = loaderStack;
3029 STACK_ALIGN(loaderStack, 16);
3031 STACK_PUSH_COPY(loaderStack, execRandom,
sizeof(execRandom));
3032 void* random = loaderStack;
3035 if (((argc + envc) % 2) == 0) {
3036 STACK_PUSH_ZEROES(loaderStack, 8);
3040 STACK_PUSH2(loaderStack, 0, 0);
3041 STACK_PUSH2(loaderStack,
reinterpret_cast<uintptr_t
>(platform), 15);
3042 if (hasExecRandom) {
3043 STACK_PUSH2(loaderStack,
reinterpret_cast<uintptr_t
>(random), 25);
3045 STACK_PUSH2(loaderStack, 0, 1);
3047 STACK_PUSH2(loaderStack, 0, 23);
3048 STACK_PUSH2(loaderStack, execCredentials.egid, 14);
3049 STACK_PUSH2(loaderStack, execCredentials.rgid, 13);
3050 STACK_PUSH2(loaderStack, execCredentials.euid, 12);
3051 STACK_PUSH2(loaderStack, execCredentials.ruid, 11);
3052 STACK_PUSH2(loaderStack,
reinterpret_cast<uintptr_t
>(execfn), 31);
3056#if !HOSTED && !ARM64 && !ARMV7
3059 STACK_PUSH2(loaderStack, 0, 32);
3060 STACK_PUSH2(loaderStack, vdsoAddress, 33);
3065 STACK_PUSH2(loaderStack, originalEntryPoint, 9);
3066 STACK_PUSH2(loaderStack, interpreterLoadBias, 7);
3068 STACK_PUSH2(loaderStack, originalImage.metadata.programHeaderCount, 5);
3070 STACK_PUSH2(loaderStack, originalLoadBias + originalImage.programHeaderAddress,
3074 STACK_PUSH(loaderStack, 0);
3075 for (
size_t i = envc; i > 0; --i) {
3076 STACK_PUSH(loaderStack,
reinterpret_cast<uintptr_t
>(envs[i - 1]));
3081 STACK_PUSH(loaderStack, 0);
3082 for (ssize_t i = argc - 1; i >= 0; --i) {
3083 STACK_PUSH(loaderStack,
reinterpret_cast<uintptr_t
>(argvs[i]));
3088 STACK_PUSH(loaderStack, argc);
3097 return failAfterCommit(Error::ValueTooLarge);
3103 loaderStack,
false,
false,
true, &placement);
3105 invalidateUserImage();
3107 return failAfterCommit(Error::OutOfMemory);
3109 posix_sandbox_inherit(*pNewThread, *pThread);
3110 m_Namespaces->publishThread(initialUts, *pNewThread,
true);
3111 if (
m_TraceContext.publishTask(initialTrace, *pNewThread) != TraceStatus::Success &&
3113 FATAL(
"Initial trace task publication failed");
3115 pNewThread->setName(
"ld.so thread");
3117 FATAL(
"PosixSubsystem::invoke: initial user Thread could not be started.");
3124 ByteSet(&s, 0,
sizeof(s));
3125 pThread->
state() = s;
3128 reinterpret_cast<uintptr_t
>(loaderStack))) {
3129 ERROR(
"PosixSubsystem::invoke: exec userspace jump was not dispatched");
3130 return failAfterCommit(Error::IoError);
3133 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.