diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-24 15:43:41 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-24 15:43:41 +0200 |
commit | 44adbac8f7217040be97928cd19998259d9d4418 (patch) | |
tree | c1c6ac9aa4d47801dc9133d6d641286631a8f4b4 /drivers/tty | |
parent | Merge tag 'pstore-v4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git... (diff) | |
parent | kill TIOCSERGSTRUCT (diff) | |
download | linux-44adbac8f7217040be97928cd19998259d9d4418.tar.xz linux-44adbac8f7217040be97928cd19998259d9d4418.zip |
Merge branch 'work.tty-ioctl' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull tty ioctl updates from Al Viro:
"This is the compat_ioctl work related to tty ioctls.
Quite a bit of dead code taken out, all tty-related stuff gone from
fs/compat_ioctl.c. A bunch of compat bugs fixed - some still remain,
but all more or less generic tty-related ioctls should be covered
(remaining issues are in things like driver-private ioctls in a pcmcia
serial card driver not getting properly handled in 32bit processes on
64bit host, etc)"
* 'work.tty-ioctl' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (53 commits)
kill TIOCSERGSTRUCT
change semantics of ldisc ->compat_ioctl()
kill TIOCSER[SG]WILD
synclink_gt(): fix compat_ioctl()
pty: fix compat ioctls
compat_ioctl - kill keyboard ioctl handling
gigaset: add ->compat_ioctl()
vt_compat_ioctl(): clean up, use compat_ptr() properly
gigaset: don't try to printk userland buffer contents
dgnc: don't bother with (empty) stub for TCXONC
dgnc: leave TIOC[GS]SOFTCAR to ldisc
remove fallback to drivers for TIOCGICOUNT
dgnc: break-related ioctls won't reach ->ioctl()
kill the rest of tty COMPAT_IOCTL() entries
dgnc: TIOCM... won't reach ->ioctl()
isdn_tty: TCSBRK{,P} won't reach ->ioctl()
kill capinc_tty_ioctl()
take compat TIOC[SG]SERIAL treatment into tty_compat_ioctl()
synclink: reduce pointless checks in ->ioctl()
complete ->[sg]et_serial() switchover
...
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/amiserial.c | 90 | ||||
-rw-r--r-- | drivers/tty/cyclades.c | 77 | ||||
-rw-r--r-- | drivers/tty/ipwireless/tty.c | 36 | ||||
-rw-r--r-- | drivers/tty/isicom.c | 72 | ||||
-rw-r--r-- | drivers/tty/moxa.c | 79 | ||||
-rw-r--r-- | drivers/tty/mxser.c | 97 | ||||
-rw-r--r-- | drivers/tty/n_gsm.c | 11 | ||||
-rw-r--r-- | drivers/tty/n_r3964.c | 22 | ||||
-rw-r--r-- | drivers/tty/pty.c | 14 | ||||
-rw-r--r-- | drivers/tty/serial/serial_core.c | 43 | ||||
-rw-r--r-- | drivers/tty/synclink.c | 3 | ||||
-rw-r--r-- | drivers/tty/synclink_gt.c | 19 | ||||
-rw-r--r-- | drivers/tty/synclinkmp.c | 3 | ||||
-rw-r--r-- | drivers/tty/tty_io.c | 229 | ||||
-rw-r--r-- | drivers/tty/tty_ioctl.c | 16 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 31 |
16 files changed, 452 insertions, 390 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 34dead614149..8330fd809a05 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -996,63 +996,55 @@ static void rs_unthrottle(struct tty_struct * tty) * ------------------------------------------------------------ */ -static int get_serial_info(struct tty_struct *tty, struct serial_state *state, - struct serial_struct __user * retinfo) +static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); + struct serial_state *state = tty->driver_data; + tty_lock(tty); - tmp.line = tty->index; - tmp.port = state->port; - tmp.flags = state->tport.flags; - tmp.xmit_fifo_size = state->xmit_fifo_size; - tmp.baud_base = state->baud_base; - tmp.close_delay = state->tport.close_delay; - tmp.closing_wait = state->tport.closing_wait; - tmp.custom_divisor = state->custom_divisor; + ss->line = tty->index; + ss->port = state->port; + ss->flags = state->tport.flags; + ss->xmit_fifo_size = state->xmit_fifo_size; + ss->baud_base = state->baud_base; + ss->close_delay = state->tport.close_delay; + ss->closing_wait = state->tport.closing_wait; + ss->custom_divisor = state->custom_divisor; tty_unlock(tty); - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - return -EFAULT; return 0; } -static int set_serial_info(struct tty_struct *tty, struct serial_state *state, - struct serial_struct __user * new_info) +static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { + struct serial_state *state = tty->driver_data; struct tty_port *port = &state->tport; - struct serial_struct new_serial; bool change_spd; int retval = 0; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - tty_lock(tty); - change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || - new_serial.custom_divisor != state->custom_divisor; - if (new_serial.irq || new_serial.port != state->port || - new_serial.xmit_fifo_size != state->xmit_fifo_size) { + change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) || + ss->custom_divisor != state->custom_divisor; + if (ss->irq || ss->port != state->port || + ss->xmit_fifo_size != state->xmit_fifo_size) { tty_unlock(tty); return -EINVAL; } if (!serial_isroot()) { - if ((new_serial.baud_base != state->baud_base) || - (new_serial.close_delay != port->close_delay) || - (new_serial.xmit_fifo_size != state->xmit_fifo_size) || - ((new_serial.flags & ~ASYNC_USR_MASK) != + if ((ss->baud_base != state->baud_base) || + (ss->close_delay != port->close_delay) || + (ss->xmit_fifo_size != state->xmit_fifo_size) || + ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { tty_unlock(tty); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - state->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_USR_MASK)); + state->custom_divisor = ss->custom_divisor; goto check_and_exit; } - if (new_serial.baud_base < 9600) { + if (ss->baud_base < 9600) { tty_unlock(tty); return -EINVAL; } @@ -1062,19 +1054,19 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, * At this point, we start making changes..... */ - state->baud_base = new_serial.baud_base; + state->baud_base = ss->baud_base; port->flags = ((port->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - state->custom_divisor = new_serial.custom_divisor; - port->close_delay = new_serial.close_delay * HZ/100; - port->closing_wait = new_serial.closing_wait * HZ/100; + (ss->flags & ASYNC_FLAGS)); + state->custom_divisor = ss->custom_divisor; + port->close_delay = ss->close_delay * HZ/100; + port->closing_wait = ss->closing_wait * HZ/100; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (tty_port_initialized(port)) { if (change_spd) { /* warn about deprecation unless clearing */ - if (new_serial.flags & ASYNC_SPD_MASK) + if (ss->flags & ASYNC_SPD_MASK) dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); change_speed(tty, state, NULL); } @@ -1084,7 +1076,6 @@ check_and_exit: return retval; } - /* * get_lsr_info - get line status register info * @@ -1224,30 +1215,19 @@ static int rs_ioctl(struct tty_struct *tty, if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + if ((cmd != TIOCSERCONFIG) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty_io_error(tty)) return -EIO; } switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(tty, info, argp); - case TIOCSSERIAL: - return set_serial_info(tty, info, argp); case TIOCSERCONFIG: return 0; case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, argp); - case TIOCSERGSTRUCT: - if (copy_to_user(argp, - info, sizeof(struct serial_state))) - return -EFAULT; - return 0; - /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -1288,12 +1268,6 @@ static int rs_ioctl(struct tty_struct *tty, finish_wait(&info->tport.delta_msr_wait, &wait); return ret; - case TIOCSERGWILD: - case TIOCSERSWILD: - /* "setserial -W" is called in Debian boot */ - printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); - return 0; - default: return -ENOIOCTLCMD; } @@ -1607,6 +1581,8 @@ static const struct tty_operations serial_ops = { .tiocmget = rs_tiocmget, .tiocmset = rs_tiocmset, .get_icount = rs_get_icount, + .set_serial = set_serial_info, + .get_serial = get_serial_info, .proc_show = rs_proc_show, }; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 6d3c58051ce3..4562c8060d09 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2257,44 +2257,45 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) } } /* set_line_char */ -static int cy_get_serial_info(struct cyclades_port *info, - struct serial_struct __user *retinfo) +static int cy_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { + struct cyclades_port *info = tty->driver_data; struct cyclades_card *cinfo = info->card; - struct serial_struct tmp = { - .type = info->type, - .line = info->line, - .port = (info->card - cy_card) * 0x100 + info->line - - cinfo->first_line, - .irq = cinfo->irq, - .flags = info->port.flags, - .close_delay = info->port.close_delay, - .closing_wait = info->port.closing_wait, - .baud_base = info->baud, - .custom_divisor = info->custom_divisor, - }; - return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; + + if (serial_paranoia_check(info, tty->name, "cy_ioctl")) + return -ENODEV; + ss->type = info->type; + ss->line = info->line; + ss->port = (info->card - cy_card) * 0x100 + info->line - + cinfo->first_line; + ss->irq = cinfo->irq; + ss->flags = info->port.flags; + ss->close_delay = info->port.close_delay; + ss->closing_wait = info->port.closing_wait; + ss->baud_base = info->baud; + ss->custom_divisor = info->custom_divisor; + return 0; } -static int -cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, - struct serial_struct __user *new_info) +static int cy_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct cyclades_port *info = tty->driver_data; int old_flags; int ret; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + if (serial_paranoia_check(info, tty->name, "cy_ioctl")) + return -ENODEV; mutex_lock(&info->port.mutex); old_flags = info->port.flags; if (!capable(CAP_SYS_ADMIN)) { - if (new_serial.close_delay != info->port.close_delay || - new_serial.baud_base != info->baud || - (new_serial.flags & ASYNC_FLAGS & + if (ss->close_delay != info->port.close_delay || + ss->baud_base != info->baud || + (ss->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) { @@ -2302,9 +2303,9 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, return -EPERM; } info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK); - info->baud = new_serial.baud_base; - info->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_USR_MASK); + info->baud = ss->baud_base; + info->custom_divisor = ss->custom_divisor; goto check_and_exit; } @@ -2313,18 +2314,18 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, * At this point, we start making changes..... */ - info->baud = new_serial.baud_base; - info->custom_divisor = new_serial.custom_divisor; + info->baud = ss->baud_base; + info->custom_divisor = ss->custom_divisor; info->port.flags = (info->port.flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS); - info->port.close_delay = new_serial.close_delay * HZ / 100; - info->port.closing_wait = new_serial.closing_wait * HZ / 100; + (ss->flags & ASYNC_FLAGS); + info->port.close_delay = ss->close_delay * HZ / 100; + info->port.closing_wait = ss->closing_wait * HZ / 100; check_and_exit: if (tty_port_initialized(&info->port)) { - if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) { + if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) { /* warn about deprecation unless clearing */ - if (new_serial.flags & ASYNC_SPD_MASK) + if (ss->flags & ASYNC_SPD_MASK) dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); } cy_set_line_char(info, tty); @@ -2698,12 +2699,6 @@ cy_ioctl(struct tty_struct *tty, case CYGETWAIT: ret_val = info->port.closing_wait / (HZ / 100); break; - case TIOCGSERIAL: - ret_val = cy_get_serial_info(info, argp); - break; - case TIOCSSERIAL: - ret_val = cy_set_serial_info(info, tty, argp); - break; case TIOCSERGETLSR: /* Get line status register */ ret_val = get_lsr_info(info, argp); break; @@ -4011,6 +4006,8 @@ static const struct tty_operations cy_ops = { .tiocmget = cy_tiocmget, .tiocmset = cy_tiocmset, .get_icount = cy_get_icount, + .set_serial = cy_set_serial_info, + .get_serial = cy_get_serial_info, .proc_show = cyclades_proc_show, }; diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 1ef751c27ac6..fad3401e604d 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -248,22 +248,29 @@ static int ipw_write_room(struct tty_struct *linux_tty) return room; } -static int ipwireless_get_serial_info(struct ipw_tty *tty, - struct serial_struct __user *retinfo) +static int ipwireless_get_serial_info(struct tty_struct *linux_tty, + struct serial_struct *ss) { - struct serial_struct tmp; + struct ipw_tty *tty = linux_tty->driver_data; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = PORT_UNKNOWN; - tmp.line = tty->index; - tmp.baud_base = 115200; + if (!tty) + return -ENODEV; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + if (!tty->port.count) + return -EINVAL; + ss->type = PORT_UNKNOWN; + ss->line = tty->index; + ss->baud_base = 115200; return 0; } +static int ipwireless_set_serial_info(struct tty_struct *linux_tty, + struct serial_struct *ss) +{ + return 0; /* Keeps the PCMCIA scripts happy. */ +} + static int ipw_chars_in_buffer(struct tty_struct *linux_tty) { struct ipw_tty *tty = linux_tty->driver_data; @@ -386,15 +393,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, return -EINVAL; /* FIXME: Exactly how is the tty object locked here .. */ - - switch (cmd) { - case TIOCGSERIAL: - return ipwireless_get_serial_info(tty, (void __user *) arg); - - case TIOCSSERIAL: - return 0; /* Keeps the PCMCIA scripts happy. */ - } - if (tty->tty_type == TTYTYPE_MODEM) { switch (cmd) { case PPPIOCGCHAN: @@ -561,6 +559,8 @@ static const struct tty_operations tty_ops = { .chars_in_buffer = ipw_chars_in_buffer, .tiocmget = ipw_tiocmget, .tiocmset = ipw_tiocmset, + .set_serial = ipwireless_set_serial_info, + .get_serial = ipwireless_get_serial_info, }; int ipwireless_tty_init(void) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 8d96e86966f1..e04a43e89f6b 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1091,34 +1091,33 @@ static int isicom_tiocmset(struct tty_struct *tty, } static int isicom_set_serial_info(struct tty_struct *tty, - struct serial_struct __user *info) + struct serial_struct *ss) { struct isi_port *port = tty->driver_data; - struct serial_struct newinfo; int reconfig_port; - if (copy_from_user(&newinfo, info, sizeof(newinfo))) - return -EFAULT; + if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) + return -ENODEV; mutex_lock(&port->port.mutex); reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != - (newinfo.flags & ASYNC_SPD_MASK)); + (ss->flags & ASYNC_SPD_MASK)); if (!capable(CAP_SYS_ADMIN)) { - if ((newinfo.close_delay != port->port.close_delay) || - (newinfo.closing_wait != port->port.closing_wait) || - ((newinfo.flags & ~ASYNC_USR_MASK) != + if ((ss->close_delay != port->port.close_delay) || + (ss->closing_wait != port->port.closing_wait) || + ((ss->flags & ~ASYNC_USR_MASK) != (port->port.flags & ~ASYNC_USR_MASK))) { mutex_unlock(&port->port.mutex); return -EPERM; } port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | - (newinfo.flags & ASYNC_USR_MASK)); + (ss->flags & ASYNC_USR_MASK)); } else { - port->port.close_delay = newinfo.close_delay; - port->port.closing_wait = newinfo.closing_wait; + port->port.close_delay = ss->close_delay; + port->port.closing_wait = ss->closing_wait; port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | - (newinfo.flags & ASYNC_FLAGS)); + (ss->flags & ASYNC_FLAGS)); } if (reconfig_port) { unsigned long flags; @@ -1130,46 +1129,24 @@ static int isicom_set_serial_info(struct tty_struct *tty, return 0; } -static int isicom_get_serial_info(struct isi_port *port, - struct serial_struct __user *info) -{ - struct serial_struct out_info; - - mutex_lock(&port->port.mutex); - memset(&out_info, 0, sizeof(out_info)); -/* out_info.type = ? */ - out_info.line = port - isi_ports; - out_info.port = port->card->base; - out_info.irq = port->card->irq; - out_info.flags = port->port.flags; -/* out_info.baud_base = ? */ - out_info.close_delay = port->port.close_delay; - out_info.closing_wait = port->port.closing_wait; - mutex_unlock(&port->port.mutex); - if (copy_to_user(info, &out_info, sizeof(out_info))) - return -EFAULT; - return 0; -} - -static int isicom_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int isicom_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct isi_port *port = tty->driver_data; - void __user *argp = (void __user *)arg; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; - switch (cmd) { - case TIOCGSERIAL: - return isicom_get_serial_info(port, argp); - - case TIOCSSERIAL: - return isicom_set_serial_info(tty, argp); - - default: - return -ENOIOCTLCMD; - } + mutex_lock(&port->port.mutex); +/* ss->type = ? */ + ss->line = port - isi_ports; + ss->port = port->card->base; + ss->irq = port->card->irq; + ss->flags = port->port.flags; +/* ss->baud_base = ? */ + ss->close_delay = port->port.close_delay; + ss->closing_wait = port->port.closing_wait; + mutex_unlock(&port->port.mutex); return 0; } @@ -1273,7 +1250,6 @@ static const struct tty_operations isicom_ops = { .flush_chars = isicom_flush_chars, .write_room = isicom_write_room, .chars_in_buffer = isicom_chars_in_buffer, - .ioctl = isicom_ioctl, .set_termios = isicom_set_termios, .throttle = isicom_throttle, .unthrottle = isicom_unthrottle, @@ -1284,6 +1260,8 @@ static const struct tty_operations isicom_ops = { .tiocmget = isicom_tiocmget, .tiocmset = isicom_tiocmset, .break_ctl = isicom_send_break, + .get_serial = isicom_get_serial_info, + .set_serial = isicom_set_serial_info, }; static const struct tty_port_operations isicom_port_ops = { diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 250a19f042d7..3a1a5e0ee93f 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -221,8 +221,8 @@ static int MoxaPortRxQueue(struct moxa_port *); static int MoxaPortTxFree(struct moxa_port *); static void MoxaPortTxDisable(struct moxa_port *); static void MoxaPortTxEnable(struct moxa_port *); -static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *); -static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *); +static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *); +static int moxa_set_serial_info(struct tty_struct *, struct serial_struct *); static void MoxaSetFifo(struct moxa_port *port, int enable); /* @@ -375,16 +375,6 @@ copy: } break; } - case TIOCGSERIAL: - mutex_lock(&ch->port.mutex); - ret = moxa_get_serial_info(ch, argp); - mutex_unlock(&ch->port.mutex); - break; - case TIOCSSERIAL: - mutex_lock(&ch->port.mutex); - ret = moxa_set_serial_info(ch, argp); - mutex_unlock(&ch->port.mutex); - break; default: ret = -ENOIOCTLCMD; } @@ -415,6 +405,8 @@ static const struct tty_operations moxa_ops = { .break_ctl = moxa_break_ctl, .tiocmget = moxa_tiocmget, .tiocmset = moxa_tiocmset, + .set_serial = moxa_set_serial_info, + .get_serial = moxa_get_serial_info, }; static const struct tty_port_operations moxa_port_ops = { @@ -2034,46 +2026,55 @@ static void MoxaPortTxEnable(struct moxa_port *port) moxafunc(port->tableAddr, FC_SetXonState, Magic_code); } -static int moxa_get_serial_info(struct moxa_port *info, - struct serial_struct __user *retinfo) +static int moxa_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp = { - .type = info->type, - .line = info->port.tty->index, - .flags = info->port.flags, - .baud_base = 921600, - .close_delay = info->port.close_delay - }; - return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; + struct moxa_port *info = tty->driver_data; + + if (tty->index == MAX_PORTS) + return -EINVAL; + if (!info) + return -ENODEV; + mutex_lock(&info->port.mutex); + ss->type = info->type, + ss->line = info->port.tty->index, + ss->flags = info->port.flags, + ss->baud_base = 921600, + ss->close_delay = info->port.close_delay; + mutex_unlock(&info->port.mutex); + return 0; } -static int moxa_set_serial_info(struct moxa_port *info, - struct serial_struct __user *new_info) +static int moxa_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct moxa_port *info = tty->driver_data; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + if (tty->index == MAX_PORTS) + return -EINVAL; + if (!info) + return -ENODEV; - if (new_serial.irq != 0 || new_serial.port != 0 || - new_serial.custom_divisor != 0 || - new_serial.baud_base != 921600) + if (ss->irq != 0 || ss->port != 0 || + ss->custom_divisor != 0 || + ss->baud_base != 921600) return -EPERM; + mutex_lock(&info->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if (((new_serial.flags & ~ASYNC_USR_MASK) != - (info->port.flags & ~ASYNC_USR_MASK))) + if (((ss->flags & ~ASYNC_USR_MASK) != + (info->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&info->port.mutex); return -EPERM; - } else - info->port.close_delay = new_serial.close_delay * HZ / 100; - - new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); - new_serial.flags |= (info->port.flags & ASYNC_FLAGS); + } + } + info->port.close_delay = ss->close_delay * HZ / 100; - MoxaSetFifo(info, new_serial.type == PORT_16550A); + MoxaSetFifo(info, ss->type == PORT_16550A); - info->type = new_serial.type; + info->type = ss->type; + mutex_unlock(&info->port.mutex); return 0; } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8bc15cb67a58..9d00ff5ef961 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1207,76 +1207,90 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) * ------------------------------------------------------------ */ static int mxser_get_serial_info(struct tty_struct *tty, - struct serial_struct __user *retinfo) + struct serial_struct *ss) { struct mxser_port *info = tty->driver_data; - struct serial_struct tmp = { - .type = info->type, - .line = tty->index, - .port = info->ioaddr, - .irq = info->board->irq, - .flags = info->port.flags, - .baud_base = info->baud_base, - .close_delay = info->port.close_delay, - .closing_wait = info->port.closing_wait, - .custom_divisor = info->custom_divisor, - }; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + struct tty_port *port = &info->port; + + if (tty->index == MXSER_PORTS) + return -ENOTTY; + + mutex_lock(&port->mutex); + ss->type = info->type, + ss->line = tty->index, + ss->port = info->ioaddr, + ss->irq = info->board->irq, + ss->flags = info->port.flags, + ss->baud_base = info->baud_base, + ss->close_delay = info->port.close_delay, + ss->closing_wait = info->port.closing_wait, + ss->custom_divisor = info->custom_divisor, + mutex_unlock(&port->mutex); return 0; } static int mxser_set_serial_info(struct tty_struct *tty, - struct serial_struct __user *new_info) + struct serial_struct *ss) { struct mxser_port *info = tty->driver_data; struct tty_port *port = &info->port; - struct serial_struct new_serial; speed_t baud; unsigned long sl_flags; unsigned int flags; int retval = 0; - if (!new_info || !info->ioaddr) + if (tty->index == MXSER_PORTS) + return -ENOTTY; + if (tty_io_error(tty)) + return -EIO; + + mutex_lock(&port->mutex); + if (!info->ioaddr) { + mutex_unlock(&port->mutex); return -ENODEV; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + } - if (new_serial.irq != info->board->irq || - new_serial.port != info->ioaddr) + if (ss->irq != info->board->irq || + ss->port != info->ioaddr) { + mutex_unlock(&port->mutex); return -EINVAL; + } flags = port->flags & ASYNC_SPD_MASK; if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.close_delay != info->port.close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) + if ((ss->baud_base != info->baud_base) || + (ss->close_delay != info->port.close_delay) || + ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&port->mutex); return -EPERM; + } info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); + (ss->flags & ASYNC_USR_MASK)); } else { /* * OK, past this point, all the error checking has been done. * At this point, we start making changes..... */ port->flags = ((port->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - port->close_delay = new_serial.close_delay * HZ / 100; - port->closing_wait = new_serial.closing_wait * HZ / 100; + (ss->flags & ASYNC_FLAGS)); + port->close_delay = ss->close_delay * HZ / 100; + port->closing_wait = ss->closing_wait * HZ / 100; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && - (new_serial.baud_base != info->baud_base || - new_serial.custom_divisor != + (ss->baud_base != info->baud_base || + ss->custom_divisor != info->custom_divisor)) { - if (new_serial.custom_divisor == 0) + if (ss->custom_divisor == 0) { + mutex_unlock(&port->mutex); return -EINVAL; - baud = new_serial.baud_base / new_serial.custom_divisor; + } + baud = ss->baud_base / ss->custom_divisor; tty_encode_baud_rate(tty, baud, baud); } } - info->type = new_serial.type; + info->type = ss->type; process_txrx_fifo(info); @@ -1291,6 +1305,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, if (retval == 0) tty_port_set_initialized(port, 1); } + mutex_unlock(&port->mutex); return retval; } @@ -1660,11 +1675,9 @@ static int mxser_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct mxser_port *info = tty->driver_data; - struct tty_port *port = &info->port; struct async_icount cnow; unsigned long flags; void __user *argp = (void __user *)arg; - int retval; if (tty->index == MXSER_PORTS) return mxser_ioctl_special(cmd, argp); @@ -1708,20 +1721,10 @@ static int mxser_ioctl(struct tty_struct *tty, return 0; } - if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty)) + if (cmd != TIOCMIWAIT && tty_io_error(tty)) return -EIO; switch (cmd) { - case TIOCGSERIAL: - mutex_lock(&port->mutex); - retval = mxser_get_serial_info(tty, argp); - mutex_unlock(&port->mutex); - return retval; - case TIOCSSERIAL: - mutex_lock(&port->mutex); - retval = mxser_set_serial_info(tty, argp); - mutex_unlock(&port->mutex); - return retval; case TIOCSERGETLSR: /* Get line status register */ return mxser_get_lsr_info(info, argp); /* @@ -2325,6 +2328,8 @@ static const struct tty_operations mxser_ops = { .wait_until_sent = mxser_wait_until_sent, .tiocmget = mxser_tiocmget, .tiocmset = mxser_tiocmset, + .set_serial = mxser_set_serial_info, + .get_serial = mxser_get_serial_info, .get_icount = mxser_get_icount, }; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 86b7e20ffd7f..6f7da9a9d76f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2614,14 +2614,6 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, } } -#ifdef CONFIG_COMPAT -static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return gsmld_ioctl(tty, file, cmd, arg); -} -#endif - /* * Network interface * @@ -2833,9 +2825,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = { .flush_buffer = gsmld_flush_buffer, .read = gsmld_read, .write = gsmld_write, -#ifdef CONFIG_COMPAT - .compat_ioctl = gsmld_compat_ioctl, -#endif .ioctl = gsmld_ioctl, .poll = gsmld_poll, .receive_buf = gsmld_receive_buf, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index dbf1ab36758e..749a608c40b0 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -134,6 +134,10 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr); static int r3964_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +#endif static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, struct poll_table_struct *wait); @@ -149,6 +153,9 @@ static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .read = r3964_read, .write = r3964_write, .ioctl = r3964_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = r3964_compat_ioctl, +#endif .set_termios = r3964_set_termios, .poll = r3964_poll, .receive_buf = r3964_receive_buf, @@ -1210,6 +1217,21 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, } } +#ifdef CONFIG_COMPAT +static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case R3964_ENABLE_SIGNALS: + case R3964_SETPRIORITY: + case R3964_USE_BCC: + return r3964_ioctl(tty, file, cmd, arg); + default: + return -ENOIOCTLCMD; + } +} +#endif + static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) { TRACE_L("set_termios"); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 678406e0948b..00099a8439d2 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -28,6 +28,7 @@ #include <linux/mount.h> #include <linux/file.h> #include <linux/ioctl.h> +#include <linux/compat.h> #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP @@ -488,6 +489,7 @@ static int pty_bsd_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +#ifdef CONFIG_COMPAT static long pty_bsd_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -495,8 +497,11 @@ static long pty_bsd_compat_ioctl(struct tty_struct *tty, * PTY ioctls don't require any special translation between 32-bit and * 64-bit userspace, they are already compatible. */ - return pty_bsd_ioctl(tty, cmd, arg); + return pty_bsd_ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); } +#else +#define pty_bsd_compat_ioctl NULL +#endif static int legacy_count = CONFIG_LEGACY_PTY_COUNT; /* @@ -676,6 +681,7 @@ static int pty_unix98_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +#ifdef CONFIG_COMPAT static long pty_unix98_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -683,8 +689,12 @@ static long pty_unix98_compat_ioctl(struct tty_struct *tty, * PTY ioctls don't require any special translation between 32-bit and * 64-bit userspace, they are already compatible. */ - return pty_unix98_ioctl(tty, cmd, arg); + return pty_unix98_ioctl(tty, cmd, + cmd == TIOCSIG ? arg : (unsigned long)compat_ptr(arg)); } +#else +#define pty_unix98_compat_ioctl NULL +#endif /** * ptm_unix98_lookup - find a pty master diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 80bb56facfb6..54726c3f74c6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -778,17 +778,13 @@ out: return ret; } -static int uart_get_info_user(struct tty_port *port, - struct serial_struct __user *retinfo) +static int uart_get_info_user(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - if (uart_get_info(port, &tmp) < 0) - return -EIO; + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; + return uart_get_info(port, ss) < 0 ? -EIO : 0; } static int uart_set_info(struct tty_struct *tty, struct tty_port *port, @@ -990,16 +986,13 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, return retval; } -static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, - struct serial_struct __user *newinfo) +static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct new_serial; + struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; int retval; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - + down_write(&tty->termios_rwsem); /* * This semaphore protects port->count. It is also * very useful to prevent opens. Also, take the @@ -1008,8 +1001,9 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, * under us. */ mutex_lock(&port->mutex); - retval = uart_set_info(tty, port, state, &new_serial); + retval = uart_set_info(tty, port, state, ss); mutex_unlock(&port->mutex); + up_write(&tty->termios_rwsem); return retval; } @@ -1325,26 +1319,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) * These ioctls don't rely on the hardware to be present. */ switch (cmd) { - case TIOCGSERIAL: - ret = uart_get_info_user(port, uarg); - break; - - case TIOCSSERIAL: - down_write(&tty->termios_rwsem); - ret = uart_set_info_user(tty, state, uarg); - up_write(&tty->termios_rwsem); - break; - case TIOCSERCONFIG: down_write(&tty->termios_rwsem); ret = uart_do_autoconfig(tty, state); up_write(&tty->termios_rwsem); break; - - case TIOCSERGWILD: /* obsolete */ - case TIOCSERSWILD: /* obsolete */ - ret = 0; - break; } if (ret != -ENOIOCTLCMD) @@ -2413,6 +2392,8 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, + .set_serial = uart_set_info_user, + .get_serial = uart_get_info_user, .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index fbdf4d01c6a9..d55c858d6058 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -2959,8 +2959,7 @@ static int mgsl_ioctl(struct tty_struct *tty, if (mgsl_paranoia_check(info, tty->name, "mgsl_ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index a94086597ebd..e8a9047de451 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1029,8 +1029,7 @@ static int ioctl(struct tty_struct *tty, return -ENODEV; DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } @@ -1186,14 +1185,13 @@ static long slgt_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct slgt_info *info = tty->driver_data; - int rc = -ENOIOCTLCMD; + int rc; if (sanity_check(info, tty->name, "compat_ioctl")) return -ENODEV; DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); switch (cmd) { - case MGSL_IOCSPARAMS32: rc = set_params32(info, compat_ptr(arg)); break; @@ -1213,18 +1211,11 @@ static long slgt_compat_ioctl(struct tty_struct *tty, case MGSL_IOCWAITGPIO: case MGSL_IOCGXSYNC: case MGSL_IOCGXCTRL: - case MGSL_IOCSTXIDLE: - case MGSL_IOCTXENABLE: - case MGSL_IOCRXENABLE: - case MGSL_IOCTXABORT: - case TIOCMIWAIT: - case MGSL_IOCSIF: - case MGSL_IOCSXSYNC: - case MGSL_IOCSXCTRL: - rc = ioctl(tty, cmd, arg); + rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); break; + default: + rc = ioctl(tty, cmd, arg); } - DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); return rc; } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 1e4d5b9c981a..fcb91bf7a15b 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1259,8 +1259,7 @@ static int ioctl(struct tty_struct *tty, if (sanity_check(info, tty->name, "ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 816d8ba971a2..da3c1c2f73c4 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -97,6 +97,7 @@ #include <linux/seq_file.h> #include <linux/serial.h> #include <linux/ratelimit.h> +#include <linux/compat.h> #include <linux/uaccess.h> @@ -2293,34 +2294,6 @@ static int tioccons(struct file *file) } /** - * fionbio - non blocking ioctl - * @file: file to set blocking value - * @p: user parameter - * - * Historical tty interfaces had a blocking control ioctl before - * the generic functionality existed. This piece of history is preserved - * in the expected tty API of posix OS's. - * - * Locking: none, the open file handle ensures it won't go away. - */ - -static int fionbio(struct file *file, int __user *p) -{ - int nonblock; - - if (get_user(nonblock, p)) - return -EFAULT; - - spin_lock(&file->f_lock); - if (nonblock) - file->f_flags |= O_NONBLOCK; - else - file->f_flags &= ~O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; -} - -/** * tiocsetd - set line discipline * @tty: tty device * @p: pointer to user data @@ -2488,22 +2461,40 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) return 0; } -static void tty_warn_deprecated_flags(struct serial_struct __user *ss) +static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss) { static DEFINE_RATELIMIT_STATE(depr_flags, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); char comm[TASK_COMM_LEN]; + struct serial_struct v; int flags; - if (get_user(flags, &ss->flags)) - return; + if (copy_from_user(&v, ss, sizeof(struct serial_struct))) + return -EFAULT; - flags &= ASYNC_DEPRECATED; + flags = v.flags & ASYNC_DEPRECATED; if (flags && __ratelimit(&depr_flags)) pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", __func__, get_task_comm(comm, current), flags); + if (!tty->ops->set_serial) + return -ENOTTY; + return tty->ops->set_serial(tty, &v); +} + +static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *ss) +{ + struct serial_struct v; + int err; + + memset(&v, 0, sizeof(struct serial_struct)); + if (!tty->ops->get_serial) + return -ENOTTY; + err = tty->ops->get_serial(tty, &v); + if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct))) + err = -EFAULT; + return err; } /* @@ -2566,8 +2557,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return tiocswinsz(real_tty, p); case TIOCCONS: return real_tty != tty ? -EINVAL : tioccons(file); - case FIONBIO: - return fionbio(file, p); case TIOCEXCL: set_bit(TTY_EXCLUSIVE, &tty->flags); return 0; @@ -2622,11 +2611,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCMBIS: return tty_tiocmset(tty, cmd, p); case TIOCGICOUNT: - retval = tty_tiocgicount(tty, p); - /* For the moment allow fall through to the old method */ - if (retval != -EINVAL) - return retval; - break; + return tty_tiocgicount(tty, p); case TCFLSH: switch (arg) { case TCIFLUSH: @@ -2637,8 +2622,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case TIOCSSERIAL: - tty_warn_deprecated_flags(p); - break; + return tty_tiocsserial(tty, p); + case TIOCGSERIAL: + return tty_tiocgserial(tty, p); case TIOCGPTPEER: /* Special because the struct file is needed */ return ptm_open_peer(file, tty, (int)arg); @@ -2666,6 +2652,81 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT + +struct serial_struct32 { + compat_int_t type; + compat_int_t line; + compat_uint_t port; + compat_int_t irq; + compat_int_t flags; + compat_int_t xmit_fifo_size; + compat_int_t custom_divisor; + compat_int_t baud_base; + unsigned short close_delay; + char io_type; + char reserved_char[1]; + compat_int_t hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + compat_uint_t iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; + /* compat_ulong_t iomap_base FIXME */ + compat_int_t reserved[1]; +}; + +static int compat_tty_tiocsserial(struct tty_struct *tty, + struct serial_struct32 __user *ss) +{ + static DEFINE_RATELIMIT_STATE(depr_flags, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + char comm[TASK_COMM_LEN]; + struct serial_struct32 v32; + struct serial_struct v; + int flags; + + if (copy_from_user(&v32, ss, sizeof(struct serial_struct32))) + return -EFAULT; + + memcpy(&v, &v32, offsetof(struct serial_struct32, iomem_base)); + v.iomem_base = compat_ptr(v32.iomem_base); + v.iomem_reg_shift = v32.iomem_reg_shift; + v.port_high = v32.port_high; + v.iomap_base = 0; + + flags = v.flags & ASYNC_DEPRECATED; + + if (flags && __ratelimit(&depr_flags)) + pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", + __func__, get_task_comm(comm, current), flags); + if (!tty->ops->set_serial) + return -ENOTTY; + return tty->ops->set_serial(tty, &v); +} + +static int compat_tty_tiocgserial(struct tty_struct *tty, + struct serial_struct32 __user *ss) +{ + struct serial_struct32 v32; + struct serial_struct v; + int err; + memset(&v, 0, sizeof(struct serial_struct)); + + if (!tty->ops->set_serial) + return -ENOTTY; + err = tty->ops->get_serial(tty, &v); + if (!err) { + memcpy(&v32, &v, offsetof(struct serial_struct32, iomem_base)); + v32.iomem_base = (unsigned long)v.iomem_base >> 32 ? + 0xfffffff : ptr_to_compat(v.iomem_base); + v32.iomem_reg_shift = v.iomem_reg_shift; + v32.port_high = v.port_high; + if (copy_to_user(ss, &v32, sizeof(struct serial_struct32))) + err = -EFAULT; + } + return err; +} static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2673,9 +2734,90 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, struct tty_ldisc *ld; int retval = -ENOIOCTLCMD; + switch (cmd) { + case TIOCSTI: + case TIOCGWINSZ: + case TIOCSWINSZ: + case TIOCGEXCL: + case TIOCGETD: + case TIOCSETD: + case TIOCGDEV: + case TIOCMGET: + case TIOCMSET: + case TIOCMBIC: + case TIOCMBIS: + case TIOCGICOUNT: + case TIOCGPGRP: + case TIOCSPGRP: + case TIOCGSID: + case TIOCSERGETLSR: + case TIOCGRS485: + case TIOCSRS485: +#ifdef TIOCGETP + case TIOCGETP: + case TIOCSETP: + case TIOCSETN: +#endif +#ifdef TIOCGETC + case TIOCGETC: + case TIOCSETC: +#endif +#ifdef TIOCGLTC + case TIOCGLTC: + case TIOCSLTC: +#endif + case TCSETSF: + case TCSETSW: + case TCSETS: + case TCGETS: +#ifdef TCGETS2 + case TCGETS2: + case TCSETSF2: + case TCSETSW2: + case TCSETS2: +#endif + case TCGETA: + case TCSETAF: + case TCSETAW: + case TCSETA: + case TIOCGLCKTRMIOS: + case TIOCSLCKTRMIOS: +#ifdef TCGETX + case TCGETX: + case TCSETX: + case TCSETXW: + case TCSETXF: +#endif + case TIOCGSOFTCAR: + case TIOCSSOFTCAR: + return tty_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); + case TIOCCONS: + case TIOCEXCL: + case TIOCNXCL: + case TIOCVHANGUP: + case TIOCSBRK: + case TIOCCBRK: + case TCSBRK: + case TCSBRKP: + case TCFLSH: + case TIOCGPTPEER: + case TIOCNOTTY: + case TIOCSCTTY: + case TCXONC: + case TIOCMIWAIT: + case TIOCSERCONFIG: + return tty_ioctl(file, cmd, arg); + } + if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl")) return -EINVAL; + switch (cmd) { + case TIOCSSERIAL: + return compat_tty_tiocsserial(tty, compat_ptr(arg)); + case TIOCGSERIAL: + return compat_tty_tiocgserial(tty, compat_ptr(arg)); + } if (tty->ops->compat_ioctl) { retval = tty->ops->compat_ioctl(tty, cmd, arg); if (retval != -ENOIOCTLCMD) @@ -2687,8 +2829,9 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, return hung_up_tty_compat_ioctl(file, cmd, arg); if (ld->ops->compat_ioctl) retval = ld->ops->compat_ioctl(tty, file, cmd, arg); - else - retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg); + if (retval == -ENOIOCTLCMD && ld->ops->ioctl) + retval = ld->ops->ioctl(tty, file, + (unsigned long)compat_ptr(cmd), arg); tty_ldisc_deref(ld); return retval; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index d99fec44036c..9245fffdbceb 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -941,19 +941,3 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, } } EXPORT_SYMBOL(n_tty_ioctl_helper); - -#ifdef CONFIG_COMPAT -long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case TIOCGLCKTRMIOS: - case TIOCSLCKTRMIOS: - return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg)); - default: - return -ENOIOCTLCMD; - } -} -EXPORT_SYMBOL(n_tty_compat_ioctl_helper); -#endif - diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 73cdc0d633dd..8b0ed139592f 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1175,17 +1175,13 @@ long vt_compat_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - unsigned int console; - void __user *up = (void __user *)arg; + unsigned int console = vc->vc_num; + void __user *up = compat_ptr(arg); int perm; - int ret = 0; - console = vc->vc_num; - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } + if (!vc_cons_allocated(console)) /* impossible? */ + return -ENOIOCTLCMD; /* * To have permissions to do most of the vt ioctls, we either have @@ -1201,17 +1197,14 @@ long vt_compat_ioctl(struct tty_struct *tty, */ case PIO_FONTX: case GIO_FONTX: - ret = compat_fontx_ioctl(cmd, up, perm, &op); - break; + return compat_fontx_ioctl(cmd, up, perm, &op); case KDFONTOP: - ret = compat_kdfontop_ioctl(up, perm, &op, vc); - break; + return compat_kdfontop_ioctl(up, perm, &op, vc); case PIO_UNIMAP: case GIO_UNIMAP: - ret = compat_unimap_ioctl(cmd, up, perm, vc); - break; + return compat_unimap_ioctl(cmd, up, perm, vc); /* * all these treat 'arg' as an integer @@ -1236,21 +1229,15 @@ long vt_compat_ioctl(struct tty_struct *tty, case VT_DISALLOCATE: case VT_RESIZE: case VT_RESIZEX: - goto fallback; + return vt_ioctl(tty, cmd, arg); /* * the rest has a compatible data structure behind arg, * but we have to convert it to a proper 64 bit pointer. */ default: - arg = (unsigned long)compat_ptr(arg); - goto fallback; + return vt_ioctl(tty, cmd, (unsigned long)up); } -out: - return ret; - -fallback: - return vt_ioctl(tty, cmd, arg); } |