| From 1c728719a4da6e654afb9cc047164755072ed7c9 Mon Sep 17 00:00:00 2001 |
| From: Pawel Wieczorkiewicz <wipawel@amazon.de> |
| Date: Mon, 14 Dec 2020 10:25:57 +0100 |
| Subject: xen-blkback: set ring->xenblkd to NULL after kthread_stop() |
| |
| From: Pawel Wieczorkiewicz <wipawel@amazon.de> |
| |
| commit 1c728719a4da6e654afb9cc047164755072ed7c9 upstream. |
| |
| When xen_blkif_disconnect() is called, the kernel thread behind the |
| block interface is stopped by calling kthread_stop(ring->xenblkd). |
| The ring->xenblkd thread pointer being non-NULL determines if the |
| thread has been already stopped. |
| Normally, the thread's function xen_blkif_schedule() sets the |
| ring->xenblkd to NULL, when the thread's main loop ends. |
| |
| However, when the thread has not been started yet (i.e. |
| wake_up_process() has not been called on it), the xen_blkif_schedule() |
| function would not be called yet. |
| |
| In such case the kthread_stop() call returns -EINTR and the |
| ring->xenblkd remains dangling. |
| When this happens, any consecutive call to xen_blkif_disconnect (for |
| example in frontend_changed() callback) leads to a kernel crash in |
| kthread_stop() (e.g. NULL pointer dereference in exit_creds()). |
| |
| This is XSA-350. |
| |
| Cc: <stable@vger.kernel.org> # 4.12 |
| Fixes: a24fa22ce22a ("xen/blkback: don't use xen_blkif_get() in xen-blkback kthread") |
| Reported-by: Olivier Benjamin <oliben@amazon.com> |
| Reported-by: Pawel Wieczorkiewicz <wipawel@amazon.de> |
| Signed-off-by: Pawel Wieczorkiewicz <wipawel@amazon.de> |
| Reviewed-by: Julien Grall <jgrall@amazon.com> |
| Reviewed-by: Juergen Gross <jgross@suse.com> |
| Signed-off-by: Juergen Gross <jgross@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/block/xen-blkback/xenbus.c | 1 + |
| 1 file changed, 1 insertion(+) |
| |
| --- a/drivers/block/xen-blkback/xenbus.c |
| +++ b/drivers/block/xen-blkback/xenbus.c |
| @@ -274,6 +274,7 @@ static int xen_blkif_disconnect(struct x |
| |
| if (ring->xenblkd) { |
| kthread_stop(ring->xenblkd); |
| + ring->xenblkd = NULL; |
| wake_up(&ring->shutdown_wq); |
| } |
| |