summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/defs.h5
-rw-r--r--src/ioctl.c6
-rw-r--r--src/term.c39
-rw-r--r--src/xlat/term_cmds_overlapping.in9
-rw-r--r--tests/ioctl_termios.c24
5 files changed, 75 insertions, 8 deletions
diff --git a/src/defs.h b/src/defs.h
index 3a2bdcfae..e74948529 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -674,6 +674,11 @@ struct finfo {
extern struct finfo *
get_finfo_for_dev(const char *path, struct finfo *finfo);
+extern int
+term_ioctl_decode_command_number(struct tcb *tcp,
+ const struct finfo *finfo,
+ unsigned int code);
+
/**
* @return 0 on success, -1 on error.
*/
diff --git a/src/ioctl.c b/src/ioctl.c
index 0d3cbe69f..27e4f4906 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -242,7 +242,7 @@ hiddev_decode_number(const unsigned int code)
}
static int
-ioctl_decode_command_number(struct tcb *tcp)
+ioctl_decode_command_number(struct tcb *tcp, const struct finfo *finfo)
{
const unsigned int code = tcp->u_arg[1];
@@ -270,6 +270,8 @@ ioctl_decode_command_number(struct tcb *tcp)
return 1;
}
return 0;
+ case 'T':
+ return term_ioctl_decode_command_number(tcp, finfo, code);
case 'U':
if (_IOC_DIR(code) == _IOC_READ && _IOC_NR(code) == 0x2c) {
tprints_arg_begin("UI_GET_SYSNAME");
@@ -472,7 +474,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 8b2501307..f392af3fd 100644
--- a/src/term.c
+++ b/src/term.c
@@ -40,6 +40,8 @@
# define termio_cc termios_cc
#endif
+#include "xlat/term_cmds_overlapping.h"
+
static void
decode_oflag(uint64_t val)
{
@@ -449,3 +451,40 @@ term_ioctl(struct tcb *const tcp, const unsigned int code,
return RVAL_IOCTL_DECODED;
}
+
+/*
+ * TTY and SND ioctl commands may clash, for example:
+ *
+ * 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 resolve the collision using the device information
+ * associated with the specified file descriptor.
+ */
+int
+term_ioctl_decode_command_number(struct tcb *tcp,
+ const struct finfo *finfo,
+ unsigned int code)
+{
+ /*
+ * See Linux kernel Documentation/admin-guide/devices.txt
+ */
+ if (finfo
+ && finfo->type == FINFO_DEV_CHR
+ && ((3 <= finfo->dev.major && finfo->dev.major <= 5) ||
+ (136 <= finfo->dev.major && finfo->dev.major <= 143))) {
+ const char *str = xlookup(term_cmds_overlapping, code);
+ if (str) {
+ tprints_string(str);
+ return IOCTL_NUMBER_STOP_LOOKUP;
+ }
+ }
+ return 0;
+}
diff --git a/src/xlat/term_cmds_overlapping.in b/src/xlat/term_cmds_overlapping.in
new file mode 100644
index 000000000..6b0e00338
--- /dev/null
+++ b/src/xlat/term_cmds_overlapping.in
@@ -0,0 +1,9 @@
+/* 0x5401 .. 0x5408 */
+TCGETS
+TCSETS
+TCSETSW
+TCSETSF
+TCGETA
+TCSETA
+TCSETAW
+TCSETAF
diff --git a/tests/ioctl_termios.c b/tests/ioctl_termios.c
index 9b0c94274..eaea4e96b 100644
--- a/tests/ioctl_termios.c
+++ b/tests/ioctl_termios.c
@@ -860,7 +860,8 @@ main(void)
const char *cmd_str;
bool write;
bool can_fail;
- } cmds[6];
+ bool pass_invalid_fd;
+ } cmds[9];
struct {
kernel_ulong_t data;
const char *data_str;
@@ -889,22 +890,33 @@ main(void)
#endif
{
{
- /* XXX */
+ /*
+ * If the fd is valid and points to a tty,
+ * the potential ioctl command collision is resolved.
+ */
+ { ARG_STR(TCSETS), true },
+ { ARG_STR(TCSETSW), true },
+ { ARG_STR(TCSETSF), true },
+
+ /*
+ * If the fd is invalid, it is impossible
+ * to distinguish the overlapping ioctl commands.
+ */
{ TCSETS,
#if IOCTL_CLASHED
"SNDCTL_TMR_START or "
#endif
- "TCSETS", true },
+ "TCSETS", true, true, true },
{ TCSETSW,
#if IOCTL_CLASHED
"SNDCTL_TMR_STOP or "
#endif
- "TCSETSW", true },
+ "TCSETSW", true, true, true },
{ TCSETSF,
#if IOCTL_CLASHED
"SNDCTL_TMR_CONTINUE or "
#endif
- "TCSETSF", true },
+ "TCSETSF", true, true, true },
{ ARG_STR(TCGETS), false },
{ ARG_STR(TIOCSLCKTRMIOS), true, true },
@@ -963,7 +975,7 @@ main(void)
do_ioctl(checks[i].cmds[j].cmd,
checks[i].cmds[j].cmd_str,
- ret,
+ checks[i].cmds[j].pass_invalid_fd? -1: ret,
checks[i].printer,
checks[i].args[k].data,
checks[i].args[k].valid,