The Pedigree Project 0.1
linux-amd64-signal.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "linux-amd64-signal.h"
21
22#if X64
23
24#include "pedigree/kernel/process/Thread.h"
25#include "pedigree/kernel/processor/NMFaultHandler.h"
26#include "pedigree/kernel/processor/Processor.h"
27#include "pedigree/kernel/processor/SyscallManager.h"
28#include "pedigree/kernel/processor/VirtualAddressSpace.h"
29#include "pedigree/kernel/processor/state.h"
30#include "pedigree/kernel/utilities/lib.h"
31
32#include <errno.h>
33#include <signal.h>
34
35#include "linux-amd64-signal-abi.h"
36#include "signal-syscalls.h"
37#include "syscalls/translate.h"
38#include "system-syscalls.h"
39
40namespace {
41using namespace LinuxAmd64SignalAbi;
42
43constexpr uint64_t UnblockableSignals =
44 (static_cast<uint64_t>(1) << (SIGKILL - 1)) | (static_cast<uint64_t>(1) << (SIGSTOP - 1));
45constexpr uint64_t HandlerFlagsToClear = 0x100 | 0x400 | 0x10000;
46constexpr uint64_t RestorableRflags = 0x50DD5;
47constexpr uint64_t SafeUserRflags = 0x202;
48constexpr uint64_t SupportedUcontextFlags = 0x6;
49constexpr uintptr_t MaximumCanonicalUserAddress = 0x00007FFFFFFFFFFF;
50constexpr uint16_t IretUserCodeSegment = 0x1B;
51constexpr uint16_t SysretUserCodeSegment = 0x2B;
52constexpr uint16_t UserStackSegment = 0x23;
53
54bool userCodeSegment(uint16_t selector) {
55 // Initial userspace entry uses IRET, while every subsequent syscall return
56 // derives the second valid code selector from IA32_STAR.
57 return selector == IretUserCodeSegment || selector == SysretUserCodeSegment;
58}
59
60uintptr_t alignDown(uintptr_t value, uintptr_t alignment) {
61 return value & ~(alignment - 1);
62}
63
64bool userBounds(uintptr_t address, size_t extent) {
65 if (!extent || !address || extent - 1 > (~static_cast<uintptr_t>(0) - address)) {
66 return false;
67 }
68
69 uintptr_t end = address + extent - 1;
70 VirtualAddressSpace& va = Processor::information().getVirtualAddressSpace();
71 return address >= va.getUserStart() && end <= MaximumCanonicalUserAddress &&
72 end < va.getKernelStart() && va.isAddressValid(reinterpret_cast<void*>(address)) &&
73 va.isAddressValid(reinterpret_cast<void*>(end));
74}
75
76bool userRegion(uintptr_t address, size_t extent, size_t access) {
77 if (!userBounds(address, extent)) {
78 return false;
79 }
80
81 // Keep the inclusive-end check local to the signal copy boundary even if
82 // the shared range validator changes.
83 return PosixSubsystem::checkAddress(address, extent, access) &&
84 PosixSubsystem::checkAddress(address + extent - 1, 1, access);
85}
86
87bool userExecutable(uintptr_t address) {
88 return userRegion(address, 1, PosixSubsystem::SafeExecute);
89}
90
91bool onAlternateStack(uintptr_t stackPointer, const Thread::AlternateSignalStack& stack) {
92 if (!stack.enabled || !stack.base || stack.size > (~static_cast<uintptr_t>(0) - stack.base)) {
93 return false;
94 }
95
96 return stackPointer >= stack.base && stackPointer < stack.base + stack.size;
97}
98
99void setSiginfo32(Siginfo& info, size_t offset, int32_t value) {
100 MemoryCopy(info.bytes + offset, &value, sizeof(value));
101}
102
103void setSiginfo64(Siginfo& info, size_t offset, uint64_t value) {
104 MemoryCopy(info.bytes + offset, &value, sizeof(value));
105}
106
107void populateSigcontext(Sigcontext& context, const InterruptState& state, uint64_t oldMask,
108 uintptr_t faultAddress, uintptr_t errorCode, uintptr_t fpstate) {
109 context.rax = state.getRegister(0);
110 context.rbx = state.getRegister(1);
111 context.rcx = state.getRegister(2);
112 context.rdx = state.getRegister(3);
113 context.rdi = state.getRegister(4);
114 context.rsi = state.getRegister(5);
115 context.rbp = state.getRegister(6);
116 context.r8 = state.getRegister(7);
117 context.r9 = state.getRegister(8);
118 context.r10 = state.getRegister(9);
119 context.r11 = state.getRegister(10);
120 context.r12 = state.getRegister(11);
121 context.r13 = state.getRegister(12);
122 context.r14 = state.getRegister(13);
123 context.r15 = state.getRegister(14);
124 context.rsp = state.getStackPointer();
125 context.rip = state.getInstructionPointer();
126 context.rflags = state.getFlags();
127 context.cs = state.getCodeSegment();
128 context.ss = state.getStackSegment();
129 context.errorCode = errorCode;
130 context.trapNumber = state.getInterruptNumber();
131 context.oldMask = oldMask;
132 context.cr2 = faultAddress;
133 context.fpstate = fpstate;
134}
135
136void populateSigcontext(Sigcontext& context, const SyscallState& state, uint64_t oldMask,
137 uintptr_t fpstate) {
138 context.rax = state.getRegister(0);
139 context.rbx = state.getRegister(1);
140 context.rcx = state.getInstructionPointer();
141 context.rdx = state.getRegister(2);
142 context.rdi = state.getRegister(3);
143 context.rsi = state.getRegister(4);
144 context.rbp = state.getRegister(5);
145 context.r8 = state.getRegister(6);
146 context.r9 = state.getRegister(7);
147 context.r10 = state.getRegister(8);
148 context.r11 = state.getFlags();
149 context.r12 = state.getRegister(9);
150 context.r13 = state.getRegister(10);
151 context.r14 = state.getRegister(11);
152 context.r15 = state.getRegister(12);
153 context.rsp = state.getStackPointer();
154 context.rip = state.getInstructionPointer();
155 context.rflags = state.getFlags();
156 context.cs = SysretUserCodeSegment;
157 context.ss = UserStackSegment;
158 context.oldMask = oldMask;
159 context.fpstate = fpstate;
160}
161
162int signalCode(Subsystem::ExceptionType exception, uintptr_t errorCode) {
163 switch (exception) {
164 case Subsystem::PageFault:
165 return (errorCode & 1) ? SEGV_ACCERR : SEGV_MAPERR;
166 case Subsystem::InvalidOpcode:
167 return ILL_ILLOPC;
168 case Subsystem::GeneralProtectionFault:
169 case Subsystem::FileMappingFault:
170 return BUS_ADRERR;
171 case Subsystem::DivideByZero:
172 return FPE_INTDIV;
173 case Subsystem::FpuError:
174 case Subsystem::SpecialFpuError:
175 return FPE_FLTINV;
176 default:
177 return SI_KERNEL;
178 }
179}
180
181uintptr_t signalAddress(Subsystem::ExceptionType exception, const InterruptState& state,
182 uintptr_t faultAddress) {
183 return exception == Subsystem::PageFault || exception == Subsystem::FileMappingFault
184 ? faultAddress
185 : state.getInstructionPointer();
186}
187
188void badFrame() {
189 Processor::information().getCurrentThread()->deferSignalExit(SIGSEGV);
190}
191
192struct AsyncHandlerState {
193 uintptr_t frameAddress;
194 uintptr_t infoAddress;
195 uintptr_t ucontextAddress;
196 uintptr_t handlerAddress;
197 uint64_t flags;
198};
199
200bool restartableSyscall(const SyscallState& state) {
201 switch (state.getSyscallNumber()) {
202 case PedigreeLinuxAmd64Syscall_read:
203 case PedigreeLinuxAmd64Syscall_write:
204 case PedigreeLinuxAmd64Syscall_open:
205 case PedigreeLinuxAmd64Syscall_openat:
206 case PedigreeLinuxAmd64Syscall_readv:
207 case PedigreeLinuxAmd64Syscall_writev:
208 case PedigreeLinuxAmd64Syscall_pread64:
209 case PedigreeLinuxAmd64Syscall_pwrite64:
210 case PedigreeLinuxAmd64Syscall_preadv:
211 case PedigreeLinuxAmd64Syscall_pwritev:
212 case PedigreeLinuxAmd64Syscall_preadv2:
213 case PedigreeLinuxAmd64Syscall_pwritev2:
214 case PedigreeLinuxAmd64Syscall_wait4:
215 case PedigreeLinuxAmd64Syscall_waitid:
216 case PedigreeLinuxAmd64Syscall_accept:
217 case PedigreeLinuxAmd64Syscall_accept4:
218 case PedigreeLinuxAmd64Syscall_sendto:
219 case PedigreeLinuxAmd64Syscall_recvfrom:
220 case PedigreeLinuxAmd64Syscall_sendmsg:
221 case PedigreeLinuxAmd64Syscall_recvmsg:
222 case PedigreeLinuxAmd64Syscall_mq_timedsend:
223 case PedigreeLinuxAmd64Syscall_mq_timedreceive:
224 return true;
225 case PedigreeLinuxAmd64Syscall_recvmmsg:
226 // Replaying a supplied relative timeout would extend its deadline.
227 return state.getSyscallParameter(10) == 0;
228 case PedigreeLinuxAmd64Syscall_futex:
229 // Replaying a relative timeout would extend the caller's deadline.
230 // Only the implemented, untimed FUTEX_WAIT operation is eligible.
231 return (state.getSyscallParameter(7) & ~static_cast<uintptr_t>(128)) == 0 &&
232 state.getSyscallParameter(9) == 0;
233 default:
234 // Sleeps and poll/select/epoll waits always report interruption.
235 // connect may already own an in-flight attempt when interrupted.
236 return false;
237 }
238}
239
240void restartInterruptedSyscall(Thread* thread, uint32_t flags, Sigcontext& context) {
241 const SyscallState* original = thread->getOriginalSyscallState();
242 if (!(flags & SA_RESTART) || context.rax != static_cast<uint64_t>(-EINTR) || !original ||
243 original->getSyscallService() != linuxCompat ||
244 context.rip != original->getInstructionPointer() ||
245 context.rsp != original->getStackPointer() || context.rip < 2 ||
246 !restartableSyscall(*original)) {
247 return;
248 }
249
250 // The entry image predates result publication and ABI argument translation.
251 // Replaying only -EINTR leaves all successful partial transfers untouched.
252 context.rax = original->getRegister(0);
253 context.rdi = original->getSyscallParameter(6);
254 context.rsi = original->getSyscallParameter(7);
255 context.rdx = original->getSyscallParameter(8);
256 context.r10 = original->getSyscallParameter(9);
257 context.r8 = original->getSyscallParameter(10);
258 context.r9 = original->getSyscallParameter(11);
259 context.rip -= 2;
260}
261
262Event::UserReturnDelivery resolveAsyncDisposition(Thread* thread, SignalEvent& event,
264 if (!event.deliveryActive())
265 return Event::UserReturnDelivery::Delivered;
266 const size_t signal = event.getNumber();
267 Process* process = thread ? thread->getParent() : nullptr;
268 PosixSubsystem* subsystem =
269 process ? static_cast<PosixSubsystem*>(process->getSubsystem()) : nullptr;
270 if (!subsystem || !subsystem->getSignalDisposition(signal, disposition, true)) {
271 badFrame();
272 return Event::UserReturnDelivery::Failed;
273 }
274 if (disposition.type == 0) {
275 return Event::UserReturnDelivery::NotApplicable;
276 }
277
278 if (disposition.type == 1 && signal != SIGCHLD && signal != SIGURG && signal != SIGWINCH) {
279 thread->setCurrentSignalDelivery(signal, event.getContinuationEpoch());
280 reinterpret_cast<_sig_func_ptr>(disposition.handler)(static_cast<int>(signal));
281 }
282 return Event::UserReturnDelivery::Delivered;
283}
284
285bool buildAsyncFrame(Thread* thread, LinuxAmd64Signal::AsyncEvent& event, Sigcontext& context,
286 const PosixSubsystem::SignalDisposition& disposition,
287 AsyncHandlerState& handlerState) {
288 const int signal = static_cast<int>(event.getNumber());
289 if (!thread || thread != Processor::information().getCurrentThread() || signal <= 0 ||
290 signal > 64 || !userCodeSegment(context.cs) || context.ss != UserStackSegment ||
291 !(disposition.flags & SA_RESTORER) || !userExecutable(disposition.handler) ||
292 !userExecutable(disposition.restorer)) {
293 return false;
294 }
295
296 const uintptr_t originalStack = context.rsp;
297 if (!userBounds(originalStack, 1)) {
298 return false;
299 }
300
301 Thread::AlternateSignalStack& alternate = thread->getAlternateSignalStack();
302 const bool wasOnAlternate = onAlternateStack(originalStack, alternate);
303 const bool enterAlternate =
304 (disposition.flags & SA_ONSTACK) && alternate.enabled && !wasOnAlternate;
305
306 uintptr_t stackTop = 0;
307 if (enterAlternate) {
308 if (!alternate.base || alternate.size > (~static_cast<uintptr_t>(0) - alternate.base)) {
309 return false;
310 }
311 stackTop = alternate.base + alternate.size;
312 } else {
313 if (originalStack < 128) {
314 return false;
315 }
316 stackTop = originalStack - 128;
317 }
318
319 if (stackTop < sizeof(Fpstate)) {
320 return false;
321 }
322 const uintptr_t fpstateAddress = alignDown(stackTop - sizeof(Fpstate), 64);
323 if (fpstateAddress < sizeof(RtSigframe) + 8) {
324 return false;
325 }
326 const uintptr_t frameAddress = alignDown(fpstateAddress - sizeof(RtSigframe), 16) - 8;
327
328 if (!userRegion(frameAddress, sizeof(RtSigframe), PosixSubsystem::SafeWrite) ||
329 !userRegion(fpstateAddress, sizeof(Fpstate), PosixSubsystem::SafeWrite)) {
330 return false;
331 }
332 if (enterAlternate || wasOnAlternate) {
333 const uintptr_t alternateEnd = alternate.base + alternate.size;
334 if (frameAddress < alternate.base || fpstateAddress + sizeof(Fpstate) > alternateEnd) {
335 return false;
336 }
337 }
338
339 RtSigframe frame = {};
340 Fpstate savedFpstate = {};
341 if (!NMFaultHandler::saveCurrentThreadFpuState(&savedFpstate, true)) {
342 return false;
343 }
344 Fpstate fpstate = savedFpstate;
345 ByteSet(fpstate.reserved3, 0, sizeof(fpstate.reserved3));
346
347 const uint64_t currentMask = thread->getSignalMask();
348 const uint64_t oldMask = thread->getSignalMaskForReturnFrame();
349 frame.restorer = disposition.restorer;
350 frame.ucontext.flags = SupportedUcontextFlags;
351 if (alternate.enabled) {
352 frame.ucontext.stack.stackPointer = alternate.base;
353 frame.ucontext.stack.size = alternate.size;
354 frame.ucontext.stack.flags = wasOnAlternate ? SS_ONSTACK : 0;
355 } else {
356 frame.ucontext.stack.flags = SS_DISABLE;
357 }
358 context.oldMask = oldMask;
359 context.fpstate = fpstateAddress;
360 frame.ucontext.mcontext = context;
361 frame.ucontext.signalMask = oldMask;
362
363 setSiginfo32(frame.info, 0, signal);
364 setSiginfo32(frame.info, 4, 0);
365 setSiginfo32(frame.info, 8, event.getSignalCode());
366 setSiginfo32(frame.info, 16, event.getSenderProcess());
367 setSiginfo32(frame.info, 20, static_cast<int32_t>(event.getSenderUser()));
368 setSiginfo64(frame.info, 24, event.getSignalValue());
369 int32_t timerId = 0, overrun = 0;
370 event.timerInfo(timerId, overrun);
371 if (event.getSignalCode() == -2) {
372 setSiginfo32(frame.info, 16, timerId);
373 setSiginfo32(frame.info, 20, overrun);
374 } else if (signal == SIGCHLD && event.getSignalCode() > 0 && event.getSignalCode() <= 6) {
375 setSiginfo32(frame.info, 24, event.childStatus());
376 setSiginfo64(frame.info, 32, event.childUserTime());
377 setSiginfo64(frame.info, 40, event.childSystemTime());
378 }
379
380 if (!PosixSubsystem::copyToUser(reinterpret_cast<void*>(fpstateAddress), &fpstate,
381 sizeof(fpstate)) ||
382 !PosixSubsystem::copyToUser(reinterpret_cast<void*>(frameAddress), &frame, sizeof(frame))) {
384 FATAL("Could not restore FPU state after a failed signal-frame copy.");
385 }
386 return false;
387 }
388
389 event.completeSignalDelivery(overrun);
390 uint64_t handlerMask = currentMask | disposition.signalMask;
391 if (!(disposition.flags & SA_NODEFER)) {
392 handlerMask |= static_cast<uint64_t>(1) << (signal - 1);
393 }
394 thread->commitSignalHandlerMask(handlerMask & ~UnblockableSignals);
395 alternate.inUse = wasOnAlternate || enterAlternate;
396
397 handlerState.frameAddress = frameAddress;
398 handlerState.infoAddress = frameAddress + __builtin_offsetof(RtSigframe, info);
399 handlerState.ucontextAddress = frameAddress + __builtin_offsetof(RtSigframe, ucontext);
400 handlerState.handlerAddress = disposition.handler;
401 handlerState.flags = (context.rflags & ~HandlerFlagsToClear) | SafeUserRflags;
402 return true;
403}
404} // namespace
405
406LinuxAmd64Signal::AsyncEvent::AsyncEvent(uintptr_t handler, size_t signal, uint64_t signalMask,
407 bool deferSignal, uint32_t flags, uintptr_t restorer,
408 bool useAlternateStack, bool isDeletable)
409 : SignalEvent(handler, signal, ~0UL, signalMask, deferSignal, isDeletable,
410 Event::HandlerPrivilege::User, DeliveryDisposition::CaughtHandler,
411 useAlternateStack),
412 m_Flags(flags),
413 m_Restorer(restorer) {}
414
415LinuxAmd64Signal::AsyncEvent::AsyncEvent(const AsyncEvent& other, bool isDeletable)
416 : SignalEvent(other, isDeletable), m_Flags(other.m_Flags), m_Restorer(other.m_Restorer) {}
417
419 if (isDeletable()) {
420 return this;
421 }
422 return new AsyncEvent(*this, true);
423}
424
428
430 Sigcontext context = {};
431 populateSigcontext(context, state, 0, 0, state.getErrorCode(), 0);
432 AsyncHandlerState handlerState = {};
433 Thread* thread = Processor::information().getCurrentThread();
435 const Event::UserReturnDelivery resolved = resolveAsyncDisposition(thread, *this, disposition);
436 if (resolved != Event::UserReturnDelivery::NotApplicable) {
437 return resolved;
438 }
439 if (!buildAsyncFrame(thread, *this, context, disposition, handlerState)) {
440 badFrame();
441 return Event::UserReturnDelivery::Failed;
442 }
443
444 state.setRegister(0, 0);
445 state.setRegister(4, getNumber());
446 state.setRegister(5, handlerState.infoAddress);
447 state.setRegister(3, handlerState.ucontextAddress);
448 state.setInstructionPointer(handlerState.handlerAddress);
449 state.setStackPointer(handlerState.frameAddress);
450 state.setFlags(handlerState.flags);
451 return Event::UserReturnDelivery::Delivered;
452}
453
455 Sigcontext context = {};
456 populateSigcontext(context, state, 0, 0);
457 AsyncHandlerState handlerState = {};
458 Thread* thread = Processor::information().getCurrentThread();
460 const Event::UserReturnDelivery resolved = resolveAsyncDisposition(thread, *this, disposition);
461 if (resolved != Event::UserReturnDelivery::NotApplicable) {
462 return resolved;
463 }
464 restartInterruptedSyscall(thread, disposition.flags, context);
465 if (!buildAsyncFrame(thread, *this, context, disposition, handlerState)) {
466 badFrame();
467 return Event::UserReturnDelivery::Failed;
468 }
469
470 state.setRegister(0, 0);
471 state.setRegister(3, getNumber());
472 state.setRegister(4, handlerState.infoAddress);
473 state.setRegister(2, handlerState.ucontextAddress);
474 state.setInstructionPointer(handlerState.handlerAddress);
475 state.setStackPointer(handlerState.frameAddress);
476 state.setFlags(handlerState.flags);
477 return Event::UserReturnDelivery::Delivered;
478}
479
480LinuxAmd64Signal::DeliveryResult LinuxAmd64Signal::deliverSynchronous(
481 Thread* thread, int signal, const PosixSubsystem::SignalDisposition& disposition,
482 Subsystem::ExceptionType exception, InterruptState& state, uintptr_t faultAddress,
483 uintptr_t errorCode) {
484 if (!thread || thread != Processor::information().getCurrentThread() || disposition.type != 0) {
485 return NotApplicable;
486 }
487
488 if (signal <= 0 || signal > 64 || state.kernelMode() ||
489 !userCodeSegment(state.getCodeSegment()) || state.getStackSegment() != UserStackSegment ||
490 !(disposition.flags & SA_RESTORER) || !userExecutable(disposition.handler) ||
491 !userExecutable(disposition.restorer)) {
492 return Failed;
493 }
494
495 uintptr_t originalStack = state.getStackPointer();
496 if (!userBounds(originalStack, 1)) {
497 return Failed;
498 }
499
500 Thread::AlternateSignalStack& alternate = thread->getAlternateSignalStack();
501 bool wasOnAlternate = onAlternateStack(originalStack, alternate);
502 bool enterAlternate = (disposition.flags & SA_ONSTACK) && alternate.enabled && !wasOnAlternate;
503
504 uintptr_t stackTop = 0;
505 if (enterAlternate) {
506 if (!alternate.base || alternate.size > (~static_cast<uintptr_t>(0) - alternate.base)) {
507 return Failed;
508 }
509 stackTop = alternate.base + alternate.size;
510 } else {
511 if (originalStack < 128) {
512 return Failed;
513 }
514 stackTop = originalStack - 128;
515 }
516
517 if (stackTop < sizeof(Fpstate)) {
518 return Failed;
519 }
520 uintptr_t fpstateAddress = alignDown(stackTop - sizeof(Fpstate), 64);
521 if (fpstateAddress < sizeof(RtSigframe) + 8) {
522 return Failed;
523 }
524 uintptr_t frameAddress = alignDown(fpstateAddress - sizeof(RtSigframe), 16) - 8;
525
526 if (!userRegion(frameAddress, sizeof(RtSigframe), PosixSubsystem::SafeWrite) ||
527 !userRegion(fpstateAddress, sizeof(Fpstate), PosixSubsystem::SafeWrite)) {
528 return Failed;
529 }
530
531 if (enterAlternate || wasOnAlternate) {
532 uintptr_t alternateEnd = alternate.base + alternate.size;
533 if (frameAddress < alternate.base || fpstateAddress + sizeof(Fpstate) > alternateEnd) {
534 return Failed;
535 }
536 }
537
538 RtSigframe frame = {};
539 Fpstate savedFpstate = {};
540 if (!NMFaultHandler::saveCurrentThreadFpuState(&savedFpstate, true)) {
541 return Failed;
542 }
543 Fpstate fpstate = savedFpstate;
544 ByteSet(fpstate.reserved3, 0, sizeof(fpstate.reserved3));
545
546 const uint64_t currentMask = thread->getSignalMask();
547 const uint64_t oldMask = thread->getSignalMaskForReturnFrame();
548 frame.restorer = disposition.restorer;
549 frame.ucontext.flags = SupportedUcontextFlags;
550 if (alternate.enabled) {
551 frame.ucontext.stack.stackPointer = alternate.base;
552 frame.ucontext.stack.size = alternate.size;
553 frame.ucontext.stack.flags = wasOnAlternate ? SS_ONSTACK : 0;
554 } else {
555 frame.ucontext.stack.flags = SS_DISABLE;
556 }
557 populateSigcontext(frame.ucontext.mcontext, state, oldMask,
558 exception == Subsystem::PageFault || exception == Subsystem::FileMappingFault
559 ? faultAddress
560 : 0,
561 errorCode, fpstateAddress);
562 frame.ucontext.signalMask = oldMask;
563
564 setSiginfo32(frame.info, 0, signal);
565 setSiginfo32(frame.info, 4, 0);
566 setSiginfo32(frame.info, 8, signalCode(exception, errorCode));
567 setSiginfo64(frame.info, 16, signalAddress(exception, state, faultAddress));
568 setSiginfo32(frame.info, 24, static_cast<int32_t>(state.getInterruptNumber()));
569
570 if (!PosixSubsystem::copyToUser(reinterpret_cast<void*>(fpstateAddress), &fpstate,
571 sizeof(fpstate)) ||
572 !PosixSubsystem::copyToUser(reinterpret_cast<void*>(frameAddress), &frame, sizeof(frame))) {
574 FATAL("Could not restore FPU state after a failed signal-frame copy.");
575 }
576 return Failed;
577 }
578
579 uint64_t handlerMask = currentMask | disposition.signalMask;
580 if (!(disposition.flags & SA_NODEFER)) {
581 handlerMask |= static_cast<uint64_t>(1) << (signal - 1);
582 }
583 thread->commitSignalHandlerMask(handlerMask & ~UnblockableSignals);
584 alternate.inUse = wasOnAlternate || enterAlternate;
585
586 state.setRegister(0, 0);
587 state.setRegister(4, static_cast<uintptr_t>(signal));
588 state.setRegister(5, frameAddress + __builtin_offsetof(RtSigframe, info));
589 state.setRegister(3, frameAddress + __builtin_offsetof(RtSigframe, ucontext));
590 state.setInstructionPointer(disposition.handler);
591 state.setStackPointer(frameAddress);
592 state.setFlags((state.getFlags() & ~HandlerFlagsToClear) | SafeUserRflags);
593 return Delivered;
594}
595
596void LinuxAmd64Signal::sigreturn(SyscallState& state) {
597 uintptr_t syscallStack = state.getStackPointer();
598 if (syscallStack < 8) {
599 badFrame();
600 return;
601 }
602 uintptr_t frameAddress = syscallStack - 8;
603 if (!userRegion(frameAddress, sizeof(RtSigframe), PosixSubsystem::SafeRead)) {
604 badFrame();
605 return;
606 }
607
608 RtSigframe frame = {};
609 if (!PosixSubsystem::copyFromUser(&frame, reinterpret_cast<const void*>(frameAddress),
610 sizeof(frame))) {
611 badFrame();
612 return;
613 }
614 const Sigcontext& context = frame.ucontext.mcontext;
615
616 if ((frame.ucontext.flags & ~SupportedUcontextFlags) || !userCodeSegment(context.cs) ||
617 context.ss != UserStackSegment || !userBounds(context.rip, 1) ||
618 !userBounds(context.rsp, 1) || !context.fpstate || (context.fpstate & 0x3F) ||
619 !userRegion(context.fpstate, sizeof(Fpstate), PosixSubsystem::SafeRead)) {
620 badFrame();
621 return;
622 }
623
624 int alternateFlags = frame.ucontext.stack.flags;
625 if (alternateFlags & ~(SS_ONSTACK | SS_DISABLE) ||
626 ((alternateFlags & SS_ONSTACK) && (alternateFlags & SS_DISABLE))) {
627 badFrame();
628 return;
629 }
630
631 Thread::AlternateSignalStack restoredAlternate;
632 if (!(alternateFlags & SS_DISABLE)) {
633 restoredAlternate.base = frame.ucontext.stack.stackPointer;
634 restoredAlternate.size = frame.ucontext.stack.size;
635 restoredAlternate.enabled = true;
636 restoredAlternate.inUse = alternateFlags & SS_ONSTACK;
637 if (restoredAlternate.size < MINSIGSTKSZ ||
638 !userBounds(restoredAlternate.base, restoredAlternate.size) ||
639 (restoredAlternate.inUse && !onAlternateStack(context.rsp, restoredAlternate))) {
640 badFrame();
641 return;
642 }
643 }
644
645 Fpstate fpstate = {};
646 if (!PosixSubsystem::copyFromUser(&fpstate, reinterpret_cast<const void*>(context.fpstate),
647 sizeof(fpstate))) {
648 badFrame();
649 return;
650 }
651 for (size_t i = 0; i < 12; ++i) {
652 if (fpstate.reserved3[i]) {
653 badFrame();
654 return;
655 }
656 }
658 badFrame();
659 return;
660 }
661
662 Thread* thread = Processor::information().getCurrentThread();
663 thread->setSignalMask(frame.ucontext.signalMask & ~UnblockableSignals);
664 thread->getAlternateSignalStack() = restoredAlternate;
665
666 X64ProcessorState restored;
667 restored.r8 = context.r8;
668 restored.r9 = context.r9;
669 restored.r10 = context.r10;
670 restored.r11 = context.r11;
671 restored.r12 = context.r12;
672 restored.r13 = context.r13;
673 restored.r14 = context.r14;
674 restored.r15 = context.r15;
675 restored.rdi = context.rdi;
676 restored.rsi = context.rsi;
677 restored.rbp = context.rbp;
678 restored.rbx = context.rbx;
679 restored.rdx = context.rdx;
680 restored.rax = context.rax;
681 restored.rcx = context.rcx;
682 restored.rip = context.rip;
683 restored.rflags = (context.rflags & RestorableRflags) | SafeUserRflags;
684 restored.rsp = context.rsp;
685
686 if (!SyscallManager::instance().requestStateRestore(restored)) {
687 FATAL("Signal state restoration was not dispatched.");
688 }
689}
690
691#endif
Definition Event.h:49
virtual bool isDeletable()
Definition Event.cc:225
UserReturnDelivery
Definition Event.h:58
SignalEvent * cloneForDisposition() override
Event::UserReturnDelivery deliverAtUserReturn(InterruptState &state) override
static EXPORTED_PUBLIC bool saveCurrentThreadFpuState(void *buffer, bool resetForSignalHandler)
static EXPORTED_PUBLIC bool restoreCurrentThreadFpuState(const void *buffer)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
bool getSignalDisposition(size_t sig, SignalDisposition &disposition, bool beginDelivery=false)
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
static ProcessorInformation & information()
static EXPORTED_PUBLIC SyscallManager & instance()
uint64_t getSignalMask()
Definition Thread.cc:2002
void commitSignalHandlerMask(uint64_t mask)
Definition Thread.cc:2018
const SyscallState * getOriginalSyscallState() const
Definition Thread.h:719
Process * getParent() const
Definition Thread.h:338
void setSignalMask(uint64_t mask)
Definition Thread.cc:2007
uint64_t getSignalMaskForReturnFrame()
Definition Thread.cc:2012
void setCurrentSignalDelivery(size_t signalNumber, size_t continuationEpoch)
Definition Thread.cc:2042
Definition User.h:32
virtual uintptr_t getUserStart() const =0
virtual uintptr_t getKernelStart() const =0
virtual bool isAddressValid(void *virtualAddress)=0