summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2022-06-30 16:01:05 +0200
committerEugene Syromyatnikov <evgsyr@gmail.com>2022-07-04 19:12:08 +0200
commit676979fa9cc7920e5e4d547814f9c0edb597fa0d (patch)
tree919fcf45c5158fd0d8ed3e29d54c4918634b5ea7
parent227f8d7e391c92cc5409b46ddc816fd9f55131c0 (diff)
downloadstrace-676979fa9cc7920e5e4d547814f9c0edb597fa0d.tar.gz
pathtrace, util: do not print " (deleted)" as part of the path
In order to allow to discern the unlinked paths from the paths that do indeed end with " (deleted)". * src/defs.h (getfdpath_pid): Add deleted parameter. (getfdpath): Pass NULL as deleted parameter to getfdpath_pid. * src/largefile_wrappers.h (lstat_file): New macro. * src/pathtrace.c: Include <sys/stat.h>, <sys/types.h>, <unistd.h>, and "largefile_wrappers.h". (getfdpath_pid): Add deleted parameter, check if path ends with " (deleted)", and if it is, try to figure out if it is a part of the path by comparing device/inode numbers of the file procfs link resolves into and the file pointed by the path read; strip " (deleted)"; set deleted (if it is non-NULL) to true if the fd is turned out to be deleted and to false otherwise. * src/util.c (print_quoted_string_in_angle_brackets): Add deleted parameter, print "(deleted)" after the closing angle bracket if it is non-NULL. (printfd_pid): Add deleted local variable, pass it to getfdpath_pid and print_quoted_string_in_angle_brackets calls. * tests/fchmod.c: Add checks for a file with " (deleted)" in the path, update expected output. * NEWS: Mention the change.
-rw-r--r--NEWS5
-rw-r--r--src/defs.h5
-rw-r--r--src/largefile_wrappers.h2
-rw-r--r--src/pathtrace.c48
-rw-r--r--src/util.c10
-rw-r--r--tests/fchmod.c47
6 files changed, 105 insertions, 12 deletions
diff --git a/NEWS b/NEWS
index bd5b6c509..2d4c78e8e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
Noteworthy changes in release ?.?? (????-??-??)
===============================================
+* Changes in behaviour
+ * The "(deleted)" marker for unlinked paths of file descriptors is now printed
+ outside angle brackets; the matching of unlinked paths of file descriptors
+ no longer includes the " (deleted)" part into consideration.
+
* Improvements
* Implemented printing of Unix socket sun_path field's SELinux context.
diff --git a/src/defs.h b/src/defs.h
index 2f9b27fa0..b9c2a1586 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -785,12 +785,13 @@ pathtrace_match(struct tcb *tcp)
return pathtrace_match_set(tcp, &global_path_set);
}
-extern int getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize);
+extern int getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize,
+ bool *deleted);
static inline int
getfdpath(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
{
- return getfdpath_pid(tcp->pid, fd, buf, bufsize);
+ return getfdpath_pid(tcp->pid, fd, buf, bufsize, NULL);
}
extern unsigned long getfdinode(struct tcb *, int);
diff --git a/src/largefile_wrappers.h b/src/largefile_wrappers.h
index 4c2370ca3..5f25527f9 100644
--- a/src/largefile_wrappers.h
+++ b/src/largefile_wrappers.h
@@ -31,6 +31,7 @@
# endif
# define fstat_fd fstat64
# define strace_stat_t struct stat64
+# define lstat_file lstat64
# define stat_file stat64
# define struct_dirent struct dirent64
# define read_dir readdir64
@@ -42,6 +43,7 @@
# define fcntl_fd fcntl
# define fstat_fd fstat
# define strace_stat_t struct stat
+# define lstat_file lstat
# define stat_file stat
# define struct_dirent struct dirent
# define read_dir readdir
diff --git a/src/pathtrace.c b/src/pathtrace.c
index 53e465b1d..5cf53709c 100644
--- a/src/pathtrace.c
+++ b/src/pathtrace.c
@@ -10,7 +10,11 @@
#include "defs.h"
#include <limits.h>
#include <poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "largefile_wrappers.h"
#include "number_set.h"
#include "sen.h"
#include "xstring.h"
@@ -77,7 +81,7 @@ storepath(const char *path, struct path_set *set)
* Get path associated with fd of a process with pid.
*/
int
-getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize)
+getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize, bool *deleted)
{
char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
ssize_t n;
@@ -91,12 +95,50 @@ getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize)
xsprintf(linkpath, "/proc/%u/fd/%u", proc_pid, fd);
n = readlink(linkpath, buf, bufsize - 1);
+ if (n < 0)
+ goto end;
+
/*
* NB: if buf is too small, readlink doesn't fail,
* it returns truncated result (IOW: n == bufsize - 1).
*/
- if (n >= 0)
- buf[n] = '\0';
+ buf[n] = '\0';
+ if (deleted)
+ *deleted = false;
+
+ /*
+ * Try to figure out if the kernel has appended " (deleted)"
+ * to the end of a potentially unlinked path and set deleted
+ * if it is the case.
+ */
+ static const char del_sfx[] = " (deleted)";
+ if ((size_t) n <= sizeof(del_sfx))
+ goto end;
+
+ char *del = buf + n + 1 - sizeof(del_sfx);
+
+ if (memcmp(del, del_sfx, sizeof(del_sfx)))
+ goto end;
+
+ strace_stat_t st_link;
+ strace_stat_t st_path;
+ int rc = stat_file(linkpath, &st_link);
+
+ if (rc)
+ goto end;
+
+ rc = lstat_file(buf, &st_path);
+
+ if (rc ||
+ (st_link.st_ino != st_path.st_ino) ||
+ (st_link.st_dev != st_path.st_dev)) {
+ *del = '\0';
+ n = del - buf + 1;
+ if (deleted)
+ *deleted = true;
+ }
+
+end:
return n;
}
diff --git a/src/util.c b/src/util.c
index cd1614da0..c4c4bc0ef 100644
--- a/src/util.c
+++ b/src/util.c
@@ -735,12 +735,15 @@ printpidfd(pid_t pid_of_fd, int fd, const char *path)
}
static void
-print_quoted_string_in_angle_brackets(const char *str)
+print_quoted_string_in_angle_brackets(const char *str, const bool deleted)
{
tprints("<");
print_quoted_string_ex(str, strlen(str),
QUOTE_OMIT_LEADING_TRAILING_QUOTES, "<>");
tprints(">");
+
+ if (deleted)
+ tprints("(deleted)");
}
void
@@ -749,8 +752,9 @@ printfd_pid(struct tcb *tcp, pid_t pid, int fd)
PRINT_VAL_D(fd);
char path[PATH_MAX + 1];
+ bool deleted;
if (pid > 0 && !number_set_array_is_empty(decode_fd_set, 0)
- && getfdpath_pid(pid, fd, path, sizeof(path)) >= 0) {
+ && getfdpath_pid(pid, fd, path, sizeof(path), &deleted) >= 0) {
if (is_number_in_set(DECODE_FD_SOCKET, decode_fd_set) &&
printsocket(tcp, fd, path))
goto printed;
@@ -761,7 +765,7 @@ printfd_pid(struct tcb *tcp, pid_t pid, int fd)
printpidfd(pid, fd, path))
goto printed;
if (is_number_in_set(DECODE_FD_PATH, decode_fd_set))
- print_quoted_string_in_angle_brackets(path);
+ print_quoted_string_in_angle_brackets(path, deleted);
printed: ;
}
diff --git a/tests/fchmod.c b/tests/fchmod.c
index 0b0570cfe..797ee95a7 100644
--- a/tests/fchmod.c
+++ b/tests/fchmod.c
@@ -35,10 +35,17 @@ main(void)
(void) unlink(sample);
int fd = open(sample, O_CREAT|O_RDONLY, 0400);
if (fd == -1)
- perror_msg_and_fail("open");
+ perror_msg_and_fail("open(\"%s\")", sample);
+
+ static const char sample_del[] = "fchmod_sample_file (deleted)";
+ (void) unlink(sample_del);
+ int fd_del = open(sample_del, O_CREAT|O_RDONLY, 0400);
+ if (fd_del == -1)
+ perror_msg_and_fail("open(\"%s\")", sample);
# ifdef YFLAG
char *sample_realpath = get_fd_path(fd);
+ char *sample_del_realpath = get_fd_path(fd_del);
# endif
const char *sample_secontext = SECONTEXT_FILE(sample);
@@ -56,12 +63,27 @@ main(void)
sample_secontext,
sprintrc(rc));
+ const char *sample_del_secontext = SECONTEXT_FILE(sample_del);
+ rc = syscall(__NR_fchmod, fd_del, 0600);
+# ifdef YFLAG
+ printf("%s%s(%d<%s>%s, 0600) = %s\n",
+# else
+ printf("%s%s(%d%s, 0600) = %s\n",
+# endif
+ my_secontext, "fchmod",
+ fd_del,
+# ifdef YFLAG
+ sample_del_realpath,
+# endif
+ sample_del_secontext,
+ sprintrc(rc));
+
if (unlink(sample))
- perror_msg_and_fail("unlink");
+ perror_msg_and_fail("unlink(\"%s\")", sample);
rc = syscall(__NR_fchmod, fd, 051);
# ifdef YFLAG
- printf("%s%s(%d<%s (deleted)>%s, 051) = %s\n",
+ printf("%s%s(%d<%s>(deleted)%s, 051) = %s\n",
# else
printf("%s%s(%d%s, 051) = %s\n",
# endif
@@ -73,9 +95,26 @@ main(void)
sample_secontext,
sprintrc(rc));
+ if (unlink(sample_del))
+ perror_msg_and_fail("unlink(\"%s\")", sample_del);
+
+ rc = syscall(__NR_fchmod, fd_del, 051);
+# ifdef YFLAG
+ printf("%s%s(%d<%s>(deleted)%s, 051) = %s\n",
+# else
+ printf("%s%s(%d%s, 051) = %s\n",
+# endif
+ my_secontext, "fchmod",
+ fd_del,
+# ifdef YFLAG
+ sample_del_realpath,
+# endif
+ sample_del_secontext,
+ sprintrc(rc));
+
rc = syscall(__NR_fchmod, fd, 004);
# ifdef YFLAG
- printf("%s%s(%d<%s (deleted)>%s, 004) = %s\n",
+ printf("%s%s(%d<%s>(deleted)%s, 004) = %s\n",
# else
printf("%s%s(%d%s, 004) = %s\n",
# endif