* [PATCH 1/2] [gdb] Add contrib/sudo-allow-ptrace.sh
@ 2024-03-25 13:45 Tom de Vries
2024-03-25 13:45 ` [PATCH 2/2] [gdb] Fix gdb.base/attach-deleted-exec.exp with sudo-allow-ptrace.sh Tom de Vries
0 siblings, 1 reply; 2+ messages in thread
From: Tom de Vries @ 2024-03-25 13:45 UTC (permalink / raw)
To: gdb-patches
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
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
base-commit: 61ced226a4fc2e6df7836cd9c0f7e1ad47af2440
--
2.35.3
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH 2/2] [gdb] Fix gdb.base/attach-deleted-exec.exp with sudo-allow-ptrace.sh
2024-03-25 13:45 [PATCH 1/2] [gdb] Add contrib/sudo-allow-ptrace.sh Tom de Vries
@ 2024-03-25 13:45 ` Tom de Vries
0 siblings, 0 replies; 2+ messages in thread
From: Tom de Vries @ 2024-03-25 13:45 UTC (permalink / raw)
To: gdb-patches
When running test-case gdb.base/attach-deleted-exec.exp with script
gdb/contrib/sudo-allow-ptrace.sh, we run into:
...
(gdb) attach 2804069^M
Attaching to process 2804069^M
No executable file now.^M
warning: Could not load vsyscall page because no executable was specified^M
0x0000ffff79cd83c8 in ?? ()^M
(gdb) FAIL: gdb.base/attach-deleted-exec.exp: \
attach to process with deleted executable
...
The script sudo-allow-ptrace.sh was introduced to work around
kernel.yama.ptrace_scope being set to 1 or 2, but this fail also happens for
kernel.yama.ptrace_scope=0.
The root cause for the fail is the failing "access (name, R_OK) == 0" check in
linux_proc_pid_to_exec_file:
...
/* Use /proc/PID/exe if the actual file can't be read, but /proc/PID/exe
can be. */
if (access (buf, R_OK) != 0 && access (name, R_OK) == 0)
strcpy (buf, name);
...
In other words, the system says there's no read permission for /proc/PID/exe.
Confusingly though, reading /proc/PID/exe works fine, so there seems to be a
contradiction here.
This behaviour can be minimally reproduced using:
...
$ cat try.sh
kill -9 $(pidof mysleep) 2> /dev/null
cp /usr/bin/sleep mysleep
md5sum mysleep
./mysleep 10000 &
(
sleep 1
pid=$(pidof mysleep)
echo "PID: $pid"
test -r /proc/$pid/exe
echo $?
md5sum /proc/$pid/exe
kill -9 $(pidof mysleep) 2> /dev/null
)
...
and:
...
$ cat ./try2.sh
sudo \
-E \
capsh \
--caps="cap_setpcap,cap_setuid,cap_setgid+ep cap_sys_ptrace+eip" \
--keep=1 \
--user=$USER \
--addamb="cap_sys_ptrace" \
--shell=./try.sh --
...
which shows:
...
$ ./try2.sh
[sudo] password for root:
6a85b2e53dce34ce2c35129b5b20c50b mysleep
PID: 4536
1
6a85b2e53dce34ce2c35129b5b20c50b /proc/4536/exe
...
where:
- according to test -r, we cannot read /proc/$pid/exe
- but according to md5sum, we can read /proc/$pid/exe
This was filed as a potential kernel PR here (
https://bugzilla.suse.com/show_bug.cgi?id=1221867 ).
As for gdb, fix or workaround this by dropping the "access (name, R_OK) == 0"
check.
While reading about /proc/PID/exe I came across:
- https://bugzilla.suse.com/show_bug.cgi?id=1216352
- https://bugzilla.kernel.org/show_bug.cgi?id=211593
which advise avoiding using readlink on /proc/PID/exec before reading.
I've looked briefly into fixing this, but found that it's not trivial, so
for now I've added a FIXME comment in linux_proc_pid_to_exec_file.
PR gdb/31528
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31528
---
gdb/nat/linux-procfs.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/gdb/nat/linux-procfs.c b/gdb/nat/linux-procfs.c
index b17e3120792..a3a16ed93af 100644
--- a/gdb/nat/linux-procfs.c
+++ b/gdb/nat/linux-procfs.c
@@ -345,6 +345,23 @@ linux_proc_pid_to_exec_file (int pid)
char name[PATH_MAX];
ssize_t len;
+ /* FIXME: calling readlink to determine the file to read symbols from is
+ problematic. Consider the scenario where:
+ - we run an application /foo/bar,
+ - we use gdb to attach to the running application,
+ - gdb calls linux_proc_pid_to_exec_file to the get the filename to read
+ the symbols from,
+ - linux_proc_pid_to_exec_file calls readlink on /proc/PID/exe, and
+ returns /foo/bar,
+ - we remove /foo/bar, and
+ - gdb tries to read the symbols from /foo/bar, and fails.
+ At this point we can still read the symbols from /proc/PID/exe.
+
+ See also:
+ - https://bugzilla.suse.com/show_bug.cgi?id=1216352
+ - https://bugzilla.kernel.org/show_bug.cgi?id=211593
+ */
+
xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
len = readlink (name, buf, PATH_MAX - 1);
if (len <= 0)
@@ -352,9 +369,11 @@ linux_proc_pid_to_exec_file (int pid)
else
buf[len] = '\0';
- /* Use /proc/PID/exe if the actual file can't be read, but /proc/PID/exe
- can be. */
- if (access (buf, R_OK) != 0 && access (name, R_OK) == 0)
+ /* Use /proc/PID/exe if the actual file can't be read. Note that we don't
+ check for "access ("/proc/PID/exe", R_OK) == 0". It possible that this
+ check will fail while we can actually read /proc/PID/exe (
+ https://bugzilla.suse.com/show_bug.cgi?id=1221867 ). */
+ if (access (buf, R_OK) != 0)
strcpy (buf, name);
return buf;
--
2.35.3
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-03-25 13:45 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-25 13:45 [PATCH 1/2] [gdb] Add contrib/sudo-allow-ptrace.sh Tom de Vries
2024-03-25 13:45 ` [PATCH 2/2] [gdb] Fix gdb.base/attach-deleted-exec.exp with sudo-allow-ptrace.sh Tom de Vries
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox