tty: Correct tty buffer flush.
Subsystems (2)
PATCH 1/1 tty: Correct tty buffer flush.
The root of problem is carelessly zeroing pointer(in function __tty_buffer_flush()),
when another thread can use it. It can be cause of "NULL pointer dereference".
Main idea of the patch, this is never release last (struct tty_buffer) in the active buffer.
Only flush data for ldisc(tty->buf.head->read = tty->buf.head->commit).
At that moment driver can collect(write) data in buffer without conflict.
It is repeat behavior of flush_to_ldisc(), only without feeding data to ldisc. Test program and bug report you can see:
https://lkml.org/lkml/2012/11/29/368
---
drivers/tty/tty_buffer.c +7 -4
@@ -114,11 +114,14 @@ static void __tty_buffer_flush(struct tty_struct *tty) {struct tty_buffer *thead; -while ((thead = tty->buf.head) !=NULL ) { - tty->buf.head = thead->next; -tty_buffer_free (tty, thead); +if (tty->buf.head ==NULL ) +return ; +while ((thead = tty->buf.head->next) !=NULL ) { +tty_buffer_free (tty, tty->buf.head); + tty->buf.head = thead; } - tty->buf.tail =NULL ; +WARN_ON (tty->buf.head != tty->buf.tail); + tty->buf.head->read = tty->buf.head->commit; }/**
Quoted 26 lines · Ilya Zykov
The root of problem is carelessly zeroing
pointer(in function __tty_buffer_flush()),
when another thread can use it. It can be cause of "NULL pointer dereference".
Main idea of the patch, this is never release last (structtty_buffer) in the active buffer.
Only flush data forldisc(tty->buf.head->read = tty->buf.head->commit).
At that moment driver can collect(write) data in buffer without conflict.
It is repeat behavior offlush_to_ldisc(), only without feeding data to ldisc. Test program and bug report you can see:
https://lkml.org/lkml/2012/11/29/368Signed-off-by Ilya Zykov <[email protected]>---
drivers/tty/tty_buffer.c +2
-3@@ -114,11 +114,14 @@ static void __tty_buffer_flush(struct tty_struct *tty) {struct tty_buffer *thead; -while ((thead = tty->buf.head) !=NULL ) { - tty->buf.head = thead->next; -tty_buffer_free (tty, thead); +if (tty->buf.head ==NULL ) +return ;
drivers/tty/tty_buffer.c static void __tty_buffer_flush(struct tty_struct *tty) · line 127
Quoted 10 lines
drivers/tty/tty_buffer.c +5
-1+while ((thead = tty->buf.head->next) !=NULL ) { +tty_buffer_free (tty, tty->buf.head); + tty->buf.head = thead; } - tty->buf.tail =NULL ; +WARN_ON (tty->buf.head != tty->buf.tail); + tty->buf.head->read = tty->buf.head->commit; }/**
You can include this patch, in 3.2 series , for improve stability, it would be merged in upstream 3.9-rc1.
Thank you.
Ilya.
Quoted 35 lines · Ilya Zykov
Quoted 34 lines · Ilya Zykov
The root of problem is carelessly zeroing
pointer(in function __tty_buffer_flush()),
when another thread can use it. It can be cause of "NULL pointer dereference".
Main idea of the patch, this is never release last (structtty_buffer) in the active buffer.
Only flush data forldisc(tty->buf.head->read = tty->buf.head->commit).
At that moment driver can collect(write) data in buffer without conflict.
It is repeat behavior offlush_to_ldisc(), only without feeding data to ldisc. Test program and bug report you can see:
https://lkml.org/lkml/2012/11/29/368Signed-off-by Ilya Zykov <[email protected]>---
drivers/tty/tty_buffer.c +7
-4@@ -114,11 +114,14 @@ static void __tty_buffer_flush(struct tty_struct *tty) {struct tty_buffer *thead; -while ((thead = tty->buf.head) !=NULL ) { - tty->buf.head = thead->next; -tty_buffer_free (tty, thead); +if (tty->buf.head ==NULL ) +return ; +while ((thead = tty->buf.head->next) !=NULL ) { +tty_buffer_free (tty, tty->buf.head); + tty->buf.head = thead; } - tty->buf.tail =NULL ; +WARN_ON (tty->buf.head != tty->buf.tail); + tty->buf.head->read = tty->buf.head->commit; }
Quoted 5 lines
drivers/tty/tty_buffer.c static void __tty_buffer_flush(struct tty_struct *tty) · line 127
Quoted 2 lines
drivers/tty/tty_buffer.c +0
-0/** You can include this patch, in 3.2 series , for improve stability, it would be merged in upstream 3.9-rc1.
Added to the queue, thanks.
Ben.
Signature · 3 lines
Ben Hutchings
Usenet is essentially a HUGE group of people passing notes in class.
- Rachel Kadel, `A Quick Guide to Newsgroup Etiquette'