[PATCH 2/6] Extend printfd() to collect extra information about fd

Masatake YAMATO yamato at redhat.com
Thu Mar 10 12:01:02 UTC 2022


The collected information can be used to improve decoding
arguments of system calls like ioctl.

* src/defs.h (fd_info): New structure definition for storing
extra information associated with a file descriptor.
(printfd_pid_filling_info): New function declaration extending
printfd_pid() to collect extra information about the fd when
printing it.
(printfd_pid): Inline it with using printfd_pid_filling_info().
(printfd_filling_info): New function based on
printfd_pid_filling_info().
(printfd): Use printfd_filling_info() instead of printfd_pid().
* src/ioctl.c (SYS_FUNC(ioctl)): Call printfd_filling_info()
instead of printfd() to collect extra information about the fd.
* src/util.c (printdev): Add an extra parameter `fd_info'. The
function stores extra information about the fd to the buffer
pointed by the parameter.
(printfd_pid_filling_info): New function doing what printfd_pid()
did and/or collecting the extra information about the fd.

Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
 src/defs.h  | 21 +++++++++++++++++++--
 src/ioctl.c |  4 +++-
 src/util.c  | 39 ++++++++++++++++++++++++++++++++++-----
 3 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/src/defs.h b/src/defs.h
index d3d769be6..04c985268 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -653,6 +653,11 @@ static inline int set_tcb_priv_ulong(struct tcb *tcp, unsigned long val)
 	return set_tcb_priv_data(tcp, (void *) val, 0);
 }
 
+struct fd_info {
+	enum { fd_info_unset, fd_info_dev_chr, fd_info_dev_blk } type;
+	unsigned int major, minor;
+};
+
 /**
  * @return 0 on success, -1 on error.
  */
@@ -1190,12 +1195,24 @@ extern pid_t pidfd_get_pid(pid_t pid_of_fd, int fd);
  * Print file descriptor fd owned by process with ID pid (from the PID NS
  * of the tracer).
  */
-extern void printfd_pid(struct tcb *tcp, pid_t pid, int fd);
+extern void printfd_pid_filling_info(struct tcb *tcp, pid_t pid, int fd,
+				     struct fd_info **fd_info);
+
+static inline void printfd_pid(struct tcb *tcp, pid_t pid, int fd)
+{
+	printfd_pid_filling_info(tcp, pid, fd, NULL);
+}
+
+static inline void
+printfd_filling_info(struct tcb *tcp, int fd, struct fd_info **fd_info)
+{
+	printfd_pid_filling_info(tcp, tcp->pid, fd, fd_info);
+}
 
 static inline void
 printfd(struct tcb *tcp, int fd)
 {
-	printfd_pid(tcp, tcp->pid, fd);
+	printfd_filling_info(tcp, fd, NULL);
 }
 
 /**
diff --git a/src/ioctl.c b/src/ioctl.c
index 8173bdc6b..b6dcfff99 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -432,7 +432,9 @@ SYS_FUNC(ioctl)
 	int ret;
 
 	if (entering(tcp)) {
-		printfd(tcp, tcp->u_arg[0]);
+		struct fd_info *fd_info = NULL;
+
+		printfd_filling_info(tcp, tcp->u_arg[0], &fd_info);
 		tprint_arg_next();
 
 		if (xlat_verbosity != XLAT_STYLE_ABBREV)
diff --git a/src/util.c b/src/util.c
index d0de13ada..8ef65b815 100644
--- a/src/util.c
+++ b/src/util.c
@@ -632,7 +632,7 @@ printsocket(struct tcb *tcp, int fd, const char *path)
 }
 
 static bool
-printdev(struct tcb *tcp, int fd, const char *path)
+printdev(struct tcb *tcp, int fd, const char *path, struct fd_info **fd_info)
 {
 	strace_stat_t st;
 
@@ -654,6 +654,15 @@ printdev(struct tcb *tcp, int fd, const char *path)
 		tprintf("<%s %u:%u>>",
 			S_ISBLK(st.st_mode)? "block" : "char",
 			major(st.st_rdev), minor(st.st_rdev));
+
+		if (fd_info) {
+			struct fd_info *info = xmalloc(sizeof(*info));
+			info->type = S_ISBLK(st.st_mode)? fd_info_dev_blk: fd_info_dev_chr;
+			info->major = major(st.st_rdev);
+			info->minor = minor(st.st_rdev);
+			*fd_info = info;
+		}
+
 		return true;
 	}
 
@@ -726,18 +735,36 @@ print_quoted_string_in_angle_brackets(const char *str)
 }
 
 void
-printfd_pid(struct tcb *tcp, pid_t pid, int fd)
+printfd_pid_filling_info(struct tcb *tcp, pid_t pid, int fd, struct fd_info **fd_info)
 {
 	PRINT_VAL_D(fd);
 
+	bool should_print = false;
 	char path[PATH_MAX + 1];
-	if (pid > 0 && !number_set_array_is_empty(decode_fd_set, 0)
+	if (pid > 0
+	    && ((should_print = !number_set_array_is_empty(decode_fd_set, 0)) || fd_info)
 	    && getfdpath_pid(pid, fd, path, sizeof(path)) >= 0) {
+		/*
+		 * If FD_INFO is given, FT_INFO must be filled.
+		 *
+		 * <A> If the information of fd will be printed (SHOULD_PRINT),
+		 *     a helper function, printdev(), for printing also fills
+		 *     FD_INFO as side effect.
+		 * <B> If the information of fd will not be printed (!SHOULD_PRINT),
+		 *     we must force to call the helper function for
+		 *     filling FD_INFO. However, nothing should be
+		 *     printed. Calling disable_tprint/enable_tprint
+		 *     is for disabling the output stream.
+		 */
+		void *tprint_state = NULL;
+		if (!should_print)
+			tprint_state = disable_tprint();
+
 		if (is_number_in_set(DECODE_FD_SOCKET, decode_fd_set) &&
 		    printsocket(tcp, fd, path))
 			goto printed;
-		if (is_number_in_set(DECODE_FD_DEV, decode_fd_set) &&
-		    printdev(tcp, fd, path))
+		if ((fd_info || is_number_in_set(DECODE_FD_DEV, decode_fd_set)) &&
+		    printdev(tcp, fd, path, fd_info))
 			goto printed;
 		if (is_number_in_set(DECODE_FD_PIDFD, decode_fd_set) &&
 		    printpidfd(pid, fd, path))
@@ -745,6 +772,8 @@ printfd_pid(struct tcb *tcp, pid_t pid, int fd)
 		if (is_number_in_set(DECODE_FD_PATH, decode_fd_set))
 			print_quoted_string_in_angle_brackets(path);
 printed:	;
+		if (!should_print)
+			enable_tprint(tprint_state);
 	}
 
 	selinux_printfdcon(pid, fd);
-- 
2.35.1



More information about the Strace-devel mailing list