Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: never hold BTM while getting tty_mutex

tty_mutex is never taken with the BTM held, except for
two corner cases that are worked around here.
We give up the BTM before calling tty_release() in the
error path of tty_open().
Similarly, we reorder the locking in ptmx_open()
to get tty_mutex before the BTM.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Arnd Bergmann and committed by
Greg Kroah-Hartman
64ba3dc3 ec79d605

+17 -19
+11 -13
drivers/char/pty.c
··· 647 647 * allocated_ptys_lock handles the list of free pty numbers 648 648 */ 649 649 650 - static int __ptmx_open(struct inode *inode, struct file *filp) 650 + static int ptmx_open(struct inode *inode, struct file *filp) 651 651 { 652 652 struct tty_struct *tty; 653 653 int retval; ··· 656 656 nonseekable_open(inode, filp); 657 657 658 658 /* find a device that is not in use. */ 659 + tty_lock(); 659 660 index = devpts_new_index(inode); 661 + tty_unlock(); 660 662 if (index < 0) 661 663 return index; 662 664 663 665 mutex_lock(&tty_mutex); 666 + tty_lock(); 664 667 tty = tty_init_dev(ptm_driver, index, 1); 665 668 mutex_unlock(&tty_mutex); 666 669 ··· 681 678 goto out1; 682 679 683 680 retval = ptm_driver->ops->open(tty, filp); 684 - if (!retval) 685 - return 0; 681 + if (retval) 682 + goto out2; 686 683 out1: 684 + tty_unlock(); 685 + return retval; 686 + out2: 687 + tty_unlock(); 687 688 tty_release(inode, filp); 688 689 return retval; 689 690 out: 690 691 devpts_kill_index(inode, index); 691 - return retval; 692 - } 693 - 694 - static int ptmx_open(struct inode *inode, struct file *filp) 695 - { 696 - int ret; 697 - 698 - tty_lock(); 699 - ret = __ptmx_open(inode, filp); 700 692 tty_unlock(); 701 - return ret; 693 + return retval; 702 694 } 703 695 704 696 static struct file_operations ptmx_fops;
+6 -6
drivers/char/tty_io.c
··· 1866 1866 printk(KERN_DEBUG "error %d in opening %s...", retval, 1867 1867 tty->name); 1868 1868 #endif 1869 + tty_unlock(); /* need to call tty_release without BTM */ 1869 1870 tty_release(inode, filp); 1870 - if (retval != -ERESTARTSYS) { 1871 - tty_unlock(); 1871 + if (retval != -ERESTARTSYS) 1872 1872 return retval; 1873 - } 1874 - if (signal_pending(current)) { 1875 - tty_unlock(); 1873 + 1874 + if (signal_pending(current)) 1876 1875 return retval; 1877 - } 1876 + 1878 1877 schedule(); 1879 1878 /* 1880 1879 * Need to reset f_op in case a hangup happened. 1881 1880 */ 1881 + tty_lock(); 1882 1882 if (filp->f_op == &hung_up_tty_fops) 1883 1883 filp->f_op = &tty_fops; 1884 1884 tty_unlock();