gdb: implement linux namespace support for fileio_lstat and vFile::lstat

The new algorithm to look for a build-id-based debug file
(introduced by commit 22836ca885)
makes use of fileio_lstat. As lstat was not supported by
linux-namespace.c, all lstat calls would be performed on the host
and not inside the namespace.  Fixed by adding namespace lstat
support.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32956

Approved-By: Andrew Burgess <aburgess@redhat.com>
This commit is contained in:
Fabian Kilger
2025-06-11 22:52:16 +02:00
committed by Andrew Burgess
parent c29a37f741
commit bd389c9515
9 changed files with 119 additions and 2 deletions

View File

@@ -4585,6 +4585,20 @@ linux_nat_target::fileio_open (struct inferior *inf, const char *filename,
return fd;
}
/* Implementation of to_fileio_lstat. */
int
linux_nat_target::fileio_lstat (struct inferior *inf, const char *filename,
struct stat *sb, fileio_error *target_errno)
{
int r = linux_mntns_lstat (linux_nat_fileio_pid_of (inf), filename, sb);
if (r == -1)
*target_errno = host_to_fileio_error (errno);
return r;
}
/* Implementation of to_fileio_readlink. */
std::optional<std::string>

View File

@@ -108,6 +108,9 @@ public:
const char *filename,
fileio_error *target_errno) override;
int fileio_lstat (struct inferior *inf, const char *filename,
struct stat *sb, fileio_error *target_errno) override;
int fileio_unlink (struct inferior *inf,
const char *filename,
fileio_error *target_errno) override;

View File

@@ -233,6 +233,12 @@ enum mnsh_msg_type
MNSH_RET_INT. */
MNSH_REQ_SETNS,
/* A request that the helper call lstat. The single
argument (the filename) should be passed in BUF, and
should include a terminating NUL character. The helper
should respond with a MNSH_RET_INTSTR. */
MNSH_REQ_LSTAT,
/* A request that the helper call open. Arguments should
be passed in BUF, INT1 and INT2. The filename (in BUF)
should include a terminating NUL character. The helper
@@ -284,6 +290,10 @@ mnsh_debug_print_message (enum mnsh_msg_type type,
res += "ERROR";
break;
case MNSH_REQ_LSTAT:
res += "LSTAT";
break;
case MNSH_REQ_SETNS:
res += "SETNS";
break;
@@ -511,6 +521,20 @@ mnsh_handle_setns (int sock, int fd, int nstype)
return mnsh_return_int (sock, result, errno);
}
/* Handle a MNSH_REQ_LSTAT message. Must be async-signal-safe. */
static ssize_t
mnsh_handle_lstat (int sock, const char *filename)
{
struct stat sb;
int stat_ok = lstat (filename, &sb);
return mnsh_return_intstr (sock, stat_ok, &sb,
stat_ok == -1 ? 0 : sizeof (sb),
errno);
}
/* Handle a MNSH_REQ_OPEN message. Must be async-signal-safe. */
static ssize_t
@@ -571,6 +595,11 @@ mnsh_main (int sock)
response = mnsh_handle_setns (sock, fd, int1);
break;
case MNSH_REQ_LSTAT:
if (size > 0 && buf[size - 1] == '\0')
response = mnsh_handle_lstat (sock, buf);
break;
case MNSH_REQ_OPEN:
if (size > 0 && buf[size - 1] == '\0')
response = mnsh_handle_open (sock, buf, int1, int2);
@@ -761,6 +790,10 @@ mnsh_maybe_mourn_peer (void)
mnsh_send_message (helper->sock, MNSH_REQ_OPEN, -1, flags, mode, \
filename, strlen (filename) + 1)
#define mnsh_send_lstat(helper, filename) \
mnsh_send_message (helper->sock, MNSH_REQ_LSTAT, -1, 0, 0, \
filename, strlen (filename) + 1)
#define mnsh_send_unlink(helper, filename) \
mnsh_send_message (helper->sock, MNSH_REQ_UNLINK, -1, 0, 0, \
filename, strlen (filename) + 1)
@@ -943,6 +976,42 @@ linux_mntns_access_fs (pid_t pid)
/* See nat/linux-namespaces.h. */
int
linux_mntns_lstat (pid_t pid, const char *filename,
struct stat *sb)
{
enum mnsh_fs_code access = linux_mntns_access_fs (pid);
if (access == MNSH_FS_ERROR)
return -1;
if (access == MNSH_FS_DIRECT)
return lstat (filename, sb);
gdb_assert (access == MNSH_FS_HELPER);
struct linux_mnsh *helper = linux_mntns_get_helper ();
ssize_t size = mnsh_send_lstat (helper, filename);
if (size < 0)
return -1;
int stat_ok, error;
size = mnsh_recv_intstr (helper, &stat_ok, &error, sb, sizeof (*sb));
if (size < 0)
{
stat_ok = -1;
errno = error;
}
else
gdb_assert (stat_ok == -1 || size == sizeof (*sb));
return stat_ok;
}
/* See nat/linux-namespaces.h. */
int
linux_mntns_open_cloexec (pid_t pid, const char *filename,
int flags, mode_t mode)

View File

@@ -64,6 +64,11 @@ enum linux_ns_type
extern int linux_ns_same (pid_t pid, enum linux_ns_type type);
/* Like lstat(2), but in the mount namespace of process PID. */
extern int linux_mntns_lstat (pid_t pid, const char *filename,
struct stat *sb);
/* Like gdb_open_cloexec, but in the mount namespace of process
PID. */

View File

@@ -525,7 +525,7 @@ handle_stat (char *own_buf, int *new_packet_len)
static void
handle_lstat (char *own_buf, int *new_packet_len)
{
int bytes_sent;
int ret, bytes_sent;
char *p;
struct stat st;
struct fio_stat fst;
@@ -540,7 +540,12 @@ handle_lstat (char *own_buf, int *new_packet_len)
return;
}
if (lstat (filename, &st) == -1)
if (hostio_fs_pid != 0)
ret = the_target->multifs_lstat (hostio_fs_pid, filename, &st);
else
ret = lstat (filename, &st);
if (ret == -1)
{
hostio_error (own_buf);
return;

View File

@@ -6049,6 +6049,12 @@ linux_process_target::multifs_open (int pid, const char *filename,
return linux_mntns_open_cloexec (pid, filename, flags, mode);
}
int
linux_process_target::multifs_lstat (int pid, const char *filename, struct stat *sb)
{
return linux_mntns_lstat (pid, filename, sb);
}
int
linux_process_target::multifs_unlink (int pid, const char *filename)
{

View File

@@ -304,6 +304,8 @@ public:
int multifs_open (int pid, const char *filename, int flags,
mode_t mode) override;
int multifs_lstat (int pid, const char *filename, struct stat *st) override;
int multifs_unlink (int pid, const char *filename) override;
ssize_t multifs_readlink (int pid, const char *filename, char *buf,

View File

@@ -772,6 +772,13 @@ process_stratum_target::multifs_open (int pid, const char *filename,
return open (filename, flags, mode);
}
int
process_stratum_target::multifs_lstat (int pid, const char *filename,
struct stat *sb)
{
return lstat (filename, sb);
}
int
process_stratum_target::multifs_unlink (int pid, const char *filename)
{

View File

@@ -441,6 +441,12 @@ public:
virtual int multifs_open (int pid, const char *filename,
int flags, mode_t mode);
/* Multiple-filesystem-aware lstat. Like lstat(2), but operating in
the filesystem as it appears to process PID. Systems where all
processes share a common filesystem should not override this.
The default behavior is to use lstat(2). */
virtual int multifs_lstat (int pid, const char *filename, struct stat *sb);
/* Multiple-filesystem-aware unlink. Like unlink(2), but operates
in the filesystem as it appears to process PID. Systems where
all processes share a common filesystem should not override this.