Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShoaib Meenai <smeenai@fb.com>2022-05-26 07:39:12 +0300
committerShoaib Meenai <smeenai@fb.com>2022-05-26 19:12:51 +0300
commit0be0a53df65cb402359c257922d80ab93d86fb40 (patch)
tree0e12f091edf7840f256c4bd67ebd82a3283a84ee /libunwind/src/UnwindCursor.hpp
parent3d2b5b7b87857b0cc4c322cfc145c46c42fe2bbf (diff)
[libunwind] Use process_vm_readv to avoid potential segfaults
We've observed segfaults in libunwind when attempting to check for the Linux aarch64 sigreturn frame, presumably because of bad unwind info leading to an incorrect PC that we attempt to read from. Use process_vm_readv to read the memory safely instead. The s390x code path should likely follow suit, but I don't have the hardware to be able to test that, so I didn't modify it here either. Reviewed By: MaskRay, rprichard, #libunwind Differential Revision: https://reviews.llvm.org/D126343
Diffstat (limited to 'libunwind/src/UnwindCursor.hpp')
-rw-r--r--libunwind/src/UnwindCursor.hpp33
1 files changed, 24 insertions, 9 deletions
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 01f0c404a2ac..6e8fc45ebfa8 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -32,6 +32,9 @@
#if defined(_LIBUNWIND_TARGET_LINUX) && \
(defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_S390X))
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <unistd.h>
#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
#endif
@@ -2620,16 +2623,28 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
//
// [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+ // 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. process_vm_readv was added in Linux 3.2, and
+ // AArch64 supported was added in Linux 3.7, so the syscall is guaranteed to
+ // be present. Unfortunately, there are Linux AArch64 environments where the
+ // libc wrapper for the syscall might not be present (e.g. Android 5), so call
+ // the syscall directly instead.
+ uint32_t instructions[2];
+ struct iovec local_iov = {&instructions, sizeof instructions};
+ struct iovec remote_iov = {reinterpret_cast<void *>(pc), sizeof instructions};
+ long bytesRead =
+ syscall(SYS_process_vm_readv, getpid(), &local_iov, 1, &remote_iov, 1, 0);
// Look for instructions: mov x8, #0x8b; svc #0x0
- if (_addressSpace.get32(pc) == 0xd2801168 &&
- _addressSpace.get32(pc + 4) == 0xd4000001) {
- _info = {};
- _info.start_ip = pc;
- _info.end_ip = pc + 4;
- _isSigReturn = true;
- return true;
- }
- return false;
+ if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+ instructions[1] != 0xd4000001)
+ return false;
+
+ _info = {};
+ _info.start_ip = pc;
+ _info.end_ip = pc + 4;
+ _isSigReturn = true;
+ return true;
}
template <typename A, typename R>