From: Ulrich Weigand Date: Mon, 18 Jul 2022 14:54:48 +0000 (+0200) Subject: [libunwind][SystemZ] Use process_vm_readv to avoid potential segfaults X-Git-Tag: upstream/15.0.7~1324 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=24ec521cd7bb51447f4ab03460d91c57378d49f7;p=platform%2Fupstream%2Fllvm.git [libunwind][SystemZ] Use process_vm_readv to avoid potential segfaults Fix potential crashes during unwind when checking for signal frames and the current PC is invalid. The same bug was fixed for aarch64 in https://reviews.llvm.org/D126343. Reviewed by: MaskRay Differential Revision: https://reviews.llvm.org/D129856 --- diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index e363f9e..b8bd9bc 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2695,8 +2695,14 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) { // own restorer function, though, or user-mode QEMU might write a trampoline // onto the stack. const pint_t pc = static_cast(this->getReg(UNW_REG_IP)); - const uint16_t inst = _addressSpace.get16(pc); - if (inst == 0x0a77 || inst == 0x0aad) { + // The PC might contain an invalid address if the unwind info is bad, so + // directly accessing it could cause a segfault. Use process_vm_readv to + // read the memory safely instead. + uint16_t inst; + struct iovec local_iov = {&inst, sizeof inst}; + struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst}; + long bytesRead = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0); + if (bytesRead == sizeof inst && (inst == 0x0a77 || inst == 0x0aad)) { _info = {}; _info.start_ip = pc; _info.end_ip = pc + 2; diff --git a/libunwind/test/bad_unwind_info.pass.cpp b/libunwind/test/bad_unwind_info.pass.cpp index 97427ea9..06017d17 100644 --- a/libunwind/test/bad_unwind_info.pass.cpp +++ b/libunwind/test/bad_unwind_info.pass.cpp @@ -10,7 +10,7 @@ // Ensure that libunwind doesn't crash on invalid info; the Linux aarch64 // sigreturn frame check would previously attempt to access invalid memory in // this scenario. -// REQUIRES: linux && (target={{aarch64-.+}} || target={{x86_64-.+}}) +// REQUIRES: linux && (target={{aarch64-.+}} || target={{s390x-.+}} || target={{x86_64-.+}}) // GCC doesn't support __attribute__((naked)) on AArch64. // UNSUPPORTED: gcc @@ -36,6 +36,20 @@ __attribute__((naked)) void bad_unwind_info() { ".cfi_def_cfa_offset 0\n" ".cfi_restore x30\n" "ret\n"); +#elif defined(__s390x__) + __asm__("stmg %r14,%r15,112(%r15)\n" + "mvghi 104(%r15),4\n" + "# purposely use incorrect offset for %r14\n" + ".cfi_offset 14, -56\n" + ".cfi_offset 15, -40\n" + "lay %r15,-160(%r15)\n" + ".cfi_def_cfa_offset 320\n" + "brasl %r14,stepper\n" + "lmg %r14,%r15,272(%r15)\n" + ".cfi_restore 15\n" + ".cfi_restore 14\n" + ".cfi_def_cfa_offset 160\n" + "br %r14\n"); #elif defined(__x86_64__) __asm__("pushq %rbx\n" ".cfi_def_cfa_offset 16\n" @@ -48,7 +62,7 @@ __attribute__((naked)) void bad_unwind_info() { ".cfi_def_cfa_offset 8\n" "ret\n"); #else -#error This test is only supported on aarch64 or x86-64 +#error This test is only supported on aarch64, s390x, or x86-64 #endif }