Commit 97d0c931 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull tty/serial driver fixes from Greg KH:
 "Here are a few bug fixes for the tty core that resolve reported
  issues, and some serial driver fixes as well (including the
  much-reported imx driver problem)

  All of these have been in linux-next with no reported problems"

* tag 'tty-4.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  drivers/tty: require read access for controlling terminal
  serial: 8250: add uart_config entry for PORT_RT2880
  tty: fix data race on tty_buffer.commit
  tty: fix data race in tty_buffer_flush
  tty: fix data race in flush_to_ldisc
  tty: fix stall caused by missing memory barrier in drivers/tty/n_tty.c
  serial: atmel: fix error path of probe function
  tty: don't leak cdev in tty_cdev_add()
  Revert "serial: imx: remove unbalanced clk_prepare"
parents 91dbc047 0c556271
......@@ -343,8 +343,7 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (waitqueue_active(&tty->link->read_wait))
wake_up_interruptible(&tty->link->read_wait);
wake_up_interruptible(&tty->link->read_wait);
}
}
......@@ -1382,8 +1381,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
put_tty_queue(c, ldata);
smp_store_release(&ldata->canon_head, ldata->read_head);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
return 0;
}
}
......@@ -1667,8 +1665,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
}
......@@ -1887,10 +1884,8 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
}
/* The termios change make the tty ready for I/O */
if (waitqueue_active(&tty->write_wait))
wake_up_interruptible(&tty->write_wait);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait);
}
/**
......
......@@ -261,6 +261,14 @@ configured less than Maximum supported fifo bytes */
UART_FCR7_64BYTE,
.flags = UART_CAP_FIFO,
},
[PORT_RT2880] = {
.name = "Palmchip BK-3103",
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO,
},
};
/* Uart divisor latch read */
......
......@@ -2786,7 +2786,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
ret = atmel_init_gpios(port, &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to initialize GPIOs.");
goto err;
goto err_clear_bit;
}
ret = atmel_init_port(port, pdev);
......
......@@ -1631,12 +1631,12 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
int locked = 1;
int retval;
retval = clk_prepare_enable(sport->clk_per);
retval = clk_enable(sport->clk_per);
if (retval)
return;
retval = clk_prepare_enable(sport->clk_ipg);
retval = clk_enable(sport->clk_ipg);
if (retval) {
clk_disable_unprepare(sport->clk_per);
clk_disable(sport->clk_per);
return;
}
......@@ -1675,8 +1675,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
if (locked)
spin_unlock_irqrestore(&sport->port.lock, flags);
clk_disable_unprepare(sport->clk_ipg);
clk_disable_unprepare(sport->clk_per);
clk_disable(sport->clk_ipg);
clk_disable(sport->clk_per);
}
/*
......@@ -1777,7 +1777,15 @@ imx_console_setup(struct console *co, char *options)
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
clk_disable_unprepare(sport->clk_ipg);
clk_disable(sport->clk_ipg);
if (retval) {
clk_unprepare(sport->clk_ipg);
goto error_console;
}
retval = clk_prepare(sport->clk_per);
if (retval)
clk_disable_unprepare(sport->clk_ipg);
error_console:
return retval;
......
......@@ -242,7 +242,10 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
atomic_inc(&buf->priority);
mutex_lock(&buf->lock);
while ((next = buf->head->next) != NULL) {
/* paired w/ release in __tty_buffer_request_room; ensures there are
* no pending memory accesses to the freed buffer
*/
while ((next = smp_load_acquire(&buf->head->next)) != NULL) {
tty_buffer_free(port, buf->head);
buf->head = next;
}
......@@ -290,7 +293,10 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
if (n != NULL) {
n->flags = flags;
buf->tail = n;
b->commit = b->used;
/* paired w/ acquire in flush_to_ldisc(); ensures
* flush_to_ldisc() sees buffer data.
*/
smp_store_release(&b->commit, b->used);
/* paired w/ acquire in flush_to_ldisc(); ensures the
* latest commit value can be read before the head is
* advanced to the next buffer
......@@ -393,7 +399,10 @@ void tty_schedule_flip(struct tty_port *port)
{
struct tty_bufhead *buf = &port->buf;
buf->tail->commit = buf->tail->used;
/* paired w/ acquire in flush_to_ldisc(); ensures
* flush_to_ldisc() sees buffer data.
*/
smp_store_release(&buf->tail->commit, buf->tail->used);
schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_schedule_flip);
......@@ -467,7 +476,7 @@ static void flush_to_ldisc(struct work_struct *work)
struct tty_struct *tty;
struct tty_ldisc *disc;
tty = port->itty;
tty = READ_ONCE(port->itty);
if (tty == NULL)
return;
......@@ -491,7 +500,10 @@ static void flush_to_ldisc(struct work_struct *work)
* is advancing to the next buffer
*/
next = smp_load_acquire(&head->next);
count = head->commit - head->read;
/* paired w/ release in __tty_buffer_request_room() or in
* tty_buffer_flush(); ensures we see the committed buffer data
*/
count = smp_load_acquire(&head->commit) - head->read;
if (!count) {
if (next == NULL) {
check_other_closed(tty);
......
......@@ -2128,8 +2128,24 @@ static int tty_open(struct inode *inode, struct file *filp)
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
tty->session == NULL)
__proc_set_tty(tty);
tty->session == NULL) {
/*
* Don't let a process that only has write access to the tty
* obtain the privileges associated with having a tty as
* controlling terminal (being able to reopen it with full
* access through /dev/tty, being able to perform pushback).
* Many distributions set the group of all ttys to "tty" and
* grant write-only access to all terminals for setgid tty
* binaries, which should not imply full privileges on all ttys.
*
* This could theoretically break old code that performs open()
* on a write-only file descriptor. In that case, it might be
* necessary to also permit this if
* inode_permission(inode, MAY_READ) == 0.
*/
if (filp->f_mode & FMODE_READ)
__proc_set_tty(tty);
}
spin_unlock_irq(&current->sighand->siglock);
read_unlock(&tasklist_lock);
tty_unlock(tty);
......@@ -2418,7 +2434,7 @@ static int fionbio(struct file *file, int __user *p)
* Takes ->siglock() when updating signal->tty
*/
static int tiocsctty(struct tty_struct *tty, int arg)
static int tiocsctty(struct tty_struct *tty, struct file *file, int arg)
{
int ret = 0;
......@@ -2452,6 +2468,13 @@ static int tiocsctty(struct tty_struct *tty, int arg)
goto unlock;
}
}
/* See the comment in tty_open(). */
if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) {
ret = -EPERM;
goto unlock;
}
proc_set_tty(tty);
unlock:
read_unlock(&tasklist_lock);
......@@ -2844,7 +2867,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
no_tty();
return 0;
case TIOCSCTTY:
return tiocsctty(tty, arg);
return tiocsctty(tty, file, arg);
case TIOCGPGRP:
return tiocgpgrp(tty, real_tty, p);
case TIOCSPGRP:
......@@ -3151,13 +3174,18 @@ struct class *tty_class;
static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
unsigned int index, unsigned int count)
{
int err;
/* init here, since reused cdevs cause crashes */
driver->cdevs[index] = cdev_alloc();
if (!driver->cdevs[index])
return -ENOMEM;
cdev_init(driver->cdevs[index], &tty_fops);
driver->cdevs[index]->ops = &tty_fops;
driver->cdevs[index]->owner = driver->owner;
return cdev_add(driver->cdevs[index], dev, count);
err = cdev_add(driver->cdevs[index], dev, count);
if (err)
kobject_put(&driver->cdevs[index]->kobj);
return err;
}
/**
......
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