From: Greg Kroah-Hartman Date: Mon, 12 Aug 2013 04:31:25 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.0.91~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7a12ddcaa45dbce6591891e26f0a77d7cddffe4c;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: virtio-console-add-pipe_lock-unlock-for-splice_write.patch virtio-console-clean-up-port-data-immediately-at-time-of-unplug.patch virtio-console-fix-race-in-port_fops_open-and-port-unplug.patch virtio-console-fix-race-with-port-unplug-and-open-close.patch virtio-console-fix-raising-sigio-after-port-unplug.patch virtio-console-quit-from-splice_write-if-pipe-nrbufs-is-0.patch virtio-console-return-enodev-on-all-read-operations-after-unplug.patch --- diff --git a/queue-3.10/series b/queue-3.10/series index cc294a6de62..86eb0a22910 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -29,3 +29,10 @@ btrfs-release-both-paths-before-logging-dir-changed-extents.patch lockd-don-t-call-utsname-nodename-from-nlmclnt_setlockargs.patch sunrpc-don-t-auto-disconnect-from-the-local-rpcbind-socket.patch sunrpc-if-the-rpcbind-channel-is-disconnected-fail-the-call-to-unregister.patch +virtio-console-quit-from-splice_write-if-pipe-nrbufs-is-0.patch +virtio-console-add-pipe_lock-unlock-for-splice_write.patch +virtio-console-fix-race-with-port-unplug-and-open-close.patch +virtio-console-fix-race-in-port_fops_open-and-port-unplug.patch +virtio-console-clean-up-port-data-immediately-at-time-of-unplug.patch +virtio-console-fix-raising-sigio-after-port-unplug.patch +virtio-console-return-enodev-on-all-read-operations-after-unplug.patch diff --git a/queue-3.10/virtio-console-add-pipe_lock-unlock-for-splice_write.patch b/queue-3.10/virtio-console-add-pipe_lock-unlock-for-splice_write.patch new file mode 100644 index 00000000000..7b137cf03b4 --- /dev/null +++ b/queue-3.10/virtio-console-add-pipe_lock-unlock-for-splice_write.patch @@ -0,0 +1,141 @@ +From 2b4fbf029dff5a28d9bf646346dea891ec43398a Mon Sep 17 00:00:00 2001 +From: Yoshihiro YUNOMAE +Date: Tue, 23 Jul 2013 11:30:49 +0930 +Subject: virtio/console: Add pipe_lock/unlock for splice_write + +From: Yoshihiro YUNOMAE + +commit 2b4fbf029dff5a28d9bf646346dea891ec43398a upstream. + +Add pipe_lock/unlock for splice_write to avoid oops by following competition: + +(1) An application gets fds of a trace buffer, virtio-serial, pipe. +(2) The application does fork() +(3) The processes execute splice_read(trace buffer) and + splice_write(virtio-serial) via same pipe. + + + get fds of a trace buffer, + virtio-serial, pipe + | + fork()----------create--------+ + | | + splice(read) | ---+ + splice(write) | +-- no competition + | splice(read) | + | splice(write) ---+ + | | + splice(read) | + splice(write) splice(read) ------ competition + | splice(write) + +Two processes share a pipe_inode_info structure. If the child execute +splice(read) when the parent tries to execute splice(write), the +structure can be broken. Existing virtio-serial driver does not get +lock for the structure in splice_write, so this competition will induce +oops. + + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 + IP: [] splice_from_pipe_feed+0x6f/0x130 + PGD 7223e067 PUD 72391067 PMD 0 + Oops: 0000 [#1] SMP + Modules linked in: lockd bnep bluetooth rfkill sunrpc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_page_alloc snd_timer snd soundcore pcspkr virtio_net virtio_balloon i2c_piix4 i2c_core microcode uinput floppy + CPU: 0 PID: 1072 Comm: compete-test Not tainted 3.10.0ws+ #55 + Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 + task: ffff880071b98000 ti: ffff88007b55e000 task.ti: ffff88007b55e000 + RIP: 0010:[] [] splice_from_pipe_feed+0x6f/0x130 + RSP: 0018:ffff88007b55fd78 EFLAGS: 00010287 + RAX: 0000000000000000 RBX: ffff88007b55fe20 RCX: 0000000000000000 + RDX: 0000000000001000 RSI: ffff88007a95ba30 RDI: ffff880036f9e6c0 + RBP: ffff88007b55fda8 R08: 00000000000006ec R09: ffff880077626708 + R10: 0000000000000003 R11: ffffffff8139ca59 R12: ffff88007a95ba30 + R13: 0000000000000000 R14: ffffffff8139dd00 R15: ffff880036f9e6c0 + FS: 00007f2e2e3a0740(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b + CR2: 0000000000000018 CR3: 0000000071bd1000 CR4: 00000000000006f0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 + Stack: + ffffffff8139ca59 ffff88007b55fe20 ffff880036f9e6c0 ffffffff8139dd00 + ffff8800776266c0 ffff880077626708 ffff88007b55fde8 ffffffff811a6e8e + ffff88007b55fde8 ffffffff8139ca59 ffff880036f9e6c0 ffff88007b55fe20 + Call Trace: + [] ? alloc_buf.isra.13+0x39/0xb0 + [] ? virtcons_restore+0x100/0x100 + [] __splice_from_pipe+0x7e/0x90 + [] ? alloc_buf.isra.13+0x39/0xb0 + [] port_fops_splice_write+0xe9/0x140 + [] ? selinux_file_permission+0xc4/0x120 + [] ? wait_port_writable+0x1b0/0x1b0 + [] do_splice_from+0xa0/0x110 + [] SyS_splice+0x5ff/0x6b0 + [] tracesys+0xdd/0xe2 + Code: 49 8b 87 80 00 00 00 4c 8d 24 d0 8b 53 04 41 8b 44 24 0c 4d 8b 6c 24 10 39 d0 89 03 76 02 89 13 49 8b 44 24 10 4c 89 e6 4c 89 ff 50 18 85 c0 0f 85 aa 00 00 00 48 89 da 4c 89 e6 4c 89 ff 41 + RIP [] splice_from_pipe_feed+0x6f/0x130 + RSP + CR2: 0000000000000018 + ---[ end trace 24572beb7764de59 ]--- + +V2: Fix a locking problem for error +V3: Add Reviewed-by lines and stable@ line in sign-off area + +Signed-off-by: Yoshihiro YUNOMAE +Reviewed-by: Amit Shah +Reviewed-by: Masami Hiramatsu +Cc: Amit Shah +Cc: Arnd Bergmann +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -936,16 +936,21 @@ static ssize_t port_fops_splice_write(st + * pipe->nrbufs == 0 means there are no data to transfer, + * so this returns just 0 for no data. + */ +- if (!pipe->nrbufs) +- return 0; ++ pipe_lock(pipe); ++ if (!pipe->nrbufs) { ++ ret = 0; ++ goto error_out; ++ } + + ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); + if (ret < 0) +- return ret; ++ goto error_out; + + buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); +- if (!buf) +- return -ENOMEM; ++ if (!buf) { ++ ret = -ENOMEM; ++ goto error_out; ++ } + + sgl.n = 0; + sgl.len = 0; +@@ -953,12 +958,17 @@ static ssize_t port_fops_splice_write(st + sgl.sg = buf->sg; + sg_init_table(sgl.sg, sgl.size); + ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); ++ pipe_unlock(pipe); + if (likely(ret > 0)) + ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true); + + if (unlikely(ret <= 0)) + free_buf(buf, true); + return ret; ++ ++error_out: ++ pipe_unlock(pipe); ++ return ret; + } + + static unsigned int port_fops_poll(struct file *filp, poll_table *wait) diff --git a/queue-3.10/virtio-console-clean-up-port-data-immediately-at-time-of-unplug.patch b/queue-3.10/virtio-console-clean-up-port-data-immediately-at-time-of-unplug.patch new file mode 100644 index 00000000000..4210f588195 --- /dev/null +++ b/queue-3.10/virtio-console-clean-up-port-data-immediately-at-time-of-unplug.patch @@ -0,0 +1,126 @@ +From ea3768b4386a8d1790f4cc9a35de4f55b92d6442 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 29 Jul 2013 14:20:29 +0930 +Subject: virtio: console: clean up port data immediately at time of unplug + +From: Amit Shah + +commit ea3768b4386a8d1790f4cc9a35de4f55b92d6442 upstream. + +We used to keep the port's char device structs and the /sys entries +around till the last reference to the port was dropped. This is +actually unnecessary, and resulted in buggy behaviour: + +1. Open port in guest +2. Hot-unplug port +3. Hot-plug a port with the same 'name' property as the unplugged one + +This resulted in hot-plug being unsuccessful, as a port with the same +name already exists (even though it was unplugged). + +This behaviour resulted in a warning message like this one: + +-------------------8<--------------------------------------- +WARNING: at fs/sysfs/dir.c:512 sysfs_add_one+0xc9/0x130() (Not tainted) +Hardware name: KVM +sysfs: cannot create duplicate filename +'/devices/pci0000:00/0000:00:04.0/virtio0/virtio-ports/vport0p1' + +Call Trace: + [] ? warn_slowpath_common+0x87/0xc0 + [] ? warn_slowpath_fmt+0x46/0x50 + [] ? sysfs_add_one+0xc9/0x130 + [] ? create_dir+0x68/0xb0 + [] ? sysfs_create_dir+0x39/0x50 + [] ? kobject_add_internal+0xb9/0x260 + [] ? kobject_add_varg+0x38/0x60 + [] ? kobject_add+0x44/0x70 + [] ? get_device_parent+0xf4/0x1d0 + [] ? device_add+0xc9/0x650 + +-------------------8<--------------------------------------- + +Instead of relying on guest applications to release all references to +the ports, we should go ahead and unregister the port from all the core +layers. Any open/read calls on the port will then just return errors, +and an unplug/plug operation on the host will succeed as expected. + +This also caused buggy behaviour in case of the device removal (not just +a port): when the device was removed (which means all ports on that +device are removed automatically as well), the ports with active +users would clean up only when the last references were dropped -- and +it would be too late then to be referencing char device pointers, +resulting in oopses: + +-------------------8<--------------------------------------- +PID: 6162 TASK: ffff8801147ad500 CPU: 0 COMMAND: "cat" + #0 [ffff88011b9d5a90] machine_kexec at ffffffff8103232b + #1 [ffff88011b9d5af0] crash_kexec at ffffffff810b9322 + #2 [ffff88011b9d5bc0] oops_end at ffffffff814f4a50 + #3 [ffff88011b9d5bf0] die at ffffffff8100f26b + #4 [ffff88011b9d5c20] do_general_protection at ffffffff814f45e2 + #5 [ffff88011b9d5c50] general_protection at ffffffff814f3db5 + [exception RIP: strlen+2] + RIP: ffffffff81272ae2 RSP: ffff88011b9d5d00 RFLAGS: 00010246 + RAX: 0000000000000000 RBX: ffff880118901c18 RCX: 0000000000000000 + RDX: ffff88011799982c RSI: 00000000000000d0 RDI: 3a303030302f3030 + RBP: ffff88011b9d5d38 R8: 0000000000000006 R9: ffffffffa0134500 + R10: 0000000000001000 R11: 0000000000001000 R12: ffff880117a1cc10 + R13: 00000000000000d0 R14: 0000000000000017 R15: ffffffff81aff700 + ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 + #6 [ffff88011b9d5d00] kobject_get_path at ffffffff8126dc5d + #7 [ffff88011b9d5d40] kobject_uevent_env at ffffffff8126e551 + #8 [ffff88011b9d5dd0] kobject_uevent at ffffffff8126e9eb + #9 [ffff88011b9d5de0] device_del at ffffffff813440c7 + +-------------------8<--------------------------------------- + +So clean up when we have all the context, and all that's left to do when +the references to the port have dropped is to free up the port struct +itself. + +Reported-by: chayang +Reported-by: YOGANANTH SUBRAMANIAN +Reported-by: FuXiangChun +Reported-by: Qunfang Zhang +Reported-by: Sibiao Luo +Signed-off-by: Amit Shah +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1518,14 +1518,6 @@ static void remove_port(struct kref *kre + + port = container_of(kref, struct port, kref); + +- sysfs_remove_group(&port->dev->kobj, &port_attribute_group); +- device_destroy(pdrvdata.class, port->dev->devt); +- cdev_del(port->cdev); +- +- kfree(port->name); +- +- debugfs_remove(port->debugfs_file); +- + kfree(port); + } + +@@ -1583,6 +1575,14 @@ static void unplug_port(struct port *por + */ + port->portdev = NULL; + ++ sysfs_remove_group(&port->dev->kobj, &port_attribute_group); ++ device_destroy(pdrvdata.class, port->dev->devt); ++ cdev_del(port->cdev); ++ ++ kfree(port->name); ++ ++ debugfs_remove(port->debugfs_file); ++ + /* + * Locks around here are not necessary - a port can't be + * opened after we removed the port struct from ports_list diff --git a/queue-3.10/virtio-console-fix-race-in-port_fops_open-and-port-unplug.patch b/queue-3.10/virtio-console-fix-race-in-port_fops_open-and-port-unplug.patch new file mode 100644 index 00000000000..4c4488edb20 --- /dev/null +++ b/queue-3.10/virtio-console-fix-race-in-port_fops_open-and-port-unplug.patch @@ -0,0 +1,40 @@ +From 671bdea2b9f210566610603ecbb6584c8a201c8c Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 29 Jul 2013 14:17:13 +0930 +Subject: virtio: console: fix race in port_fops_open() and port unplug + +From: Amit Shah + +commit 671bdea2b9f210566610603ecbb6584c8a201c8c upstream. + +Between open() being called and processed, the port can be unplugged. +Check if this happened, and bail out. + +A simple test script to reproduce this is: + +while true; do for i in $(seq 1 100); do echo $i > /dev/vport0p3; done; done; + +This opens and closes the port a lot of times; unplugging the port while +this is happening triggers the bug. + +Signed-off-by: Amit Shah +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1041,6 +1041,10 @@ static int port_fops_open(struct inode * + + /* We get the port with a kref here */ + port = find_port_by_devt(cdev->dev); ++ if (!port) { ++ /* Port was unplugged before we could proceed */ ++ return -ENXIO; ++ } + filp->private_data = port; + + /* diff --git a/queue-3.10/virtio-console-fix-race-with-port-unplug-and-open-close.patch b/queue-3.10/virtio-console-fix-race-with-port-unplug-and-open-close.patch new file mode 100644 index 00000000000..b1f3f860754 --- /dev/null +++ b/queue-3.10/virtio-console-fix-race-with-port-unplug-and-open-close.patch @@ -0,0 +1,57 @@ +From 057b82be3ca3d066478e43b162fc082930a746c9 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 29 Jul 2013 14:16:13 +0930 +Subject: virtio: console: fix race with port unplug and open/close + +From: Amit Shah + +commit 057b82be3ca3d066478e43b162fc082930a746c9 upstream. + +There's a window between find_port_by_devt() returning a port and us +taking a kref on the port, where the port could get unplugged. Fix it +by taking the reference in find_port_by_devt() itself. + +Problem reported and analyzed by Mateusz Guzik. + +Reported-by: Mateusz Guzik +Signed-off-by: Amit Shah +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -272,9 +272,12 @@ static struct port *find_port_by_devt_in + unsigned long flags; + + spin_lock_irqsave(&portdev->ports_lock, flags); +- list_for_each_entry(port, &portdev->ports, list) +- if (port->cdev->dev == dev) ++ list_for_each_entry(port, &portdev->ports, list) { ++ if (port->cdev->dev == dev) { ++ kref_get(&port->kref); + goto out; ++ } ++ } + port = NULL; + out: + spin_unlock_irqrestore(&portdev->ports_lock, flags); +@@ -1036,14 +1039,10 @@ static int port_fops_open(struct inode * + struct port *port; + int ret; + ++ /* We get the port with a kref here */ + port = find_port_by_devt(cdev->dev); + filp->private_data = port; + +- /* Prevent against a port getting hot-unplugged at the same time */ +- spin_lock_irq(&port->portdev->ports_lock); +- kref_get(&port->kref); +- spin_unlock_irq(&port->portdev->ports_lock); +- + /* + * Don't allow opening of console port devices -- that's done + * via /dev/hvc diff --git a/queue-3.10/virtio-console-fix-raising-sigio-after-port-unplug.patch b/queue-3.10/virtio-console-fix-raising-sigio-after-port-unplug.patch new file mode 100644 index 00000000000..6437f2e2594 --- /dev/null +++ b/queue-3.10/virtio-console-fix-raising-sigio-after-port-unplug.patch @@ -0,0 +1,46 @@ +From 92d3453815fbe74d539c86b60dab39ecdf01bb99 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 29 Jul 2013 14:21:32 +0930 +Subject: virtio: console: fix raising SIGIO after port unplug + +From: Amit Shah + +commit 92d3453815fbe74d539c86b60dab39ecdf01bb99 upstream. + +SIGIO should be sent when a port gets unplugged. It should only be sent +to prcesses that have the port opened, and have asked for SIGIO to be +delivered. We were clearing out guest_connected before calling +send_sigio_to_port(), resulting in a sigio not getting sent to +processes. + +Fix by setting guest_connected to false after invoking the sigio +function. + +Signed-off-by: Amit Shah +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1551,12 +1551,14 @@ static void unplug_port(struct port *por + spin_unlock_irq(&port->portdev->ports_lock); + + if (port->guest_connected) { ++ /* Let the app know the port is going down. */ ++ send_sigio_to_port(port); ++ ++ /* Do this after sigio is actually sent */ + port->guest_connected = false; + port->host_connected = false; +- wake_up_interruptible(&port->waitqueue); + +- /* Let the app know the port is going down. */ +- send_sigio_to_port(port); ++ wake_up_interruptible(&port->waitqueue); + } + + if (is_console_port(port)) { diff --git a/queue-3.10/virtio-console-quit-from-splice_write-if-pipe-nrbufs-is-0.patch b/queue-3.10/virtio-console-quit-from-splice_write-if-pipe-nrbufs-is-0.patch new file mode 100644 index 00000000000..45e77ea616f --- /dev/null +++ b/queue-3.10/virtio-console-quit-from-splice_write-if-pipe-nrbufs-is-0.patch @@ -0,0 +1,96 @@ +From 68c034fefe20eaf7d5569aae84584b07987ce50a Mon Sep 17 00:00:00 2001 +From: Yoshihiro YUNOMAE +Date: Tue, 23 Jul 2013 11:30:49 +0930 +Subject: virtio/console: Quit from splice_write if pipe->nrbufs is 0 + +From: Yoshihiro YUNOMAE + +commit 68c034fefe20eaf7d5569aae84584b07987ce50a upstream. + +Quit from splice_write if pipe->nrbufs is 0 for avoiding oops in virtio-serial. + +When an application was doing splice from a kernel buffer to virtio-serial on +a guest, the application received signal(SIGINT). This situation will normally +happen, but the kernel executed a kernel panic by oops as follows: + + BUG: unable to handle kernel paging request at ffff882071c8ef28 + IP: [] sg_init_table+0x2f/0x50 + PGD 1fac067 PUD 0 + Oops: 0000 [#1] SMP + Modules linked in: lockd sunrpc bnep bluetooth rfkill ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_page_alloc snd_timer snd microcode virtio_balloon virtio_net pcspkr soundcore i2c_piix4 i2c_core uinput floppy + CPU: 1 PID: 908 Comm: trace-cmd Not tainted 3.10.0+ #49 + Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 + task: ffff880071c64650 ti: ffff88007bf24000 task.ti: ffff88007bf24000 + RIP: 0010:[] [] sg_init_table+0x2f/0x50 + RSP: 0018:ffff88007bf25dd8 EFLAGS: 00010286 + RAX: 0000001fffffffe0 RBX: ffff882071c8ef28 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880071c8ef48 + RBP: ffff88007bf25de8 R08: ffff88007fd15d40 R09: ffff880071c8ef48 + R10: ffffea0001c71040 R11: ffffffff8139c555 R12: 0000000000000000 + R13: ffff88007506a3c0 R14: ffff88007c862500 R15: ffff880071c8ef00 + FS: 00007f0a3646c740(0000) GS:ffff88007fd00000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: ffff882071c8ef28 CR3: 000000007acbb000 CR4: 00000000000006e0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 + Stack: + ffff880071c8ef48 ffff88007bf25e20 ffff88007bf25e88 ffffffff8139d6fa + ffff88007bf25e28 ffffffff8127a3f4 0000000000000000 0000000000000000 + ffff880071c8ef48 0000100000000000 0000000000000003 ffff88007bf25e08 + Call Trace: + [] port_fops_splice_write+0xaa/0x130 + [] ? selinux_file_permission+0xc4/0x120 + [] ? wait_port_writable+0x1b0/0x1b0 + [] do_splice_from+0xa0/0x110 + [] SyS_splice+0x5ff/0x6b0 + [] system_call_fastpath+0x16/0x1b + Code: c1 e2 05 48 89 e5 48 83 ec 10 4c 89 65 f8 41 89 f4 31 f6 48 89 5d f0 48 89 fb e8 8d ce ff ff 41 8d 44 24 ff 48 c1 e0 05 48 01 c3 <48> 8b 03 48 83 e0 fe 48 83 c8 02 48 89 03 48 8b 5d f0 4c 8b 65 + RIP [] sg_init_table+0x2f/0x50 + RSP + CR2: ffff882071c8ef28 + ---[ end trace 86323505eb42ea8f ]--- + +It seems to induce pagefault in sg_init_tabel() when pipe->nrbufs is equal to +zero. This may happen in a following situation: + +(1) The application normally does splice(read) from a kernel buffer, then does + splice(write) to virtio-serial. +(2) The application receives SIGINT when is doing splice(read), so splice(read) + is failed by EINTR. However, the application does not finish the operation. +(3) The application tries to do splice(write) without pipe->nrbufs. +(4) The virtio-console driver tries to touch scatterlist structure sgl in + sg_init_table(), but the region is out of bound. + +To avoid the case, a kernel should check whether pipe->nrbufs is empty or not +when splice_write is executed in the virtio-console driver. + +V3: Add Reviewed-by lines and stable@ line in sign-off area. + +Signed-off-by: Yoshihiro YUNOMAE +Reviewed-by: Amit Shah +Reviewed-by: Masami Hiramatsu +Cc: Amit Shah +Cc: Arnd Bergmann +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -932,6 +932,13 @@ static ssize_t port_fops_splice_write(st + if (is_rproc_serial(port->out_vq->vdev)) + return -EINVAL; + ++ /* ++ * pipe->nrbufs == 0 means there are no data to transfer, ++ * so this returns just 0 for no data. ++ */ ++ if (!pipe->nrbufs) ++ return 0; ++ + ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); + if (ret < 0) + return ret; diff --git a/queue-3.10/virtio-console-return-enodev-on-all-read-operations-after-unplug.patch b/queue-3.10/virtio-console-return-enodev-on-all-read-operations-after-unplug.patch new file mode 100644 index 00000000000..2fe2694303a --- /dev/null +++ b/queue-3.10/virtio-console-return-enodev-on-all-read-operations-after-unplug.patch @@ -0,0 +1,50 @@ +From 96f97a83910cdb9d89d127c5ee523f8fc040a804 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 29 Jul 2013 14:23:21 +0930 +Subject: virtio: console: return -ENODEV on all read operations after unplug + +From: Amit Shah + +commit 96f97a83910cdb9d89d127c5ee523f8fc040a804 upstream. + +If a port gets unplugged while a user is blocked on read(), -ENODEV is +returned. However, subsequent read()s returned 0, indicating there's no +host-side connection (but not indicating the device went away). + +This also happened when a port was unplugged and the user didn't have +any blocking operation pending. If the user didn't monitor the SIGIO +signal, they won't have a chance to find out if the port went away. + +Fix by returning -ENODEV on all read()s after the port gets unplugged. +write() already behaves this way. + +Signed-off-by: Amit Shah +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/virtio_console.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -749,6 +749,10 @@ static ssize_t port_fops_read(struct fil + + port = filp->private_data; + ++ /* Port is hot-unplugged. */ ++ if (!port->guest_connected) ++ return -ENODEV; ++ + if (!port_has_data(port)) { + /* + * If nothing's connected on the host just return 0 in +@@ -765,7 +769,7 @@ static ssize_t port_fops_read(struct fil + if (ret < 0) + return ret; + } +- /* Port got hot-unplugged. */ ++ /* Port got hot-unplugged while we were waiting above. */ + if (!port->guest_connected) + return -ENODEV; + /*