All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9
@ 2017-03-21 14:12 Greg Kurz
  2017-03-21 14:12 ` [Qemu-devel] [PULL 1/2] 9pfs: don't try to flush self and avoid QEMU hang on reset Greg Kurz
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Greg Kurz @ 2017-03-21 14:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Greg Kurz

The following changes since commit 940a8ce075e3408742a4edcabfd6c2a15e2539eb:

  Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging (2017-03-20 16:34:26 +0000)

are available in the git repository at:

  https://github.com/gkurz/qemu.git tags/for-upstream

for you to fetch changes up to 262169abe74b4c2d8b299b7499904cfc3c1902ea:

  9pfs: proxy: assert if unmarshal fails (2017-03-21 09:12:47 +0100)

----------------------------------------------------------------
This pull request fixes a potential QEMU hang in 9pfs and two issues
reported by Coverity.

----------------------------------------------------------------
Greg Kurz (2):
      9pfs: don't try to flush self and avoid QEMU hang on reset
      9pfs: proxy: assert if unmarshal fails

 hw/9pfs/9p-proxy.c | 22 +++++++++++-----------
 hw/9pfs/9p.c       | 12 ++++++++----
 2 files changed, 19 insertions(+), 15 deletions(-)
-- 
2.7.4

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PULL 1/2] 9pfs: don't try to flush self and avoid QEMU hang on reset
  2017-03-21 14:12 [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Greg Kurz
@ 2017-03-21 14:12 ` Greg Kurz
  2017-03-21 14:13 ` [Qemu-devel] [PULL 2/2] 9pfs: proxy: assert if unmarshal fails Greg Kurz
  2017-03-21 15:44 ` [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Peter Maydell
  2 siblings, 0 replies; 4+ messages in thread
From: Greg Kurz @ 2017-03-21 14:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Greg Kurz

According to the 9P spec [*], when a client wants to cancel a pending I/O
request identified by a given tag (uint16), it must send a Tflush message
and wait for the server to respond with a Rflush message before reusing this
tag for another I/O. The server may still send a completion message for the
I/O if it wasn't actually cancelled but the Rflush message must arrive after
that.

QEMU hence waits for the flushed PDU to complete before sending the Rflush
message back to the client.

If a client sends 'Tflush tag oldtag' and tag == oldtag, QEMU will then
allocate a PDU identified by tag, find it in the PDU list and wait for
this same PDU to complete... i.e. wait for a completion that will never
happen. This causes a tag and ring slot leak in the guest, and a PDU
leak in QEMU, all of them limited by the maximal number of PDUs (128).
But, worse, this causes QEMU to hang on device reset since v9fs_reset()
wants to drain all pending I/O.

This insane behavior is likely to denote a bug in the client, and it would
deserve an Rerror message to be sent back. Unfortunately, the protocol
allows it and requires all flush requests to suceed (only a Tflush response
is expected).

The only option is to detect when we have to handle a self-referencing
flush request and report success to the client right away.

[*] http://man.cat-v.org/plan_9/5/flush

Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
 hw/9pfs/9p.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 76c9247c777d..b8c0b993580c 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -2353,7 +2353,7 @@ static void coroutine_fn v9fs_flush(void *opaque)
     ssize_t err;
     int16_t tag;
     size_t offset = 7;
-    V9fsPDU *cancel_pdu;
+    V9fsPDU *cancel_pdu = NULL;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
@@ -2364,9 +2364,13 @@ static void coroutine_fn v9fs_flush(void *opaque)
     }
     trace_v9fs_flush(pdu->tag, pdu->id, tag);
 
-    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
-        if (cancel_pdu->tag == tag) {
-            break;
+    if (pdu->tag == tag) {
+        error_report("Warning: the guest sent a self-referencing 9P flush request");
+    } else {
+        QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
+            if (cancel_pdu->tag == tag) {
+                break;
+            }
         }
     }
     if (cancel_pdu) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PULL 2/2] 9pfs: proxy: assert if unmarshal fails
  2017-03-21 14:12 [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Greg Kurz
  2017-03-21 14:12 ` [Qemu-devel] [PULL 1/2] 9pfs: don't try to flush self and avoid QEMU hang on reset Greg Kurz
@ 2017-03-21 14:13 ` Greg Kurz
  2017-03-21 15:44 ` [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Peter Maydell
  2 siblings, 0 replies; 4+ messages in thread
From: Greg Kurz @ 2017-03-21 14:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Greg Kurz

Replies from the virtfs proxy are made up of a fixed-size header (8 bytes)
and a payload of variable size (maximum 64kb). When receiving a reply,
the proxy backend first reads the whole header and then unmarshals it.
If the header is okay, it then does the same operation with the payload.

Since the proxy backend uses a pre-allocated buffer which has enough room
for a header and the maximum payload size, marshalling should never fail
with fixed size arguments. Any error here is likely to result from a more
serious corruption in QEMU and we'd better dump core right away.

This patch adds error checks where they are missing and converts the
associated error paths into assertions.

This should also address Coverity's complaints CID 1348519 and CID 1348520,
about not always checking the return value of proxy_unmarshal().

Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/9pfs/9p-proxy.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index f4aa7a9d70f8..28b20a7c3dfa 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -165,7 +165,8 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
         return retval;
     }
     reply->iov_len = PROXY_HDR_SZ;
-    proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
+    retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
+    assert(retval == 4 * 2);
     /*
      * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
      * return -ENOBUFS
@@ -194,9 +195,7 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
     if (header.type == T_ERROR) {
         int ret;
         ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
-        if (ret < 0) {
-            *status = ret;
-        }
+        assert(ret == 4);
         return 0;
     }
 
@@ -213,6 +212,7 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
                                  &prstat.st_atim_sec, &prstat.st_atim_nsec,
                                  &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
                                  &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
+        assert(retval == 8 * 3 + 4 * 3 + 8 * 10);
         prstat_to_stat(response, &prstat);
         break;
     }
@@ -225,6 +225,7 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
                                  &prstfs.f_files, &prstfs.f_ffree,
                                  &prstfs.f_fsid[0], &prstfs.f_fsid[1],
                                  &prstfs.f_namelen, &prstfs.f_frsize);
+        assert(retval == 8 * 11);
         prstatfs_to_statfs(response, &prstfs);
         break;
     }
@@ -246,7 +247,8 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
         break;
     }
     case T_GETVERSION:
-        proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
+        retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
+        assert(retval == 8);
         break;
     default:
         return -1;
@@ -274,18 +276,16 @@ static int v9fs_receive_status(V9fsProxy *proxy,
         return retval;
     }
     reply->iov_len = PROXY_HDR_SZ;
-    proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
-    if (header.size != sizeof(int)) {
-        *status = -ENOBUFS;
-        return 0;
-    }
+    retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
+    assert(retval == 4 * 2);
     retval = socket_read(proxy->sockfd,
                          reply->iov_base + PROXY_HDR_SZ, header.size);
     if (retval < 0) {
         return retval;
     }
     reply->iov_len += header.size;
-    proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
+    retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
+    assert(retval == 4);
     return 0;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9
  2017-03-21 14:12 [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Greg Kurz
  2017-03-21 14:12 ` [Qemu-devel] [PULL 1/2] 9pfs: don't try to flush self and avoid QEMU hang on reset Greg Kurz
  2017-03-21 14:13 ` [Qemu-devel] [PULL 2/2] 9pfs: proxy: assert if unmarshal fails Greg Kurz
@ 2017-03-21 15:44 ` Peter Maydell
  2 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2017-03-21 15:44 UTC (permalink / raw)
  To: Greg Kurz; +Cc: QEMU Developers

On 21 March 2017 at 14:12, Greg Kurz <groug@kaod.org> wrote:
> The following changes since commit 940a8ce075e3408742a4edcabfd6c2a15e2539eb:
>
>   Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging (2017-03-20 16:34:26 +0000)
>
> are available in the git repository at:
>
>   https://github.com/gkurz/qemu.git tags/for-upstream
>
> for you to fetch changes up to 262169abe74b4c2d8b299b7499904cfc3c1902ea:
>
>   9pfs: proxy: assert if unmarshal fails (2017-03-21 09:12:47 +0100)
>
> ----------------------------------------------------------------
> This pull request fixes a potential QEMU hang in 9pfs and two issues
> reported by Coverity.
>
> ----------------------------------------------------------------
> Greg Kurz (2):
>       9pfs: don't try to flush self and avoid QEMU hang on reset
>       9pfs: proxy: assert if unmarshal fails

Applied, thanks.

-- PMM

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-03-21 15:45 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-21 14:12 [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Greg Kurz
2017-03-21 14:12 ` [Qemu-devel] [PULL 1/2] 9pfs: don't try to flush self and avoid QEMU hang on reset Greg Kurz
2017-03-21 14:13 ` [Qemu-devel] [PULL 2/2] 9pfs: proxy: assert if unmarshal fails Greg Kurz
2017-03-21 15:44 ` [Qemu-devel] [PULL 0/2] 9pfs fixes 2017-03-21 for 2.9 Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.