aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2010-08-17 14:37:36 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-18 08:35:47 -0400
commitd996b62a8df1d935b01319bf8defb95b5709f7b8 (patch)
treed81f8240da776336845a2063555d7bb4dce684bd /drivers/char/tty_io.c
parentee2ffa0dfdd2db19705f2ba1c6a4c0bfe8122dd8 (diff)
tty: fix fu_list abuse
tty: fix fu_list abuse tty code abuses fu_list, which causes a bug in remount,ro handling. If a tty device node is opened on a filesystem, then the last link to the inode removed, the filesystem will be allowed to be remounted readonly. This is because fs_may_remount_ro does not find the 0 link tty inode on the file sb list (because the tty code incorrectly removed it to use for its own purpose). This can result in a filesystem with errors after it is marked "clean". Taking idea from Christoph's initial patch, allocate a tty private struct at file->private_data and put our required list fields in there, linking file and tty. This makes tty nodes behave the same way as other device nodes and avoid meddling with the vfs, and avoids this bug. The error handling is not trivial in the tty code, so for this bugfix, I take the simple approach of using __GFP_NOFAIL and don't worry about memory errors. This is not a problem because our allocator doesn't fail small allocs as a rule anyway. So proper error handling is left as an exercise for tty hackers. [ Arguably filesystem's device inode would ideally be divorced from the driver's pseudo inode when it is opened, but in practice it's not clear whether that will ever be worth implementing. ] Cc: linux-kernel@vger.kernel.org Cc: Christoph Hellwig <hch@infradead.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Nick Piggin <npiggin@kernel.dk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c84
1 files changed, 54 insertions, 30 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index cd5b829634ea..949067a0bd47 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -188,6 +188,41 @@ void free_tty_struct(struct tty_struct *tty)
188 kfree(tty); 188 kfree(tty);
189} 189}
190 190
191static inline struct tty_struct *file_tty(struct file *file)
192{
193 return ((struct tty_file_private *)file->private_data)->tty;
194}
195
196/* Associate a new file with the tty structure */
197void tty_add_file(struct tty_struct *tty, struct file *file)
198{
199 struct tty_file_private *priv;
200
201 /* XXX: must implement proper error handling in callers */
202 priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL);
203
204 priv->tty = tty;
205 priv->file = file;
206 file->private_data = priv;
207
208 spin_lock(&tty_files_lock);
209 list_add(&priv->list, &tty->tty_files);
210 spin_unlock(&tty_files_lock);
211}
212
213/* Delete file from its tty */
214void tty_del_file(struct file *file)
215{
216 struct tty_file_private *priv = file->private_data;
217
218 spin_lock(&tty_files_lock);
219 list_del(&priv->list);
220 spin_unlock(&tty_files_lock);
221 file->private_data = NULL;
222 kfree(priv);
223}
224
225
191#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) 226#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
192 227
193/** 228/**
@@ -500,6 +535,7 @@ void __tty_hangup(struct tty_struct *tty)
500 struct file *cons_filp = NULL; 535 struct file *cons_filp = NULL;
501 struct file *filp, *f = NULL; 536 struct file *filp, *f = NULL;
502 struct task_struct *p; 537 struct task_struct *p;
538 struct tty_file_private *priv;
503 int closecount = 0, n; 539 int closecount = 0, n;
504 unsigned long flags; 540 unsigned long flags;
505 int refs = 0; 541 int refs = 0;
@@ -509,7 +545,7 @@ void __tty_hangup(struct tty_struct *tty)
509 545
510 546
511 spin_lock(&redirect_lock); 547 spin_lock(&redirect_lock);
512 if (redirect && redirect->private_data == tty) { 548 if (redirect && file_tty(redirect) == tty) {
513 f = redirect; 549 f = redirect;
514 redirect = NULL; 550 redirect = NULL;
515 } 551 }
@@ -524,7 +560,8 @@ void __tty_hangup(struct tty_struct *tty)
524 560
525 spin_lock(&tty_files_lock); 561 spin_lock(&tty_files_lock);
526 /* This breaks for file handles being sent over AF_UNIX sockets ? */ 562 /* This breaks for file handles being sent over AF_UNIX sockets ? */
527 list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { 563 list_for_each_entry(priv, &tty->tty_files, list) {
564 filp = priv->file;
528 if (filp->f_op->write == redirected_tty_write) 565 if (filp->f_op->write == redirected_tty_write)
529 cons_filp = filp; 566 cons_filp = filp;
530 if (filp->f_op->write != tty_write) 567 if (filp->f_op->write != tty_write)
@@ -892,12 +929,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
892 loff_t *ppos) 929 loff_t *ppos)
893{ 930{
894 int i; 931 int i;
895 struct tty_struct *tty; 932 struct inode *inode = file->f_path.dentry->d_inode;
896 struct inode *inode; 933 struct tty_struct *tty = file_tty(file);
897 struct tty_ldisc *ld; 934 struct tty_ldisc *ld;
898 935
899 tty = file->private_data;
900 inode = file->f_path.dentry->d_inode;
901 if (tty_paranoia_check(tty, inode, "tty_read")) 936 if (tty_paranoia_check(tty, inode, "tty_read"))
902 return -EIO; 937 return -EIO;
903 if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) 938 if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
@@ -1068,12 +1103,11 @@ void tty_write_message(struct tty_struct *tty, char *msg)
1068static ssize_t tty_write(struct file *file, const char __user *buf, 1103static ssize_t tty_write(struct file *file, const char __user *buf,
1069 size_t count, loff_t *ppos) 1104 size_t count, loff_t *ppos)
1070{ 1105{
1071 struct tty_struct *tty;
1072 struct inode *inode = file->f_path.dentry->d_inode; 1106 struct inode *inode = file->f_path.dentry->d_inode;
1107 struct tty_struct *tty = file_tty(file);
1108 struct tty_ldisc *ld;
1073 ssize_t ret; 1109 ssize_t ret;
1074 struct tty_ldisc *ld;
1075 1110
1076 tty = file->private_data;
1077 if (tty_paranoia_check(tty, inode, "tty_write")) 1111 if (tty_paranoia_check(tty, inode, "tty_write"))
1078 return -EIO; 1112 return -EIO;
1079 if (!tty || !tty->ops->write || 1113 if (!tty || !tty->ops->write ||
@@ -1510,13 +1544,13 @@ static void release_tty(struct tty_struct *tty, int idx)
1510 1544
1511int tty_release(struct inode *inode, struct file *filp) 1545int tty_release(struct inode *inode, struct file *filp)
1512{ 1546{
1513 struct tty_struct *tty, *o_tty; 1547 struct tty_struct *tty = file_tty(filp);
1548 struct tty_struct *o_tty;
1514 int pty_master, tty_closing, o_tty_closing, do_sleep; 1549 int pty_master, tty_closing, o_tty_closing, do_sleep;
1515 int devpts; 1550 int devpts;
1516 int idx; 1551 int idx;
1517 char buf[64]; 1552 char buf[64];
1518 1553
1519 tty = filp->private_data;
1520 if (tty_paranoia_check(tty, inode, "tty_release_dev")) 1554 if (tty_paranoia_check(tty, inode, "tty_release_dev"))
1521 return 0; 1555 return 0;
1522 1556
@@ -1674,11 +1708,7 @@ int tty_release(struct inode *inode, struct file *filp)
1674 * - do_tty_hangup no longer sees this file descriptor as 1708 * - do_tty_hangup no longer sees this file descriptor as
1675 * something that needs to be handled for hangups. 1709 * something that needs to be handled for hangups.
1676 */ 1710 */
1677 spin_lock(&tty_files_lock); 1711 tty_del_file(filp);
1678 BUG_ON(list_empty(&filp->f_u.fu_list));
1679 list_del_init(&filp->f_u.fu_list);
1680 spin_unlock(&tty_files_lock);
1681 filp->private_data = NULL;
1682 1712
1683 /* 1713 /*
1684 * Perform some housekeeping before deciding whether to return. 1714 * Perform some housekeeping before deciding whether to return.
@@ -1845,12 +1875,8 @@ got_driver:
1845 return PTR_ERR(tty); 1875 return PTR_ERR(tty);
1846 } 1876 }
1847 1877
1848 filp->private_data = tty; 1878 tty_add_file(tty, filp);
1849 BUG_ON(list_empty(&filp->f_u.fu_list)); 1879
1850 file_sb_list_del(filp); /* __dentry_open has put it on the sb list */
1851 spin_lock(&tty_files_lock);
1852 list_add(&filp->f_u.fu_list, &tty->tty_files);
1853 spin_unlock(&tty_files_lock);
1854 check_tty_count(tty, "tty_open"); 1880 check_tty_count(tty, "tty_open");
1855 if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 1881 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
1856 tty->driver->subtype == PTY_TYPE_MASTER) 1882 tty->driver->subtype == PTY_TYPE_MASTER)
@@ -1926,11 +1952,10 @@ got_driver:
1926 1952
1927static unsigned int tty_poll(struct file *filp, poll_table *wait) 1953static unsigned int tty_poll(struct file *filp, poll_table *wait)
1928{ 1954{
1929 struct tty_struct *tty; 1955 struct tty_struct *tty = file_tty(filp);
1930 struct tty_ldisc *ld; 1956 struct tty_ldisc *ld;
1931 int ret = 0; 1957 int ret = 0;
1932 1958
1933 tty = filp->private_data;
1934 if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll")) 1959 if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
1935 return 0; 1960 return 0;
1936 1961
@@ -1943,11 +1968,10 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
1943 1968
1944static int __tty_fasync(int fd, struct file *filp, int on) 1969static int __tty_fasync(int fd, struct file *filp, int on)
1945{ 1970{
1946 struct tty_struct *tty; 1971 struct tty_struct *tty = file_tty(filp);
1947 unsigned long flags; 1972 unsigned long flags;
1948 int retval = 0; 1973 int retval = 0;
1949 1974
1950 tty = filp->private_data;
1951 if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) 1975 if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
1952 goto out; 1976 goto out;
1953 1977
@@ -2501,13 +2525,13 @@ EXPORT_SYMBOL(tty_pair_get_pty);
2501 */ 2525 */
2502long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 2526long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2503{ 2527{
2504 struct tty_struct *tty, *real_tty; 2528 struct tty_struct *tty = file_tty(file);
2529 struct tty_struct *real_tty;
2505 void __user *p = (void __user *)arg; 2530 void __user *p = (void __user *)arg;
2506 int retval; 2531 int retval;
2507 struct tty_ldisc *ld; 2532 struct tty_ldisc *ld;
2508 struct inode *inode = file->f_dentry->d_inode; 2533 struct inode *inode = file->f_dentry->d_inode;
2509 2534
2510 tty = file->private_data;
2511 if (tty_paranoia_check(tty, inode, "tty_ioctl")) 2535 if (tty_paranoia_check(tty, inode, "tty_ioctl"))
2512 return -EINVAL; 2536 return -EINVAL;
2513 2537
@@ -2629,7 +2653,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
2629 unsigned long arg) 2653 unsigned long arg)
2630{ 2654{
2631 struct inode *inode = file->f_dentry->d_inode; 2655 struct inode *inode = file->f_dentry->d_inode;
2632 struct tty_struct *tty = file->private_data; 2656 struct tty_struct *tty = file_tty(file);
2633 struct tty_ldisc *ld; 2657 struct tty_ldisc *ld;
2634 int retval = -ENOIOCTLCMD; 2658 int retval = -ENOIOCTLCMD;
2635 2659
@@ -2721,7 +2745,7 @@ void __do_SAK(struct tty_struct *tty)
2721 if (!filp) 2745 if (!filp)
2722 continue; 2746 continue;
2723 if (filp->f_op->read == tty_read && 2747 if (filp->f_op->read == tty_read &&
2724 filp->private_data == tty) { 2748 file_tty(filp) == tty) {
2725 printk(KERN_NOTICE "SAK: killed process %d" 2749 printk(KERN_NOTICE "SAK: killed process %d"
2726 " (%s): fd#%d opened to the tty\n", 2750 " (%s): fd#%d opened to the tty\n",
2727 task_pid_nr(p), p->comm, i); 2751 task_pid_nr(p), p->comm, i);