Skip to contentSkip to conversation

tty: Correct tty buffer flush.

PATCH In review Ilya Zykov 2 participants 3 messages Dec 3, 2012 – Mar 17, 2013

Subsystems (2)
lore
Share & tools
lore

Ilya Zykov

author
#0 lore raw

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
index 6c9b7cd..4f02f9c 100644
@@ -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;
 }
 
 /**
author
#1 lore raw
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 (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 +2 -3
index 6c9b7cd..4f02f9c 100644
@@ -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.

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/tty/tty_buffer.c?id=64325a3be08d364a62ee8f84b2cf86934bc2544a

#2 lore raw
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 (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
index 6c9b7cd..4f02f9c 100644
@@ -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'