lkml.org 
[lkml]   [2020]   [Jun]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.4 26/60] tty: hvc: Fix data abort due to race in hvc_open
    Date
    From: Raghavendra Rao Ananta <rananta@codeaurora.org>

    [ Upstream commit e2bd1dcbe1aa34ff5570b3427c530e4332ecf0fe ]

    Potentially, hvc_open() can be called in parallel when two tasks calls
    open() on /dev/hvcX. In such a scenario, if the hp->ops->notifier_add()
    callback in the function fails, where it sets the tty->driver_data to
    NULL, the parallel hvc_open() can see this NULL and cause a memory abort.
    Hence, serialize hvc_open and check if tty->private_data is NULL before
    proceeding ahead.

    The issue can be easily reproduced by launching two tasks simultaneously
    that does nothing but open() and close() on /dev/hvcX.
    For example:
    $ ./simple_open_close /dev/hvc0 & ./simple_open_close /dev/hvc0 &

    Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
    Link: https://lore.kernel.org/r/20200428032601.22127-1-rananta@codeaurora.org
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/tty/hvc/hvc_console.c | 16 ++++++++++++++--
    1 file changed, 14 insertions(+), 2 deletions(-)

    diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
    index acf6d143c753..81f23af8beca 100644
    --- a/drivers/tty/hvc/hvc_console.c
    +++ b/drivers/tty/hvc/hvc_console.c
    @@ -89,6 +89,8 @@ static LIST_HEAD(hvc_structs);
    */
    static DEFINE_SPINLOCK(hvc_structs_lock);

    +/* Mutex to serialize hvc_open */
    +static DEFINE_MUTEX(hvc_open_mutex);
    /*
    * This value is used to assign a tty->index value to a hvc_struct based
    * upon order of exposure via hvc_probe(), when we can not match it to
    @@ -333,16 +335,24 @@ static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
    */
    static int hvc_open(struct tty_struct *tty, struct file * filp)
    {
    - struct hvc_struct *hp = tty->driver_data;
    + struct hvc_struct *hp;
    unsigned long flags;
    int rc = 0;

    + mutex_lock(&hvc_open_mutex);
    +
    + hp = tty->driver_data;
    + if (!hp) {
    + rc = -EIO;
    + goto out;
    + }
    +
    spin_lock_irqsave(&hp->port.lock, flags);
    /* Check and then increment for fast path open. */
    if (hp->port.count++ > 0) {
    spin_unlock_irqrestore(&hp->port.lock, flags);
    hvc_kick();
    - return 0;
    + goto out;
    } /* else count == 0 */
    spin_unlock_irqrestore(&hp->port.lock, flags);

    @@ -371,6 +381,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
    /* Force wakeup of the polling thread */
    hvc_kick();

    +out:
    + mutex_unlock(&hvc_open_mutex);
    return rc;
    }

    --
    2.25.1
    \
     
     \ /
      Last update: 2020-06-18 03:33    [W:3.459 / U:0.132 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site