From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751901AbbIQKtw (ORCPT ); Thu, 17 Sep 2015 06:49:52 -0400 Received: from mail-wi0-f172.google.com ([209.85.212.172]:37151 "EHLO mail-wi0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750792AbbIQKtv (ORCPT ); Thu, 17 Sep 2015 06:49:51 -0400 From: Dmitry Vyukov To: gregkh@linuxfoundation.org, peter@hurleysoftware.com, jslaby@suse.com, linux-kernel@vger.kernel.org Cc: jslaby@suse.cz, andreyknvl@google.com, kcc@google.com, glider@google.com, paulmck@linux.vnet.ibm.com, hboehm@google.com, Dmitry Vyukov Subject: [PATCH v4] tty: fix data race in tty_buffer_flush Date: Thu, 17 Sep 2015 12:49:39 +0200 Message-Id: <1442486979-140497-1-git-send-email-dvyukov@google.com> X-Mailer: git-send-email 2.6.0.rc0.131.gf624c3d Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org tty_buffer_flush frees not acquired buffers. As the result, for example, read of b->size in tty_buffer_free can return garbage value which will lead to a huge buffer hanging in the freelist. This is just the benignest manifestation of freeing of a not acquired object. If the object is passed to kfree, heap can be corrupted. Acquire visibility over the buffer before freeing it. The data race was found with KernelThreadSanitizer (KTSAN). Signed-off-by: Dmitry Vyukov --- v4: Corrected commit log and patch revision notes v3: Added code comment re: paired smp barrier v2: Split from 'tty: fix data races on tty_buffer.commit' Signed-off-by: Dmitry Vyukov --- drivers/tty/tty_buffer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 5a3fa89..a2a8cd0 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -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; } -- 2.6.0.rc0.131.gf624c3d