[libunwind] [libunwind] Move errno.h and signal.h includes under the block where they're needed (PR #78054)

2024-01-13 Thread Jordan R AW via cfe-commits

ajordanr-google wrote:

Done! Thanks for the heads up on the email. I'm not too familiar with the 
GitHub workflow still. Also thanks for this fix PR.

https://github.com/llvm/llvm-project/pull/78054
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[lldb] [llvm] [libcxx] [flang] [libc] [clang-tools-extra] [clang] [compiler-rt] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2024-01-04 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 9d4665cf1ddda98129af2f6ff575989cec49af6d Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 01/13] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2024-01-02 Thread Jordan R AW via cfe-commits

ajordanr-google wrote:

All CI runs are failing on unrelated tests... can we re-run the CI again in a 
week or so?

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2024-01-02 Thread Jordan R AW via cfe-commits

ajordanr-google wrote:

Rebased to include 47413bb2760e63a3302871ea770d6c0f5a742036 (a merge commit 
seemed silly?). No other changes have been made.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2024-01-02 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 9d4665cf1ddda98129af2f6ff575989cec49af6d Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 01/13] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[llvm] [clang] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-26 Thread Jordan R AW via cfe-commits

ajordanr-google wrote:

Hmm. It looks like `[[maybe_unused]]` is still disallowed...

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang-tools-extra] [clang] [llvm] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-21 Thread Jordan R AW via cfe-commits

ajordanr-google wrote:

I don't have Commit Access (I so rarely actually commit to upstream), and I 
don't think I have yet the "track record of submitting high quality patches" :)

Can someone else merge this once the checks are green?

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang-tools-extra] [clang] [llvm] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-21 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,37 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017).
+
+  const auto sigsetAddr = reinterpret_cast(addr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+  // We MUST use a raw syscall here, as wrappers may try to access
+  // sigsetAddr which may cause a SIGSEGV. A raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). For the majority of architectures,
+  // it's 64 bits (_NSIG), and libc NSIG is _NSIG + 1.
+  const auto kernelSigsetSize = NSIG / 8;
+  const int Result = syscall(SYS_rt_sigprocmask, /*how=*/~0, sigsetAddr,
+ nullptr, kernelSigsetSize);
+  (void)Result;
+  // Because our "how" is invalid, this syscall should always fail, and our
+  // errno should always be EINVAL or an EFAULT. EFAULT is not guaranteed
+  // by the POSIX standard. Additionally, this relies on the Linux kernel
+  // to check copy_from_user before checking if the "how" argument is
+  // invalid.
+  assert(Result == -1);
+  assert(errno == EFAULT || errno == EINVAL);
+  return errno != EFAULT;

ajordanr-google wrote:

We should probably save and restore, as we do this above in 
`getInfoFromTBTable`. Good point. Done.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libunwind] [llvm] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-21 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,37 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017).
+
+  const auto sigsetAddr = reinterpret_cast(addr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+  // We MUST use a raw syscall here, as wrappers may try to access
+  // sigsetAddr which may cause a SIGSEGV. A raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). For the majority of architectures,
+  // it's 64 bits (_NSIG), and libc NSIG is _NSIG + 1.
+  const auto kernelSigsetSize = NSIG / 8;
+  const int Result = syscall(SYS_rt_sigprocmask, /*how=*/~0, sigsetAddr,
+ nullptr, kernelSigsetSize);
+  (void)Result;
+  // Because our "how" is invalid, this syscall should always fail, and our
+  // errno should always be EINVAL or an EFAULT. EFAULT is not guaranteed
+  // by the POSIX standard. Additionally, this relies on the Linux kernel

ajordanr-google wrote:

Done.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[llvm] [libunwind] [clang] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-21 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,37 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017).

ajordanr-google wrote:

Done

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang-tools-extra] [clang] [llvm] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-21 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 01/13] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[llvm] [clang-tools-extra] [clang] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[llvm] [clang-tools-extra] [clang] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang] [llvm] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang] [llvm] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);

ajordanr-google wrote:

Gotcha. I ended up using `NSIG/8` since it rounds down anyways, and I checked 
the glibc code and it has 128 instead of 127, and I think we would actually 
want 128/8 instead if I'm reading the mips case right. It's not that important 
if we don't care about mips.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang] [llvm] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2817,7 +2817,7 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   const pint_t pc = static_cast(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 SIGSEGV.
-  if (!isReadableAddr(pc) || !isReadableAddr(pc + 2))
+  if (!isReadableAddr(pc))

ajordanr-google wrote:

I think that's probably fine, as long as we aren't hitting a SIGSEGV.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [clang] [llvm] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -26,7 +26,7 @@
 __attribute__((naked)) void bad_unwind_info() {
 #if defined(__aarch64__)
   __asm__("// not using 0 because unwinder was already resilient to that\n"
-  "mov x8, #4\n"
+  "mov x8, #12\n"

ajordanr-google wrote:

Undid this with the removal of the alignment code.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [clang-tools-extra] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 01/12] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[clang-tools-extra] [clang] [llvm] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 01/11] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[clang] [llvm] [clang-tools-extra] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);

ajordanr-google wrote:

How about `(NSIG-1)/8`? 
https://www.gnu.org/software/libc/manual/html_node/Standard-Signals.html. Just 
let libc handle it. It should work cleanly for everything that's not MIPS. I 
don't have a MIPS system to test if this works for it.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[llvm] [clang] [clang-tools-extra] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);

ajordanr-google wrote:

Looking at linux-6.6.7 source code, we have some minor variety on `sigset_t` 
size...

TL;DR: They are almost all `_NSIG` bits long, which is 64 bits or, in the case 
of MIPS, maybe 128? There are two exceptions to this, where they are not a 
struct of size `_NSIG/_NSIG_BPW * sizeof(unsigned long)` but rather just 
`unsigned long`. I assume `_NSIG_BPW == sizeof(long) == sizeof(unsigned long)`, 
which seems reasonable given the comments (and not `_NSIG_BPW == sizeof(int)`).

---

`sigset_t` is almost always defined as:

```
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
```

Where:

```
arch/parisc/include/asm/signal.h-7-#define _NSIG64
arch/parisc/include/asm/signal.h-8-/* bits-per-word, where word apparently 
means 'long' not 'int' */
arch/parisc/include/asm/signal.h-9-#define _NSIG_BPWBITS_PER_LONG
arch/parisc/include/asm/signal.h:10:#define _NSIG_WORDS (_NSIG / _NSIG_BPW)

// or

arch/xtensa/include/uapi/asm/signal.h-18-#define _NSIG  64
arch/xtensa/include/uapi/asm/signal.h-19-#define _NSIG_BPW  32
arch/xtensa/include/uapi/asm/signal.h:20:#define _NSIG_WORDS(_NSIG / 
_NSIG_BPW)

// or

arch/ia64/include/asm/signal.h-15-#define _NSIG 64
arch/ia64/include/asm/signal.h-16-#define _NSIG_BPW 64
arch/ia64/include/asm/signal.h:17:#define _NSIG_WORDS   (_NSIG / _NSIG_BPW)

// or

arch/alpha/include/asm/signal.h-10-#define _NSIG64
arch/alpha/include/asm/signal.h-11-#define _NSIG_BPW64
arch/alpha/include/asm/signal.h:12:#define _NSIG_WORDS  (_NSIG / _NSIG_BPW)

// or

arch/arm/include/asm/signal.h-10-#define _NSIG  64
arch/arm/include/asm/signal.h-11-#define _NSIG_BPW  32
arch/arm/include/asm/signal.h:12:#define _NSIG_WORDS(_NSIG / _NSIG_BPW)

// or

arch/s390/include/asm/signal.h-12-/* Most things should be clean enough to 
redefine this at will, if care
arch/s390/include/asm/signal.h-13-   is taken to make libc match.  */
arch/s390/include/asm/signal.h-14-#include 
arch/s390/include/asm/signal.h-15-#define _NSIG   _SIGCONTEXT_NSIG
arch/s390/include/asm/signal.h-16-#define _NSIG_BPW   _SIGCONTEXT_NSIG_BPW
arch/s390/include/asm/signal.h:17:#define _NSIG_WORDS _SIGCONTEXT_NSIG_WORDS
arch/s390/include/uapi/asm/sigcontext.h:30:/* Has to be at least _NSIG_WORDS 
from asm/signal.h */
arch/s390/include/uapi/asm/sigcontext.h-31-#define _SIGCONTEXT_NSIG 64
arch/s390/include/uapi/asm/sigcontext.h-32-#define _SIGCONTEXT_NSIG_BPW 64

// or

arch/x86/include/asm/signal.h-11-#define _NSIG  64
arch/x86/include/asm/signal.h-12-
arch/x86/include/asm/signal.h-13-#ifdef __i386__
arch/x86/include/asm/signal.h-14-# define _NSIG_BPW 32
arch/x86/include/asm/signal.h-15-#else
arch/x86/include/asm/signal.h-16-# define _NSIG_BPW 64
arch/x86/include/asm/signal.h-17-#endif
arch/x86/include/asm/signal.h-18-
arch/x86/include/asm/signal.h:19:#define _NSIG_WORDS(_NSIG / _NSIG_BPW)

// or

arch/m68k/include/asm/signal.h-10-#define _NSIG 64
arch/m68k/include/asm/signal.h-11-#define _NSIG_BPW 32
arch/m68k/include/asm/signal.h:12:#define _NSIG_WORDS   (_NSIG / _NSIG_BPW)

// or (quite weirdly)

arch/mips/include/uapi/asm/signal.h-15-#define _NSIG128
arch/mips/include/uapi/asm/signal.h-16-#define _NSIG_BPW
(sizeof(unsigned long) * 8)
arch/mips/include/uapi/asm/signal.h:17:#define _NSIG_WORDS  (_NSIG / 
_NSIG_BPW)

// or

arch/sparc/include/uapi/asm/signal.h-81-#define __NEW_NSIG  64
arch/sparc/include/uapi/asm/signal.h-82-#ifdef __arch64__
arch/sparc/include/uapi/asm/signal.h-83-#define _NSIG_BPW   64
arch/sparc/include/uapi/asm/signal.h-84-#else
arch/sparc/include/uapi/asm/signal.h-85-#define _NSIG_BPW   32
arch/sparc/include/uapi/asm/signal.h-86-#endif

[libunwind] [clang-tools-extra] [llvm] [clang] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);
+  [[maybe_unused]] const int Result =
+  syscall(SYS_rt_sigprocmask, /*how=*/~0, sigsetAddr, sigsetAddr,
+  approxKernelSigsetSize);
+  // Because our "how" is invalid, this syscall should always fail, and our

ajordanr-google wrote:

Thanks, done.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);
+  [[maybe_unused]] const int Result =
+  syscall(SYS_rt_sigprocmask, /*how=*/~0, sigsetAddr, sigsetAddr,

ajordanr-google wrote:

Done

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2762,18 +2757,17 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
-  uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  // The PC might contain an invalid address if the unwind info is bad, so
+  // directly accessing it could cause a SIGSEGV.
+  if (!isReadableAddr(pc) || !isReadableAddr(pc + 4))

ajordanr-google wrote:

Given Paul's offline comments, I've removed the alignment as it seems to be a 
bug in QEMU not Linux.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[llvm] [clang] [clang-tools-extra] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);
+  [[maybe_unused]] const int Result =
+  syscall(SYS_rt_sigprocmask, /*how=*/~0, sigsetAddr, sigsetAddr,
+  approxKernelSigsetSize);
+  // Because our "how" is invalid, this syscall should always fail, and our
+  // errno should always be EINVAL or an EFAULT. EFAULT is not guaranteed
+  // by the POSIX standard, so this is (for now) Linux specific.

ajordanr-google wrote:

Removed, thanks.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[llvm] [clang] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2822,13 +2816,11 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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.
-  uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == sizeof inst && (inst == 0x0a77 || inst == 0x0aad)) {
+  // directly accessing it could cause a SIGSEGV.
+  if (!isReadableAddr(pc) || !isReadableAddr(pc + 2))

ajordanr-google wrote:

Done

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libunwind] [llvm] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',

ajordanr-google wrote:

Done.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 01/10] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[llvm] [clang] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-19 Thread Jordan R AW via cfe-commits


@@ -2974,6 +2966,39 @@ bool UnwindCursor::getFunctionName(char *buf, 
size_t bufLen,
  buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
+template 
+bool UnwindCursor::isReadableAddr(const pint_t addr) const {
+  // This code is heavily based on Abseil's 'address_is_readable.cc',
+  // which is Copyright Abseil Authors (2017), and provided under
+  // the Apache License 2.0.
+
+  // Align to 8-bytes.
+  const auto alignedAddr = addr & ~pint_t{7};
+  const auto sigsetAddr = reinterpret_cast(alignedAddr);
+  // We have to check that addr is nullptr because sigprocmask allows that
+  // as an argument without failure.
+  if (!sigsetAddr)
+return false;
+
+  // We MUST use the raw sigprocmask syscall here, as wrappers may try to
+  // access sigsetAddr which may cause a SIGSEGV. The raw syscall however is
+  // safe. Additionally, we need to pass the kernel_sigset_size, which is
+  // different from libc sizeof(sigset_t). Some archs have sigset_t
+  // defined as unsigned long, so let's use that.
+  const auto approxKernelSigsetSize = sizeof(unsigned long);

ajordanr-google wrote:

Thanks! If you have a better idea on how to make this more robust, I'd love to 
know. For now I've hardcoded it to 8 then.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits


@@ -26,7 +26,7 @@
 __attribute__((naked)) void bad_unwind_info() {
 #if defined(__aarch64__)
   __asm__("// not using 0 because unwinder was already resilient to that\n"
-  "mov x8, #4\n"
+  "mov x8, #12\n"

ajordanr-google wrote:

Note: changed this for an 8 byte alignment check, because `0x4 & 0x7` is `0x0`, 
whereas `0xC & 0x7` is `0x8`.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[llvm] [clang] [libunwind] [clang-tools-extra] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/8] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[clang] [llvm] [clang-tools-extra] [libunwind] [libunwind] Replace process_vm_readv with SYS_rt_sigprocmask (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [clang-tools-extra] [libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [libunwind] [clang] [llvm] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/7] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-18 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/7] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-13 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/5] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-13 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/4] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-13 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/3] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d9..5e4e376220daa0 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == 

[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-13 Thread Jordan R AW via cfe-commits


@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);

ajordanr-google wrote:

Gotcha, that all makes sense. Thanks!

---

Playing around with `SYS_rt_procmask` on Linux x86_64, There's apparently a 
point in which we can still read a 
given address but `SYS_rt_procmask` sets `errno = 14` (Bad Address)

Looping over the raw syscall with:

```
syscall(SYS_rt_sigprocmask, /* how= */ -1, Addr, Addr, 8);


until it breaks gives

```
Addr: 0x56322ab46ff8; Offset: 59704; errno: 22; Value: 0x0
Addr: 0x56322ab46ff9; Offset: 59705; errno: 14; Value: 0x0
Addr: 0x56322ab46ffa; Offset: 59706; errno: 14; Value: 0x0
Addr: 0x56322ab46ffb; Offset: 59707; errno: 14; Value: 0x0
Addr: 0x56322ab46ffc; Offset: 59708; errno: 14; Value: 0x0
Addr: 0x56322ab46ffd; Offset: 59709; errno: 14; Value: 0x0
Addr: 0x56322ab46ffe; Offset: 59710; errno: 14; Value: 0x0
Addr: 0x56322ab46fff; Offset: 59711; errno: 14; Value: 0x0
fish: Job 1, './main' terminated by signal SIGSEGV (Address boundary error)
```

Seems there's about a 7 to 8 byte boundary where it fails but we can still 
read, at least on x86_64. So the 8 byte alignment on AARCH64 as mentioned in 
address_is_readable.cc seems to make sense, though we'd probably want to still 
check both the beginning and end of the `instructions` range. I think that 
should be sufficient.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-08 Thread Jordan R AW via cfe-commits


@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;

ajordanr-google wrote:

Fixed.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-08 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google updated 
https://github.com/llvm/llvm-project/pull/74791

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH 1/2] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d..5e4e376220daa 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)
 return false;
 
@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;
-  struct iovec local_iov = {, sizeof inst};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst};
-  long bytesRead = process_vm_readv(getpid(), _iov, 1, _iov, 1, 
0);
-  if (bytesRead == sizeof 

[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-08 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google edited 
https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-08 Thread Jordan R AW via cfe-commits


@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);

ajordanr-google wrote:

This is interesting, thanks.

I definitely could, though I'm mildly hesitant for two reasons. The first is 
because of the [comment from 
address_is_readable.cc](https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/HEAD/absl/debugging/internal/address_is_readable.cc#74)

```c++
// This strategy depends on Linux implementation details,
// so we rely on the test to alert us if it stops working.
```

The other is whether the check will span the full set of instructions we want 
to read. The Abseil implimentation checks 8 bytes, which I think should just 
about fit everything we need if it weren't for that 8 byte alignment:

```c++
// Align address on 8-byte boundary. On aarch64, checking last
// byte before inaccessible page returned unexpected EFAULT.
const uintptr_t u_addr = reinterpret_cast(addr) & ~uintptr_t{7};
```

I'm not familiar with the alignment requirements for a (potentially broken) PC. 
You'd have more context than I do as to whether we'd need to check for both 
instructions with `rt_sigprocmask`?

I notice in the comments that pipe was a discarded method, but it doesn't 
really explain why. Performance reasons perhaps?

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-08 Thread Jordan R AW via cfe-commits


@@ -2822,13 +2825,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_s390x &) {
   // onto the stack.
   const pint_t pc = static_cast(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
+  // directly accessing it could cause a segfault. Use pipe/write/read to
   // read the memory safely instead.
   uint16_t inst;

ajordanr-google wrote:

Should be removed, since we redefined this lower down on line 2834.

https://github.com/llvm/llvm-project/pull/74791
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[libunwind] [libunwind] Replace process_vm_readv with pipe (PR #74791)

2023-12-07 Thread Jordan R AW via cfe-commits

https://github.com/ajordanr-google created 
https://github.com/llvm/llvm-project/pull/74791

process_vm_readv is generally considered dangerous from a syscall perspective, 
and is frequently blanket banned in seccomp filters such as those in Chromium 
and ChromiumOS. We can get the same behaviour during the invalid PC address 
case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the output of 
check-unwind on an ARM64 device under strace. Previously, bad_unwind_info in 
particular would use process_vm_readv, but with this commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```

>From 1f4df1b82970c95684eed93c8f6bcaa6d6507b88 Mon Sep 17 00:00:00 2001
From: Jordan R Abrahams-Whitehead 
Date: Fri, 8 Dec 2023 00:09:59 +
Subject: [PATCH] [libunwind] Replace process_vm_readv with pipe

process_vm_readv is generally considered dangerous from a syscall
perspective, and is frequently blanket banned in seccomp filters such as
those in Chromium and ChromiumOS. We can get the same behaviour during
the invalid PC address case with pipes and write/read.

Testing to ensure that process_vm_readv does not appear, I ran the
output of check-unwind on an ARM64 device under strace. Previously,
bad_unwind_info in particular would use process_vm_readv, but with this
commit, it now uses pipe2:

```
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep process_vm_readv
strace test/Output/bad_unwind_info.pass.cpp.dir/t.tmp.exe \
  |& grep pipe2
```
---
 libunwind/src/UnwindCursor.hpp | 50 --
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 647a5a9c9d92d..5e4e376220daa 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -33,6 +33,7 @@
 #if defined(_LIBUNWIND_TARGET_LINUX) &&
\
 (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || 
\
  defined(_LIBUNWIND_TARGET_S390X))
+#include 
 #include 
 #include 
 #include 
@@ -2700,19 +2701,18 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) {
   // [1] 
https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast(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.
+  // directly accessing it could cause a segfault. Use pipe/write/read to read
+  // the memory safely instead.
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+  if (bytesRead != bufferSize || instructions[0] != 0xd2801168 ||
   instructions[1] != 0xd401)
 return false;
 
@@ -2762,17 +2762,20 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) {
 template 
 bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) {
   const pint_t pc = static_cast(getReg(UNW_REG_IP));
+  int pipefd[2];
+  if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1)
+return false;
   uint32_t instructions[2];
-  struct iovec local_iov = {, sizeof instructions};
-  struct iovec remote_iov = {reinterpret_cast(pc), sizeof 
instructions};
-  long bytesRead =
-  syscall(SYS_process_vm_readv, getpid(), _iov, 1, _iov, 1, 
0);
+  const auto bufferSize = sizeof instructions;
+  if (write(pipefd[1], reinterpret_cast(pc), bufferSize) != bufferSize)
+return false;
+  const auto bytesRead = read(pipefd[0], instructions, bufferSize);
   // Look for the two instructions used in the sigreturn trampoline
   // __vdso_rt_sigreturn:
   //
   // 0x08b00893 li a7,0x8b
   // 0x0073 ecall
-  if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 ||
+  if (bytesRead != bufferSize || instructions[0] != 0x08b00893 ||
   instructions[1] != 0x0073)