diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-14 15:29:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-14 15:29:59 -0500 |
commit | 779ee19da757d6bbf5504840f8b624f525de9797 (patch) | |
tree | c538becc24cb3a49b59d6ed782160a84dee8c1bb | |
parent | 9db8cc1ae5b0805230f710ddf4f2de0591db820a (diff) | |
parent | c8053b58762745d93930826b60a4073854a15ce5 (diff) |
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
-rw-r--r-- | drivers/tty/pty.c | 21 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 21 | ||||
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 10 | ||||
-rw-r--r-- | drivers/tty/tty_io.c | 3 | ||||
-rw-r--r-- | drivers/tty/tty_mutex.c | 7 | ||||
-rw-r--r-- | fs/devpts/inode.c | 20 | ||||
-rw-r--r-- | include/linux/devpts_fs.h | 4 |
7 files changed, 79 insertions, 7 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index b3110040164a..2348fa613707 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c | |||
@@ -681,7 +681,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) | |||
681 | /* this is called once with whichever end is closed last */ | 681 | /* this is called once with whichever end is closed last */ |
682 | static void pty_unix98_shutdown(struct tty_struct *tty) | 682 | static void pty_unix98_shutdown(struct tty_struct *tty) |
683 | { | 683 | { |
684 | devpts_kill_index(tty->driver_data, tty->index); | 684 | struct inode *ptmx_inode; |
685 | |||
686 | if (tty->driver->subtype == PTY_TYPE_MASTER) | ||
687 | ptmx_inode = tty->driver_data; | ||
688 | else | ||
689 | ptmx_inode = tty->link->driver_data; | ||
690 | devpts_kill_index(ptmx_inode, tty->index); | ||
691 | devpts_del_ref(ptmx_inode); | ||
685 | } | 692 | } |
686 | 693 | ||
687 | static const struct tty_operations ptm_unix98_ops = { | 694 | static const struct tty_operations ptm_unix98_ops = { |
@@ -773,6 +780,18 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
773 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | 780 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ |
774 | tty->driver_data = inode; | 781 | tty->driver_data = inode; |
775 | 782 | ||
783 | /* | ||
784 | * In the case where all references to ptmx inode are dropped and we | ||
785 | * still have /dev/tty opened pointing to the master/slave pair (ptmx | ||
786 | * is closed/released before /dev/tty), we must make sure that the inode | ||
787 | * is still valid when we call the final pty_unix98_shutdown, thus we | ||
788 | * hold an additional reference to the ptmx inode. For the same /dev/tty | ||
789 | * last close case, we also need to make sure the super_block isn't | ||
790 | * destroyed (devpts instance unmounted), before /dev/tty is closed and | ||
791 | * on its release devpts_kill_index is called. | ||
792 | */ | ||
793 | devpts_add_ref(inode); | ||
794 | |||
776 | tty_add_file(tty, filp); | 795 | tty_add_file(tty, filp); |
777 | 796 | ||
778 | slave_inode = devpts_pty_new(inode, | 797 | slave_inode = devpts_pty_new(inode, |
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e71ec78fc11e..7cd6f9a90542 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c | |||
@@ -1941,6 +1941,7 @@ pci_wch_ch38x_setup(struct serial_private *priv, | |||
1941 | #define PCIE_VENDOR_ID_WCH 0x1c00 | 1941 | #define PCIE_VENDOR_ID_WCH 0x1c00 |
1942 | #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 | 1942 | #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 |
1943 | #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 | 1943 | #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 |
1944 | #define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253 | ||
1944 | 1945 | ||
1945 | #define PCI_VENDOR_ID_PERICOM 0x12D8 | 1946 | #define PCI_VENDOR_ID_PERICOM 0x12D8 |
1946 | #define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951 | 1947 | #define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951 |
@@ -2637,6 +2638,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { | |||
2637 | .subdevice = PCI_ANY_ID, | 2638 | .subdevice = PCI_ANY_ID, |
2638 | .setup = pci_wch_ch353_setup, | 2639 | .setup = pci_wch_ch353_setup, |
2639 | }, | 2640 | }, |
2641 | /* WCH CH382 2S card (16850 clone) */ | ||
2642 | { | ||
2643 | .vendor = PCIE_VENDOR_ID_WCH, | ||
2644 | .device = PCIE_DEVICE_ID_WCH_CH382_2S, | ||
2645 | .subvendor = PCI_ANY_ID, | ||
2646 | .subdevice = PCI_ANY_ID, | ||
2647 | .setup = pci_wch_ch38x_setup, | ||
2648 | }, | ||
2640 | /* WCH CH382 2S1P card (16850 clone) */ | 2649 | /* WCH CH382 2S1P card (16850 clone) */ |
2641 | { | 2650 | { |
2642 | .vendor = PCIE_VENDOR_ID_WCH, | 2651 | .vendor = PCIE_VENDOR_ID_WCH, |
@@ -2955,6 +2964,7 @@ enum pci_board_num_t { | |||
2955 | pbn_fintek_4, | 2964 | pbn_fintek_4, |
2956 | pbn_fintek_8, | 2965 | pbn_fintek_8, |
2957 | pbn_fintek_12, | 2966 | pbn_fintek_12, |
2967 | pbn_wch382_2, | ||
2958 | pbn_wch384_4, | 2968 | pbn_wch384_4, |
2959 | pbn_pericom_PI7C9X7951, | 2969 | pbn_pericom_PI7C9X7951, |
2960 | pbn_pericom_PI7C9X7952, | 2970 | pbn_pericom_PI7C9X7952, |
@@ -3775,6 +3785,13 @@ static struct pciserial_board pci_boards[] = { | |||
3775 | .base_baud = 115200, | 3785 | .base_baud = 115200, |
3776 | .first_offset = 0x40, | 3786 | .first_offset = 0x40, |
3777 | }, | 3787 | }, |
3788 | [pbn_wch382_2] = { | ||
3789 | .flags = FL_BASE0, | ||
3790 | .num_ports = 2, | ||
3791 | .base_baud = 115200, | ||
3792 | .uart_offset = 8, | ||
3793 | .first_offset = 0xC0, | ||
3794 | }, | ||
3778 | [pbn_wch384_4] = { | 3795 | [pbn_wch384_4] = { |
3779 | .flags = FL_BASE0, | 3796 | .flags = FL_BASE0, |
3780 | .num_ports = 4, | 3797 | .num_ports = 4, |
@@ -5574,6 +5591,10 @@ static struct pci_device_id serial_pci_tbl[] = { | |||
5574 | PCI_ANY_ID, PCI_ANY_ID, | 5591 | PCI_ANY_ID, PCI_ANY_ID, |
5575 | 0, 0, pbn_b0_bt_2_115200 }, | 5592 | 0, 0, pbn_b0_bt_2_115200 }, |
5576 | 5593 | ||
5594 | { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S, | ||
5595 | PCI_ANY_ID, PCI_ANY_ID, | ||
5596 | 0, 0, pbn_wch382_2 }, | ||
5597 | |||
5577 | { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S, | 5598 | { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S, |
5578 | PCI_ANY_ID, PCI_ANY_ID, | 5599 | PCI_ANY_ID, PCI_ANY_ID, |
5579 | 0, 0, pbn_wch384_4 }, | 5600 | 0, 0, pbn_wch384_4 }, |
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index b645f9228ed7..fa49eb1e2fa2 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c | |||
@@ -1165,7 +1165,7 @@ serial_omap_type(struct uart_port *port) | |||
1165 | 1165 | ||
1166 | #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) | 1166 | #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) |
1167 | 1167 | ||
1168 | static void wait_for_xmitr(struct uart_omap_port *up) | 1168 | static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) |
1169 | { | 1169 | { |
1170 | unsigned int status, tmout = 10000; | 1170 | unsigned int status, tmout = 10000; |
1171 | 1171 | ||
@@ -1343,7 +1343,7 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up) | |||
1343 | 1343 | ||
1344 | /* Enable or disable the rs485 support */ | 1344 | /* Enable or disable the rs485 support */ |
1345 | static int | 1345 | static int |
1346 | serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) | 1346 | serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) |
1347 | { | 1347 | { |
1348 | struct uart_omap_port *up = to_uart_omap_port(port); | 1348 | struct uart_omap_port *up = to_uart_omap_port(port); |
1349 | unsigned int mode; | 1349 | unsigned int mode; |
@@ -1356,8 +1356,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) | |||
1356 | up->ier = 0; | 1356 | up->ier = 0; |
1357 | serial_out(up, UART_IER, 0); | 1357 | serial_out(up, UART_IER, 0); |
1358 | 1358 | ||
1359 | /* Clamp the delays to [0, 100ms] */ | ||
1360 | rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); | ||
1361 | rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); | ||
1362 | |||
1359 | /* store new config */ | 1363 | /* store new config */ |
1360 | port->rs485 = *rs485conf; | 1364 | port->rs485 = *rs485; |
1361 | 1365 | ||
1362 | /* | 1366 | /* |
1363 | * Just as a precaution, only allow rs485 | 1367 | * Just as a precaution, only allow rs485 |
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 5cec01c75691..a7eacef1bd22 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c | |||
@@ -2066,13 +2066,12 @@ retry_open: | |||
2066 | if (tty) { | 2066 | if (tty) { |
2067 | mutex_unlock(&tty_mutex); | 2067 | mutex_unlock(&tty_mutex); |
2068 | retval = tty_lock_interruptible(tty); | 2068 | retval = tty_lock_interruptible(tty); |
2069 | tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */ | ||
2069 | if (retval) { | 2070 | if (retval) { |
2070 | if (retval == -EINTR) | 2071 | if (retval == -EINTR) |
2071 | retval = -ERESTARTSYS; | 2072 | retval = -ERESTARTSYS; |
2072 | goto err_unref; | 2073 | goto err_unref; |
2073 | } | 2074 | } |
2074 | /* safe to drop the kref from tty_driver_lookup_tty() */ | ||
2075 | tty_kref_put(tty); | ||
2076 | retval = tty_reopen(tty); | 2075 | retval = tty_reopen(tty); |
2077 | if (retval < 0) { | 2076 | if (retval < 0) { |
2078 | tty_unlock(tty); | 2077 | tty_unlock(tty); |
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index d2f3c4cd697f..dfa9ec03fa8e 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c | |||
@@ -21,10 +21,15 @@ EXPORT_SYMBOL(tty_lock); | |||
21 | 21 | ||
22 | int tty_lock_interruptible(struct tty_struct *tty) | 22 | int tty_lock_interruptible(struct tty_struct *tty) |
23 | { | 23 | { |
24 | int ret; | ||
25 | |||
24 | if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) | 26 | if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) |
25 | return -EIO; | 27 | return -EIO; |
26 | tty_kref_get(tty); | 28 | tty_kref_get(tty); |
27 | return mutex_lock_interruptible(&tty->legacy_mutex); | 29 | ret = mutex_lock_interruptible(&tty->legacy_mutex); |
30 | if (ret) | ||
31 | tty_kref_put(tty); | ||
32 | return ret; | ||
28 | } | 33 | } |
29 | 34 | ||
30 | void __lockfunc tty_unlock(struct tty_struct *tty) | 35 | void __lockfunc tty_unlock(struct tty_struct *tty) |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 1f107fd51328..655f21f99160 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -575,6 +575,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx) | |||
575 | mutex_unlock(&allocated_ptys_lock); | 575 | mutex_unlock(&allocated_ptys_lock); |
576 | } | 576 | } |
577 | 577 | ||
578 | /* | ||
579 | * pty code needs to hold extra references in case of last /dev/tty close | ||
580 | */ | ||
581 | |||
582 | void devpts_add_ref(struct inode *ptmx_inode) | ||
583 | { | ||
584 | struct super_block *sb = pts_sb_from_inode(ptmx_inode); | ||
585 | |||
586 | atomic_inc(&sb->s_active); | ||
587 | ihold(ptmx_inode); | ||
588 | } | ||
589 | |||
590 | void devpts_del_ref(struct inode *ptmx_inode) | ||
591 | { | ||
592 | struct super_block *sb = pts_sb_from_inode(ptmx_inode); | ||
593 | |||
594 | iput(ptmx_inode); | ||
595 | deactivate_super(sb); | ||
596 | } | ||
597 | |||
578 | /** | 598 | /** |
579 | * devpts_pty_new -- create a new inode in /dev/pts/ | 599 | * devpts_pty_new -- create a new inode in /dev/pts/ |
580 | * @ptmx_inode: inode of the master | 600 | * @ptmx_inode: inode of the master |
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h index 251a2090a554..e0ee0b3000b2 100644 --- a/include/linux/devpts_fs.h +++ b/include/linux/devpts_fs.h | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | int devpts_new_index(struct inode *ptmx_inode); | 20 | int devpts_new_index(struct inode *ptmx_inode); |
21 | void devpts_kill_index(struct inode *ptmx_inode, int idx); | 21 | void devpts_kill_index(struct inode *ptmx_inode, int idx); |
22 | void devpts_add_ref(struct inode *ptmx_inode); | ||
23 | void devpts_del_ref(struct inode *ptmx_inode); | ||
22 | /* mknod in devpts */ | 24 | /* mknod in devpts */ |
23 | struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, | 25 | struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, |
24 | void *priv); | 26 | void *priv); |
@@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode); | |||
32 | /* Dummy stubs in the no-pty case */ | 34 | /* Dummy stubs in the no-pty case */ |
33 | static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } | 35 | static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } |
34 | static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } | 36 | static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } |
37 | static inline void devpts_add_ref(struct inode *ptmx_inode) { } | ||
38 | static inline void devpts_del_ref(struct inode *ptmx_inode) { } | ||
35 | static inline struct inode *devpts_pty_new(struct inode *ptmx_inode, | 39 | static inline struct inode *devpts_pty_new(struct inode *ptmx_inode, |
36 | dev_t device, int index, void *priv) | 40 | dev_t device, int index, void *priv) |
37 | { | 41 | { |