* [PATCH v5 0/3] Fix several data races in tty
@ 2015-09-17 15:17 Dmitry Vyukov
2015-09-17 15:17 ` [PATCH v5 1/3] tty: fix data race in flush_to_ldisc Dmitry Vyukov
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Dmitry Vyukov @ 2015-09-17 15:17 UTC (permalink / raw)
To: gregkh, peter, jslaby, linux-kernel
Cc: jslaby, andreyknvl, kcc, glider, paulmck, hboehm, Dmitry Vyukov
v5: Combine the 3 patches into single series
v4: Corrected commit log and patch revision notes
v3: Added code comment re: paired smp barrier
in "tty: fix data race in tty_buffer_flush"
v2: Split "tty: fix data race in tty_buffer_flush"
from "tty: fix data races on tty_buffer.commit".
Removed WRITE_ONCE when updating port->itty in
"tty: fix data race in flush_to_ldisc".
Dmitry Vyukov (3):
tty: fix data race in flush_to_ldisc
tty: fix data race in tty_buffer_flush
tty: fix data race on tty_buffer.commit
drivers/tty/tty_buffer.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
--
2.6.0.rc0.131.gf624c3d
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v5 1/3] tty: fix data race in flush_to_ldisc
2015-09-17 15:17 [PATCH v5 0/3] Fix several data races in tty Dmitry Vyukov
@ 2015-09-17 15:17 ` Dmitry Vyukov
2015-09-17 17:37 ` Peter Hurley
2015-09-17 15:17 ` [PATCH v5 2/3] tty: fix data race in tty_buffer_flush Dmitry Vyukov
2015-09-17 15:17 ` [PATCH v5 3/3] tty: fix data race on tty_buffer.commit Dmitry Vyukov
2 siblings, 1 reply; 7+ messages in thread
From: Dmitry Vyukov @ 2015-09-17 15:17 UTC (permalink / raw)
To: gregkh, peter, jslaby, linux-kernel
Cc: jslaby, andreyknvl, kcc, glider, paulmck, hboehm, Dmitry Vyukov
flush_to_ldisc reads port->itty and checks that it is not NULL,
concurrently release_tty sets port->itty to NULL. It is possible
that flush_to_ldisc loads port->itty once, ensures that it is
not NULL, but then reloads it again and uses. The second load
can already return NULL, which will cause a crash.
Use READ_ONCE to read port->itty.
The data race was found with KernelThreadSanitizer (KTSAN).
Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
---
Changed since first version:
- remove WRITE_ONCE when updating port->itty
---
drivers/tty/tty_buffer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 5a3fa89..23de97d 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -467,7 +467,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;
--
2.6.0.rc0.131.gf624c3d
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 2/3] tty: fix data race in tty_buffer_flush
2015-09-17 15:17 [PATCH v5 0/3] Fix several data races in tty Dmitry Vyukov
2015-09-17 15:17 ` [PATCH v5 1/3] tty: fix data race in flush_to_ldisc Dmitry Vyukov
@ 2015-09-17 15:17 ` Dmitry Vyukov
2015-09-17 17:38 ` Peter Hurley
2015-09-17 15:17 ` [PATCH v5 3/3] tty: fix data race on tty_buffer.commit Dmitry Vyukov
2 siblings, 1 reply; 7+ messages in thread
From: Dmitry Vyukov @ 2015-09-17 15:17 UTC (permalink / raw)
To: gregkh, peter, jslaby, linux-kernel
Cc: jslaby, andreyknvl, kcc, glider, paulmck, hboehm, Dmitry Vyukov
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 <dvyukov@google.com>
---
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 <dvyukov@google.com>
---
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
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 3/3] tty: fix data race on tty_buffer.commit
2015-09-17 15:17 [PATCH v5 0/3] Fix several data races in tty Dmitry Vyukov
2015-09-17 15:17 ` [PATCH v5 1/3] tty: fix data race in flush_to_ldisc Dmitry Vyukov
2015-09-17 15:17 ` [PATCH v5 2/3] tty: fix data race in tty_buffer_flush Dmitry Vyukov
@ 2015-09-17 15:17 ` Dmitry Vyukov
2015-09-17 17:42 ` Peter Hurley
2 siblings, 1 reply; 7+ messages in thread
From: Dmitry Vyukov @ 2015-09-17 15:17 UTC (permalink / raw)
To: gregkh, peter, jslaby, linux-kernel
Cc: jslaby, andreyknvl, kcc, glider, paulmck, hboehm, Dmitry Vyukov
Race on buffer data happens when newly committed data is
picked up by an old flush work in the following scenario:
__tty_buffer_request_room does a plain write of tail->commit,
no barriers were executed before that.
At this point flush_to_ldisc reads this new value of commit,
and reads buffer data, no barriers in between.
The committed buffer data is not necessary visible to flush_to_ldisc.
Similar bug happens when tty_schedule_flip commits data.
Update commit with smp_store_release and read commit with
smp_load_acquire, as it is commit that signals data readiness.
This is orthogonal to the existing synchronization on tty_buffer.next,
which is required to not dismiss a buffer with unconsumed data.
The data race was found with KernelThreadSanitizer (KTSAN).
Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
---
v3: Added patch revision notes
v2: Removed unrelated changed
---
drivers/tty/tty_buffer.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 5a3fa89..7ed2006 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -290,7 +290,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 +396,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);
@@ -491,7 +497,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);
--
2.6.0.rc0.131.gf624c3d
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v5 1/3] tty: fix data race in flush_to_ldisc
2015-09-17 15:17 ` [PATCH v5 1/3] tty: fix data race in flush_to_ldisc Dmitry Vyukov
@ 2015-09-17 17:37 ` Peter Hurley
0 siblings, 0 replies; 7+ messages in thread
From: Peter Hurley @ 2015-09-17 17:37 UTC (permalink / raw)
To: Dmitry Vyukov
Cc: Greg Kroah-Hartman, Jiri Slaby, Linux kernel mailing list,
Jiri Slaby, Andrey Konovalov, Kostya Serebryany,
Alexander Potapenko, Paul McKenney, Hans Boehm
On Thu, Sep 17, 2015 at 11:17 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
> flush_to_ldisc reads port->itty and checks that it is not NULL,
> concurrently release_tty sets port->itty to NULL. It is possible
> that flush_to_ldisc loads port->itty once, ensures that it is
> not NULL, but then reloads it again and uses. The second load
> can already return NULL, which will cause a crash.
>
> Use READ_ONCE to read port->itty.
>
> The data race was found with KernelThreadSanitizer (KTSAN).
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 2/3] tty: fix data race in tty_buffer_flush
2015-09-17 15:17 ` [PATCH v5 2/3] tty: fix data race in tty_buffer_flush Dmitry Vyukov
@ 2015-09-17 17:38 ` Peter Hurley
0 siblings, 0 replies; 7+ messages in thread
From: Peter Hurley @ 2015-09-17 17:38 UTC (permalink / raw)
To: Dmitry Vyukov
Cc: Greg Kroah-Hartman, Jiri Slaby, Linux kernel mailing list,
Jiri Slaby, Andrey Konovalov, Kostya Serebryany,
Alexander Potapenko, Paul McKenney, Hans Boehm
On Thu, Sep 17, 2015 at 11:17 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
> 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).
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 3/3] tty: fix data race on tty_buffer.commit
2015-09-17 15:17 ` [PATCH v5 3/3] tty: fix data race on tty_buffer.commit Dmitry Vyukov
@ 2015-09-17 17:42 ` Peter Hurley
0 siblings, 0 replies; 7+ messages in thread
From: Peter Hurley @ 2015-09-17 17:42 UTC (permalink / raw)
To: Dmitry Vyukov
Cc: Greg Kroah-Hartman, Jiri Slaby, Linux kernel mailing list,
Jiri Slaby, Andrey Konovalov, Kostya Serebryany,
Alexander Potapenko, Paul McKenney, Hans Boehm
On Thu, Sep 17, 2015 at 11:17 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
> Race on buffer data happens when newly committed data is
> picked up by an old flush work in the following scenario:
> __tty_buffer_request_room does a plain write of tail->commit,
> no barriers were executed before that.
> At this point flush_to_ldisc reads this new value of commit,
> and reads buffer data, no barriers in between.
> The committed buffer data is not necessary visible to flush_to_ldisc.
>
> Similar bug happens when tty_schedule_flip commits data.
>
> Update commit with smp_store_release and read commit with
> smp_load_acquire, as it is commit that signals data readiness.
> This is orthogonal to the existing synchronization on tty_buffer.next,
> which is required to not dismiss a buffer with unconsumed data.
>
> The data race was found with KernelThreadSanitizer (KTSAN).
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-09-17 17:42 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-17 15:17 [PATCH v5 0/3] Fix several data races in tty Dmitry Vyukov
2015-09-17 15:17 ` [PATCH v5 1/3] tty: fix data race in flush_to_ldisc Dmitry Vyukov
2015-09-17 17:37 ` Peter Hurley
2015-09-17 15:17 ` [PATCH v5 2/3] tty: fix data race in tty_buffer_flush Dmitry Vyukov
2015-09-17 17:38 ` Peter Hurley
2015-09-17 15:17 ` [PATCH v5 3/3] tty: fix data race on tty_buffer.commit Dmitry Vyukov
2015-09-17 17:42 ` Peter Hurley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).