• Peter Hurley's avatar
    tty: Fix lockless tty buffer race · 62a0d8d7
    Peter Hurley authored
    Commit 6a20dbd6,
    "tty: Fix race condition between __tty_buffer_request_room and flush_to_ldisc"
    correctly identifies an unsafe race condition between
    __tty_buffer_request_room() and flush_to_ldisc(), where the consumer
    flush_to_ldisc() prematurely advances the head before consuming the
    last of the data committed. For example:
    
               CPU 0                     |            CPU 1
    __tty_buffer_request_room            | flush_to_ldisc
      ...                                |   ...
                                         |   count = head->commit - head->read
      n = tty_buffer_alloc()             |
      b->commit = b->used                |
      b->next = n                        |
                                         |   if (!count)                /* T */
                                         |     if (head->next == NULL)  /* F */
                                         |     buf->head = head->next
    
    In this case, buf->head has been advanced but head->commit may have
    been updated with a new value.
    
    Instead of reintroducing an unnecessary lock, fix the race locklessly.
    Read the commit-next pair in the reverse order of writing, which guarantees
    the commit value read is the latest value written if the head is
    advancing.
    Reported-by: default avatarManfred Schlaegl <manfred.schlaegl@gmx.at>
    Cc: <stable@vger.kernel.org> # 3.12.x+
    Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    62a0d8d7
tty_buffer.c 13.9 KB