CIFS: Fix null pointer deref during read resp processing
authorPavel Shilovsky <pshilov@microsoft.com>
Mon, 10 Apr 2017 17:31:33 +0000 (10:31 -0700)
committerSteve French <smfrench@gmail.com>
Tue, 11 Apr 2017 04:36:38 +0000 (23:36 -0500)
Currently during receiving a read response mid->resp_buf can be
NULL when it is being passed to cifs_discard_remaining_data() from
cifs_readv_discard(). Fix it by always passing server->smallbuf
instead and initializing mid->resp_buf at the end of read response
processing.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
CC: Stable <stable@vger.kernel.org>
Acked-by: Sachin Prabhu <sprabhu@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/smb2ops.c

index ec5e5e514fdd4a2556fa15974e869cdba5e3bd91..97e5d236d26559806ca8bc278f7c248e0579ef77 100644 (file)
@@ -79,8 +79,7 @@ extern void cifs_delete_mid(struct mid_q_entry *mid);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
                                struct mid_q_entry *mid);
-extern int cifs_discard_remaining_data(struct TCP_Server_Info *server,
-                                      char *buf);
+extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
                        struct smb_rqst *rqst,
                        mid_receive_t *receive, mid_callback_t *callback,
index 967b92631807a95786a264acf80833f0e0dbb147..5d21f00ae341b4ec002eb33dd79c7a16a1e1dfa4 100644 (file)
@@ -1400,9 +1400,9 @@ openRetry:
  * current bigbuf.
  */
 int
-cifs_discard_remaining_data(struct TCP_Server_Info *server, char *buf)
+cifs_discard_remaining_data(struct TCP_Server_Info *server)
 {
-       unsigned int rfclen = get_rfc1002_length(buf);
+       unsigned int rfclen = get_rfc1002_length(server->smallbuf);
        int remaining = rfclen + 4 - server->total_read;
 
        while (remaining > 0) {
@@ -1426,8 +1426,10 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        int length;
        struct cifs_readdata *rdata = mid->callback_data;
 
-       length = cifs_discard_remaining_data(server, mid->resp_buf);
+       length = cifs_discard_remaining_data(server);
        dequeue_mid(mid, rdata->result);
+       mid->resp_buf = server->smallbuf;
+       server->smallbuf = NULL;
        return length;
 }
 
@@ -1459,7 +1461,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        if (server->ops->is_status_pending &&
            server->ops->is_status_pending(buf, server, 0)) {
-               cifs_discard_remaining_data(server, buf);
+               cifs_discard_remaining_data(server);
                return -1;
        }
 
@@ -1519,9 +1521,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
                 rdata->iov[0].iov_base, server->total_read);
 
-       mid->resp_buf = server->smallbuf;
-       server->smallbuf = NULL;
-
        /* how much data is in the response? */
        data_len = server->ops->read_data_length(buf);
        if (data_offset + data_len > buflen) {
@@ -1544,6 +1543,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                return cifs_readv_discard(server, mid);
 
        dequeue_mid(mid, false);
+       mid->resp_buf = server->smallbuf;
+       server->smallbuf = NULL;
        return length;
 }
 
index 7b12a727947efc48df3ce8ea7698936d0702da21..152e37f2ad9213462a2ae439296a6edb49d653f9 100644 (file)
@@ -2195,7 +2195,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
        if (rc)
                goto free_pages;
 
-       rc = cifs_discard_remaining_data(server, buf);
+       rc = cifs_discard_remaining_data(server);
        if (rc)
                goto free_pages;
 
@@ -2221,7 +2221,7 @@ free_pages:
        kfree(pages);
        return rc;
 discard_data:
-       cifs_discard_remaining_data(server, buf);
+       cifs_discard_remaining_data(server);
        goto free_pages;
 }