Commit 779ee19d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-4.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are a number of small tty and serial driver fixes for 4.5-rc4
  that resolve some reported issues.

  One of them got reverted as it wasn't correct based on testing, and
  all have been in linux-next for a while"

* tag 'tty-4.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  Revert "8250: uniphier: allow modular build with 8250 console"
  pty: make sure super_block is still valid in final /dev/tty close
  pty: fix possible use after free of tty->driver_data
  tty: Add support for PCIe WCH382 2S multi-IO card
  serial/omap: mark wait_for_xmitr as __maybe_unused
  serial: omap: Prevent DoS using unprivileged ioctl(TIOCSRS485)
  8250: uniphier: allow modular build with 8250 console
  tty: Drop krefs for interrupted tty lock
parents 9db8cc1a c8053b58
...@@ -681,7 +681,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) ...@@ -681,7 +681,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
/* this is called once with whichever end is closed last */ /* this is called once with whichever end is closed last */
static void pty_unix98_shutdown(struct tty_struct *tty) static void pty_unix98_shutdown(struct tty_struct *tty)
{ {
devpts_kill_index(tty->driver_data, tty->index); struct inode *ptmx_inode;
if (tty->driver->subtype == PTY_TYPE_MASTER)
ptmx_inode = tty->driver_data;
else
ptmx_inode = tty->link->driver_data;
devpts_kill_index(ptmx_inode, tty->index);
devpts_del_ref(ptmx_inode);
} }
static const struct tty_operations ptm_unix98_ops = { static const struct tty_operations ptm_unix98_ops = {
...@@ -773,6 +780,18 @@ static int ptmx_open(struct inode *inode, struct file *filp) ...@@ -773,6 +780,18 @@ static int ptmx_open(struct inode *inode, struct file *filp)
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty->driver_data = inode; tty->driver_data = inode;
/*
* In the case where all references to ptmx inode are dropped and we
* still have /dev/tty opened pointing to the master/slave pair (ptmx
* is closed/released before /dev/tty), we must make sure that the inode
* is still valid when we call the final pty_unix98_shutdown, thus we
* hold an additional reference to the ptmx inode. For the same /dev/tty
* last close case, we also need to make sure the super_block isn't
* destroyed (devpts instance unmounted), before /dev/tty is closed and
* on its release devpts_kill_index is called.
*/
devpts_add_ref(inode);
tty_add_file(tty, filp); tty_add_file(tty, filp);
slave_inode = devpts_pty_new(inode, slave_inode = devpts_pty_new(inode,
......
...@@ -1941,6 +1941,7 @@ pci_wch_ch38x_setup(struct serial_private *priv, ...@@ -1941,6 +1941,7 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCIE_VENDOR_ID_WCH 0x1c00 #define PCIE_VENDOR_ID_WCH 0x1c00
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253
#define PCI_VENDOR_ID_PERICOM 0x12D8 #define PCI_VENDOR_ID_PERICOM 0x12D8
#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951 #define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951
...@@ -2637,6 +2638,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { ...@@ -2637,6 +2638,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup, .setup = pci_wch_ch353_setup,
}, },
/* WCH CH382 2S card (16850 clone) */
{
.vendor = PCIE_VENDOR_ID_WCH,
.device = PCIE_DEVICE_ID_WCH_CH382_2S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch38x_setup,
},
/* WCH CH382 2S1P card (16850 clone) */ /* WCH CH382 2S1P card (16850 clone) */
{ {
.vendor = PCIE_VENDOR_ID_WCH, .vendor = PCIE_VENDOR_ID_WCH,
...@@ -2955,6 +2964,7 @@ enum pci_board_num_t { ...@@ -2955,6 +2964,7 @@ enum pci_board_num_t {
pbn_fintek_4, pbn_fintek_4,
pbn_fintek_8, pbn_fintek_8,
pbn_fintek_12, pbn_fintek_12,
pbn_wch382_2,
pbn_wch384_4, pbn_wch384_4,
pbn_pericom_PI7C9X7951, pbn_pericom_PI7C9X7951,
pbn_pericom_PI7C9X7952, pbn_pericom_PI7C9X7952,
...@@ -3775,6 +3785,13 @@ static struct pciserial_board pci_boards[] = { ...@@ -3775,6 +3785,13 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 115200, .base_baud = 115200,
.first_offset = 0x40, .first_offset = 0x40,
}, },
[pbn_wch382_2] = {
.flags = FL_BASE0,
.num_ports = 2,
.base_baud = 115200,
.uart_offset = 8,
.first_offset = 0xC0,
},
[pbn_wch384_4] = { [pbn_wch384_4] = {
.flags = FL_BASE0, .flags = FL_BASE0,
.num_ports = 4, .num_ports = 4,
...@@ -5574,6 +5591,10 @@ static struct pci_device_id serial_pci_tbl[] = { ...@@ -5574,6 +5591,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 }, 0, 0, pbn_b0_bt_2_115200 },
{ PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch382_2 },
{ PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S, { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch384_4 }, 0, 0, pbn_wch384_4 },
......
...@@ -1165,7 +1165,7 @@ serial_omap_type(struct uart_port *port) ...@@ -1165,7 +1165,7 @@ serial_omap_type(struct uart_port *port)
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static void wait_for_xmitr(struct uart_omap_port *up) static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
{ {
unsigned int status, tmout = 10000; unsigned int status, tmout = 10000;
...@@ -1343,7 +1343,7 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up) ...@@ -1343,7 +1343,7 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
/* Enable or disable the rs485 support */ /* Enable or disable the rs485 support */
static int static int
serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
{ {
struct uart_omap_port *up = to_uart_omap_port(port); struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int mode; unsigned int mode;
...@@ -1356,8 +1356,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) ...@@ -1356,8 +1356,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
up->ier = 0; up->ier = 0;
serial_out(up, UART_IER, 0); serial_out(up, UART_IER, 0);
/* Clamp the delays to [0, 100ms] */
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
/* store new config */ /* store new config */
port->rs485 = *rs485conf; port->rs485 = *rs485;
/* /*
* Just as a precaution, only allow rs485 * Just as a precaution, only allow rs485
......
...@@ -2066,13 +2066,12 @@ static int tty_open(struct inode *inode, struct file *filp) ...@@ -2066,13 +2066,12 @@ static int tty_open(struct inode *inode, struct file *filp)
if (tty) { if (tty) {
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
retval = tty_lock_interruptible(tty); retval = tty_lock_interruptible(tty);
tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */
if (retval) { if (retval) {
if (retval == -EINTR) if (retval == -EINTR)
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
goto err_unref; goto err_unref;
} }
/* safe to drop the kref from tty_driver_lookup_tty() */
tty_kref_put(tty);
retval = tty_reopen(tty); retval = tty_reopen(tty);
if (retval < 0) { if (retval < 0) {
tty_unlock(tty); tty_unlock(tty);
......
...@@ -21,10 +21,15 @@ EXPORT_SYMBOL(tty_lock); ...@@ -21,10 +21,15 @@ EXPORT_SYMBOL(tty_lock);
int tty_lock_interruptible(struct tty_struct *tty) int tty_lock_interruptible(struct tty_struct *tty)
{ {
int ret;
if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
return -EIO; return -EIO;
tty_kref_get(tty); tty_kref_get(tty);
return mutex_lock_interruptible(&tty->legacy_mutex); ret = mutex_lock_interruptible(&tty->legacy_mutex);
if (ret)
tty_kref_put(tty);
return ret;
} }
void __lockfunc tty_unlock(struct tty_struct *tty) void __lockfunc tty_unlock(struct tty_struct *tty)
......
...@@ -575,6 +575,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx) ...@@ -575,6 +575,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
mutex_unlock(&allocated_ptys_lock); mutex_unlock(&allocated_ptys_lock);
} }
/*
* pty code needs to hold extra references in case of last /dev/tty close
*/
void devpts_add_ref(struct inode *ptmx_inode)
{
struct super_block *sb = pts_sb_from_inode(ptmx_inode);
atomic_inc(&sb->s_active);
ihold(ptmx_inode);
}
void devpts_del_ref(struct inode *ptmx_inode)
{
struct super_block *sb = pts_sb_from_inode(ptmx_inode);
iput(ptmx_inode);
deactivate_super(sb);
}
/** /**
* devpts_pty_new -- create a new inode in /dev/pts/ * devpts_pty_new -- create a new inode in /dev/pts/
* @ptmx_inode: inode of the master * @ptmx_inode: inode of the master
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
int devpts_new_index(struct inode *ptmx_inode); int devpts_new_index(struct inode *ptmx_inode);
void devpts_kill_index(struct inode *ptmx_inode, int idx); void devpts_kill_index(struct inode *ptmx_inode, int idx);
void devpts_add_ref(struct inode *ptmx_inode);
void devpts_del_ref(struct inode *ptmx_inode);
/* mknod in devpts */ /* mknod in devpts */
struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
void *priv); void *priv);
...@@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode); ...@@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode);
/* Dummy stubs in the no-pty case */ /* Dummy stubs in the no-pty case */
static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
static inline void devpts_add_ref(struct inode *ptmx_inode) { }
static inline void devpts_del_ref(struct inode *ptmx_inode) { }
static inline struct inode *devpts_pty_new(struct inode *ptmx_inode, static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
dev_t device, int index, void *priv) dev_t device, int index, void *priv)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment