[PATCH v2 4/6] Use finfo structure to arbitrate overwrapped IOCTL command assignments between TTY and SND

Masatake YAMATO yamato at redhat.com
Fri Mar 11 18:02:07 UTC 2022


IOCTL command assignments are overwrapped.
We could observe the overwrapping when running vi under strace
on x86_64 arch:

  ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 ...

If a fd opens /dev/pts/*, strace with this patch can decode
the same ioctl invocation like:

  ioctl(0, TCSETS, {B38400 ...

* src/defs.h (+term_ioctl_decode_command_number): New function
declaration.
* src/ioctl.c (ioctl_decode_command_number): Add a new parameter
for passing finfo that can be used as hint for ioctl command
decoding. Handle the code `T': calling
term_ioctl_decode_command_number().
(SYS_FUNC(ioctl)): Pass finfo as hint to ioctl_decode_command_number().
* src/term.c(term_ioctl_decode_command_number): decode the command in
this earlier stage if the passed fd opens /dev/pts/*.

Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
 src/defs.h  |  4 ++++
 src/ioctl.c |  7 ++++--
 src/term.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/src/defs.h b/src/defs.h
index 8cfc8d767..8811fae8f 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -668,6 +668,10 @@ struct finfo {
 extern
 struct finfo *get_finfo_for_dev(const char *path, struct finfo *finfo);
 
+extern int
+term_ioctl_decode_command_number(int code,
+                struct tcb *tcp, struct finfo *finfo);
+
 /**
  * @return 0 on success, -1 on error.
  */
diff --git a/src/ioctl.c b/src/ioctl.c
index 0f9f0c9a9..a839da817 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -240,7 +240,7 @@ hiddev_decode_number(const unsigned int code)
 }
 
 static int
-ioctl_decode_command_number(struct tcb *tcp)
+ioctl_decode_command_number(struct tcb *tcp, struct finfo *finfo)
 {
 	const unsigned int code = tcp->u_arg[1];
 
@@ -268,6 +268,9 @@ ioctl_decode_command_number(struct tcb *tcp)
 			return 1;
 		}
 		return 0;
+	case 'T':
+		return term_ioctl_decode_command_number(code,
+							tcp, finfo);
 	case 'U':
 		if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) {
 			tprints_arg_begin("UI_GET_SYSNAME");
@@ -445,7 +448,7 @@ SYS_FUNC(ioctl)
 		if (xlat_verbosity == XLAT_STYLE_VERBOSE)
 			tprint_comment_begin();
 		if (xlat_verbosity != XLAT_STYLE_RAW) {
-			ret = ioctl_decode_command_number(tcp);
+			ret = ioctl_decode_command_number(tcp, finfo);
 			if (!(ret & IOCTL_NUMBER_STOP_LOOKUP)) {
 				iop = ioctl_lookup(tcp->u_arg[1]);
 				if (iop) {
diff --git a/src/term.c b/src/term.c
index 73cc7d63c..a0836a3d6 100644
--- a/src/term.c
+++ b/src/term.c
@@ -273,3 +273,67 @@ term_ioctl(struct tcb *const tcp, const unsigned int code,
 
 	return RVAL_IOCTL_DECODED;
 }
+
+/* The command numbers for TCSETSF, TCSETSW, and TCSETS
+ * conflict with that for SND:
+ *
+ *    0x00005404
+ *    { "SNDCTL_TMR_CONTINUE", 0x00005404 },
+ *    { "TCSETSF", 0x00005404 },
+ *    0x00005403
+ *    { "SNDCTL_TMR_STOP", 0x00005403 },
+ *    { "TCSETSW", 0x00005403 },
+ *    0x00005402
+ *    { "SNDCTL_TMR_START", 0x00005402 },
+ *    { "TCSETS", 0x00005402 },
+ *
+ * This function tries to solve the command name with the
+ * device information associated with FD.
+ *
+ * Above overwrapping is observed on x86_64.
+ * On parisc and sparc, TCSETA, TCSETAW, and TCSETAF conflict
+ * with the SNDCTL commands:
+ *
+ *   $ cd linux/arch
+ *   $ grep "'T'" *\/include/uapi/asm/ioctls.h | grep '\<[234]\>'
+ *   parisc/include/uapi/asm/ioctls.h:#define TCSETA		_IOW('T', 2, struct termio)
+ *   parisc/include/uapi/asm/ioctls.h:#define TCSETAW		_IOW('T', 3, struct termio)
+ *   parisc/include/uapi/asm/ioctls.h:#define TCSETAF		_IOW('T', 4, struct termio)
+ *   sparc/include/uapi/asm/ioctls.h:#define TCSETA		_IOW('T', 2, struct termio)
+ *   sparc/include/uapi/asm/ioctls.h:#define TCSETAW		_IOW('T', 3, struct termio)
+ *   sparc/include/uapi/asm/ioctls.h:#define TCSETAF		_IOW('T', 4, struct termio)
+ */
+extern int
+term_ioctl_decode_command_number(int code,
+                struct tcb *tcp, struct finfo *finfo)
+{
+   /* See Documentation/admin-guide/devices.txt of
+    * Linux kernel source tree about the number 3, 4, 5, 136 ~ 143.
+    */
+   if (finfo
+       && finfo->type == finfo_dev_chr
+       && ((136 <= finfo->dev.major && finfo->dev.major <= 143)
+	   || (3 <= finfo->dev.major && finfo->dev.major <= 5))) {
+       switch (code) {
+       case TCSETSF:
+	       tprints("TCSETSF");
+	       return IOCTL_NUMBER_STOP_LOOKUP;
+       case TCSETSW:
+	       tprints("TCSETSW");
+	       return IOCTL_NUMBER_STOP_LOOKUP;
+       case TCSETS:
+	       tprints("TCSETS");
+	       return IOCTL_NUMBER_STOP_LOOKUP;
+       case TCSETA:
+	       tprints("TCSETA");
+	       return IOCTL_NUMBER_STOP_LOOKUP;
+       case TCSETAW:
+	       tprints("TCSETAW");
+	       return IOCTL_NUMBER_STOP_LOOKUP;
+       case TCSETAF:
+	       tprints("TCSETAF");
+	       return IOCTL_NUMBER_STOP_LOOKUP;
+       }
+   }
+   return 0;
+}
-- 
2.35.1



More information about the Strace-devel mailing list