[1/2] Add contrib/sudo-allow-ptrace.sh

Message ID 20240325134510.24399-1-tdevries@suse.de
State New
Headers
Series [1/2] Add contrib/sudo-allow-ptrace.sh |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 fail Testing failed

Commit Message

Tom de Vries March 25, 2024, 1:45 p.m. UTC
  Some linux systems have the setting kernel.yama.ptrace_scope set to 1 or 2.
This limits the ability to attach to processes, for security reasons.
However, this can get in the way of for instance:
- debugging an application, and
- running certain test-cases in the gdb testsuite.

This can be worked around by setting kernel.yama.ptrace_scope to 0, either:
- temporarily (until the next reboot), using:
  - "echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope", or
  - "sudo sysctl -w kernel.yama.ptrace_scope=0",
- or permanently, by editing /etc/sysctl.conf or adding a file to
  /etc/sysctl.d.

However, it may be the case that setting kernel.yama.ptrace_scope to 0 is not
desirable, for instance when trying to debug an application on a production
system.

Another way of working around this is by running as root, but this may be
undesirable as well.

Here ( https://wiki.archlinux.org/title/Capabilities ) it's demonstrated how
to run gdb while temporarily adding the CAP_SYS_PTRACE capability using capsh.

I tried out this approach on the test-suite, and found that while capsh uses
"--user $USER", some things are different from being $USER:
- $HOME is /root, not /home/$USER
- USER and LOGNAME are root
- ulimit -c is 0, even though I set it to unlimited in /home/$USER/.bashrc.

Add a convenience script gdb/contrib/sudo-allow-ptrace.sh that takes care of
these differences.

With the script, I'm able to run the test-suite as usual on a
kernel.yama.ptrace_scope=1/2 system.

There's only one regression compared to kernel.yama.ptrace_scope=0, in
gdb.base/attach-deleted-exec.exp, which is filed as PR gdb/31528.  A following
patch deals with this.

Tested and shell-checked on x86_64-linux.

PR external/31520
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31520
---
 gdb/contrib/sudo-allow-ptrace.sh | 110 +++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100755 gdb/contrib/sudo-allow-ptrace.sh


base-commit: 61ced226a4fc2e6df7836cd9c0f7e1ad47af2440
  

Patch

diff --git a/gdb/contrib/sudo-allow-ptrace.sh b/gdb/contrib/sudo-allow-ptrace.sh
new file mode 100755
index 00000000000..f46ba7cd9ab
--- /dev/null
+++ b/gdb/contrib/sudo-allow-ptrace.sh
@@ -0,0 +1,110 @@ 
+#!/bin/sh
+
+# Copyright (C) 2024 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This script intends to facilitate using gdb to attach to processes
+# on a kernel.yama.ptrace_scope=1 system, without changing the setting and
+# without becoming root.
+#
+# Example usage (running the gdb testsuite):
+#   $ cd build/gdb/testsuite
+#   $ sudo-allow-ptrace.sh make check
+#
+# Example usage (using gdb to attach to process):
+#   $ sudo-allow-ptrace.sh gdb -p <pid>
+#
+# The script is based on this [1] recipe.
+#
+# [1] https://wiki.archlinux.org/title/Capabilities.
+
+set -e
+
+case " $1 " in
+    " --stage2 ")
+	stage=2
+	shift
+	;;
+
+    " --stage3 ")
+	stage=3
+	shift
+	;;
+
+    *)
+	stage=1
+	;;
+esac
+
+if [ $stage = 1 ]; then
+    # STAGE 1, as user $USER.
+
+    # shellcheck disable=SC3045
+    ulimit_core_hard=$(ulimit -Hc)
+    # shellcheck disable=SC3045
+    ulimit_core_soft=$(ulimit -Sc)
+
+    exec \
+	sudo -E \
+	"$0" \
+	--stage2 \
+	"$USER" \
+	"$HOME" \
+	"$ulimit_core_hard" \
+	"$ulimit_core_soft" \
+	"$@"
+elif [ $stage = 2 ]; then
+    # STAGE 2, as user root.
+
+    export user="$1"
+    shift
+
+    export home="$1"
+    shift
+
+    ulimit_core_hard="$1"
+    shift
+
+    ulimit_core_soft="$1"
+    shift
+
+    # shellcheck disable=SC3045
+    ulimit -Hc "$ulimit_core_hard"
+    # shellcheck disable=SC3045
+    ulimit -Sc "$ulimit_core_soft"
+
+    exec \
+	capsh \
+	--caps="cap_setpcap,cap_setuid,cap_setgid+ep cap_sys_ptrace+eip" \
+	--keep=1 \
+	--user="$user" \
+	--addamb="cap_sys_ptrace" \
+	--shell="$0" \
+	-- \
+	--stage3 \
+	"$user" \
+	"$home" \
+	"$@"
+elif [ $stage = 3 ]; then
+    # STAGE 3, as user root with "assumed identity" $USER.
+
+    export USER="$1"
+    export LOGNAME="$1"
+    shift
+
+    export HOME="$1"
+    shift
+
+    exec "$@"
+fi