Patchwork [1/9] char: remove watch callback on chardev detach from frontend

login
register
mail settings
Submitter Amit Shah
Date Aug. 28, 2013, 5:10 a.m.
Message ID <c56a21019baf5bcbd3019585ca6af1ff288072c3.1377666450.git.amit.shah@redhat.com>
Download mbox | patch
Permalink /patch/270329/
State New
Headers show

Comments

Amit Shah - Aug. 28, 2013, 5:10 a.m.
If a frontend device releases the chardev (via unplug), the chr handlers
are set to NULL via qdev's exit callbacks invoking
qemu_chr_add_handlers().  If the chardev had a pending operation, a
callback will be invoked, which will try to access data in the
just-released frontend, causing a NULL pointer dereference.

Ensure the callbacks are disabled when frontends release chardevs.

This was seen when a virtio-serial port was unplugged when heavy
guest->host IO was in progress (causing a callback to be registered).
In the window in which the throttling was active, unplugging ports
caused a qemu segfault.

https://bugzilla.redhat.com/show_bug.cgi?id=985205

CC: <qemu-stable@nongnu.org>
Reported-by: Sibiao Luo <sluo@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 include/sysemu/char.h | 1 +
 qemu-char.c           | 3 +++
 2 files changed, 4 insertions(+)

Patch

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 8053130..3400b04 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -69,6 +69,7 @@  struct CharDriverState {
     void (*chr_accept_input)(struct CharDriverState *chr);
     void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
     void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
+    void (*chr_detach)(struct CharDriverState *chr);
     void *opaque;
     char *label;
     char *filename;
diff --git a/qemu-char.c b/qemu-char.c
index 6259496..f27fdb6 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -203,6 +203,9 @@  void qemu_chr_add_handlers(CharDriverState *s,
 
     if (!opaque && !fd_can_read && !fd_read && !fd_event) {
         fe_open = 0;
+        if (s->handler_opaque && s->chr_detach) {
+            s->chr_detach(s);
+        }
     } else {
         fe_open = 1;
     }