[2/2] Fix gdb.base/attach-deleted-exec.exp with sudo-allow-ptrace.sh

Message ID 20240325134510.24399-2-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 success Testing passed

Commit Message

Tom de Vries March 25, 2024, 1:45 p.m. UTC
  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(-)
  

Patch

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;