If we encounter any read error in the middle of the message (including the NBD_CMD_WRITE payload), we are no longer in sync with the client and should not try to read anything further. For mid-message EOF, the problem wasn't too bad (the next iteration of the loop would also see EOF); but if it is some other error (perhaps a transient EIO due to reading from a flaky block device), not marking the connection failed could result in us trying to treat the tail of the previous partial payload as further commands. Usually a magic number mismatch would flag the problem, but we should never base our behavior on the contents of that random payload.
Signed-off-by: Eric Blake <ebl...@redhat.com> --- src/connections.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/connections.c b/src/connections.c index 0cbf54a..d0ef6a5 100644 --- a/src/connections.c +++ b/src/connections.c @@ -873,7 +873,7 @@ handle_request (struct connection *conn, return r; } -static void +static int skip_over_write_buffer (int sock, size_t count) { char buf[BUFSIZ]; @@ -883,12 +883,16 @@ skip_over_write_buffer (int sock, size_t count) r = read (sock, buf, count > BUFSIZ ? BUFSIZ : count); if (r == -1) { nbdkit_error ("skipping write buffer: %m"); - return; + return -1; + } + if (r == 0) { + nbdkit_error ("unexpected early EOF"); + errno = EBADMSG; + return -1; } - if (r == 0) - return; count -= r; } + return 0; } /* Convert a system errno to an NBD_E* error code. */ @@ -965,8 +969,9 @@ recv_request_send_reply (struct connection *conn) if (r == -1) return -1; if (r == 0) { /* request not valid */ - if (cmd == NBD_CMD_WRITE) - skip_over_write_buffer (conn->sockin, count); + if (cmd == NBD_CMD_WRITE && + skip_over_write_buffer (conn->sockin, count) < 0) + return -1; goto send_reply; } @@ -976,8 +981,9 @@ recv_request_send_reply (struct connection *conn) if (buf == NULL) { perror ("malloc"); error = ENOMEM; - if (cmd == NBD_CMD_WRITE) - skip_over_write_buffer (conn->sockin, count); + if (cmd == NBD_CMD_WRITE && + skip_over_write_buffer (conn->sockin, count) < 0) + return -1; goto send_reply; } } @@ -985,14 +991,14 @@ recv_request_send_reply (struct connection *conn) /* Receive the write data buffer. */ if (cmd == NBD_CMD_WRITE) { r = conn->recv (conn, buf, count); + if (r == 0) { + errno = EBADMSG; + r = -1; + } if (r == -1) { nbdkit_error ("read data: %m"); return -1; } - if (r == 0) { - debug ("client closed input unexpectedly, closing connection"); - return 0; /* disconnect */ - } } /* Perform the request. Only this part happens inside the request lock. */ -- 2.13.6 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs