Skip to content

Commit 24ec521

Browse files
committed
[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
1 parent a6316d6 commit 24ec521

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

libunwind/src/UnwindCursor.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,8 +2695,14 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_s390x &) {
26952695
// own restorer function, though, or user-mode QEMU might write a trampoline
26962696
// onto the stack.
26972697
const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
2698-
const uint16_t inst = _addressSpace.get16(pc);
2699-
if (inst == 0x0a77 || inst == 0x0aad) {
2698+
// The PC might contain an invalid address if the unwind info is bad, so
2699+
// directly accessing it could cause a segfault. Use process_vm_readv to
2700+
// read the memory safely instead.
2701+
uint16_t inst;
2702+
struct iovec local_iov = {&inst, sizeof inst};
2703+
struct iovec remote_iov = {reinterpret_cast<void *>(pc), sizeof inst};
2704+
long bytesRead = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0);
2705+
if (bytesRead == sizeof inst && (inst == 0x0a77 || inst == 0x0aad)) {
27002706
_info = {};
27012707
_info.start_ip = pc;
27022708
_info.end_ip = pc + 2;

libunwind/test/bad_unwind_info.pass.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// Ensure that libunwind doesn't crash on invalid info; the Linux aarch64
1111
// sigreturn frame check would previously attempt to access invalid memory in
1212
// this scenario.
13-
// REQUIRES: linux && (target={{aarch64-.+}} || target={{x86_64-.+}})
13+
// REQUIRES: linux && (target={{aarch64-.+}} || target={{s390x-.+}} || target={{x86_64-.+}})
1414

1515
// GCC doesn't support __attribute__((naked)) on AArch64.
1616
// UNSUPPORTED: gcc
@@ -36,6 +36,20 @@ __attribute__((naked)) void bad_unwind_info() {
3636
".cfi_def_cfa_offset 0\n"
3737
".cfi_restore x30\n"
3838
"ret\n");
39+
#elif defined(__s390x__)
40+
__asm__("stmg %r14,%r15,112(%r15)\n"
41+
"mvghi 104(%r15),4\n"
42+
"# purposely use incorrect offset for %r14\n"
43+
".cfi_offset 14, -56\n"
44+
".cfi_offset 15, -40\n"
45+
"lay %r15,-160(%r15)\n"
46+
".cfi_def_cfa_offset 320\n"
47+
"brasl %r14,stepper\n"
48+
"lmg %r14,%r15,272(%r15)\n"
49+
".cfi_restore 15\n"
50+
".cfi_restore 14\n"
51+
".cfi_def_cfa_offset 160\n"
52+
"br %r14\n");
3953
#elif defined(__x86_64__)
4054
__asm__("pushq %rbx\n"
4155
".cfi_def_cfa_offset 16\n"
@@ -48,7 +62,7 @@ __attribute__((naked)) void bad_unwind_info() {
4862
".cfi_def_cfa_offset 8\n"
4963
"ret\n");
5064
#else
51-
#error This test is only supported on aarch64 or x86-64
65+
#error This test is only supported on aarch64, s390x, or x86-64
5266
#endif
5367
}
5468

0 commit comments

Comments
 (0)