Skip to content

Commit 41025a1

Browse files
fixup! [libunwind] Replace process_vm_readv with pipe
1 parent 602b3f2 commit 41025a1

File tree

1 file changed

+36
-30
lines changed

1 file changed

+36
-30
lines changed

libunwind/src/UnwindCursor.hpp

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,26 @@ class UnwindCursor : public AbstractUnwindCursor {
558558
_info.handler = 0;
559559
return UNW_STEP_SUCCESS;
560560
}
561+
bool isReadableAddr(const void *addr) const {
562+
// This code is heavily based on Abseil's 'address_is_readable.cc',
563+
// which is Copyright Abseil Authors (2017), and provided under
564+
// the Apache License 2.0.
565+
566+
// We have to check that addr is a nullptr because sigprocmask allows that
567+
// as an argument without failure.
568+
if (!addr)
569+
return false;
570+
// Align to 8-bytes.
571+
const auto uintptr_addr = reinterpret_cast<uintptr_t>(addr) & ~uintptr_t{7};
572+
const auto sigsetaddr = reinterpret_cast<sigset_t *>(uintptr_addr);
573+
[[maybe_unused]] int Result = sigprocmask(/*how=*/-1, sigsetaddr, nullptr);
574+
// Because our "how" is invalid, this syscall should always fail, and our
575+
// errno should always be EINVAL or an EFAULT. EFAULT is not guaranteed
576+
// by the POSIX standard, so this is (for now) Linux specific.
577+
assert(Result == -1);
578+
assert(errno == EFAULT || errno == EINVAL);
579+
return errno != EFAULT;
580+
}
561581

562582
A &_addressSpace;
563583
unw_proc_info_t _info;
@@ -2701,19 +2721,13 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
27012721
// [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
27022722
const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
27032723
// The PC might contain an invalid address if the unwind info is bad, so
2704-
// directly accessing it could cause a segfault. Use pipe/write/read to read
2705-
// the memory safely instead.
2706-
int pipefd[2];
2707-
if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
2708-
return false;
2709-
uint32_t instructions[2];
2710-
const auto bufferSize = sizeof instructions;
2711-
if (write(pipefd[1], reinterpret_cast<void *>(pc), bufferSize) != bufferSize)
2724+
// directly accessing it could cause a SIGSEGV.
2725+
if (!isReadableAddr(static_cast<void *>(pc)) ||
2726+
!isReadableAddr(static_cast<void *>(pc + 4)))
27122727
return false;
2713-
const auto bytesRead = read(pipefd[0], instructions, bufferSize);
2728+
auto *instructions = static_cast<uint32_t *>(pc);
27142729
// Look for instructions: mov x8, #0x8b; svc #0x0
2715-
if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
2716-
instructions[1] != 0xd4000001)
2730+
if (instructions[0] != 0xd2801168 || instructions[1] != 0xd4000001)
27172731
return false;
27182732

27192733
_info = {};
@@ -2762,21 +2776,18 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
27622776
template <typename A, typename R>
27632777
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_riscv &) {
27642778
const pint_t pc = static_cast<pint_t>(getReg(UNW_REG_IP));
2765-
int pipefd[2];
2766-
if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
2767-
return false;
2768-
uint32_t instructions[2];
2769-
const auto bufferSize = sizeof instructions;
2770-
if (write(pipefd[1], reinterpret_cast<void *>(pc), bufferSize) != bufferSize)
2779+
// The PC might contain an invalid address if the unwind info is bad, so
2780+
// directly accessing it could cause a SIGSEGV.
2781+
if (!isReadableAddr(static_cast<void *>(pc)) ||
2782+
!isReadableAddr(static_cast<void *>(pc + 4)))
27712783
return false;
2772-
const auto bytesRead = read(pipefd[0], instructions, bufferSize);
2784+
const auto *instructions = static_cast<uint32_t *>(pc);
27732785
// Look for the two instructions used in the sigreturn trampoline
27742786
// __vdso_rt_sigreturn:
27752787
//
27762788
// 0x08b00893 li a7,0x8b
27772789
// 0x00000073 ecall
2778-
if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
2779-
instructions[1] != 0x00000073)
2790+
if (instructions[0] != 0x08b00893 || instructions[1] != 0x00000073)
27802791
return false;
27812792

27822793
_info = {};
@@ -2825,17 +2836,12 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_s390x &) {
28252836
// onto the stack.
28262837
const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
28272838
// The PC might contain an invalid address if the unwind info is bad, so
2828-
// directly accessing it could cause a segfault. Use pipe/write/read to
2829-
// read the memory safely instead.
2830-
int pipefd[2];
2831-
if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
2832-
return false;
2833-
uint16_t inst;
2834-
const auto bufferSize = sizeof inst;
2835-
if (write(pipefd[1], reinterpret_cast<void *>(pc), bufferSize) != bufferSize)
2839+
// directly accessing it could cause a SIGSEGV.
2840+
if (!isReadableAddr(static_cast<void *>(pc)) ||
2841+
!isReadableAddr(static_cast<void *>(pc + 2)))
28362842
return false;
2837-
const auto bytesRead = read(pipefd[0], &inst, bufferSize);
2838-
if (bytesRead == bufferSize && (inst == 0x0a77 || inst == 0x0aad)) {
2843+
const auto inst = *reinterpret_cast<uint16_t *>(pc);
2844+
if (inst == 0x0a77 || inst == 0x0aad) {
28392845
_info = {};
28402846
_info.start_ip = pc;
28412847
_info.end_ip = pc + 2;

0 commit comments

Comments
 (0)