]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
CIFS: Fix NULL pointer dereference in mid callback
authorPavel Shilovsky <pshilov@microsoft.com>
Thu, 21 Nov 2019 19:35:13 +0000 (11:35 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 21 Dec 2019 10:04:46 +0000 (11:04 +0100)
commit 86a7964be7afaf3df6b64faaa10a7032d2444e51 upstream.

There is a race between a system call processing thread
and the demultiplex thread when mid->resp_buf becomes NULL
and later is being accessed to get credits. It happens when
the 1st thread wakes up before a mid callback is called in
the 2nd one but the mid state has already been set to
MID_RESPONSE_RECEIVED. This causes NULL pointer dereference
in mid callback.

Fix this by saving credits from the response before we
update the mid state and then use this value in the mid
callback rather then accessing a response buffer.

Cc: Stable <stable@vger.kernel.org>
Fixes: ee258d79159afed5 ("CIFS: Move credit processing to mid callbacks for SMB3")
Tested-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/smb2ops.c

index d78bfcc191560804b694b965a381b21f7b5962f2..5d2dd04b55a6bbe616dccdaebc8414410e4cb100 100644 (file)
@@ -1524,6 +1524,7 @@ struct mid_q_entry {
        struct TCP_Server_Info *server; /* server corresponding to this mid */
        __u64 mid;              /* multiplex id */
        __u16 credits;          /* number of credits consumed by this mid */
+       __u16 credits_received; /* number of credits from the response */
        __u32 pid;              /* process id */
        __u32 sequence_number;  /* for CIFS signing */
        unsigned long when_alloc;  /* when mid was created */
index 2dd2b63992dd8aa1980df251c436c4ac3619496e..a7a026795bc2c4f470359c60da9545263feeb536 100644 (file)
@@ -905,6 +905,20 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
        spin_unlock(&GlobalMid_Lock);
 }
 
+static unsigned int
+smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
+{
+       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
+
+       /*
+        * SMB1 does not use credits.
+        */
+       if (server->vals->header_preamble_size)
+               return 0;
+
+       return le16_to_cpu(shdr->CreditRequest);
+}
+
 static void
 handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
           char *buf, int malformed)
@@ -912,6 +926,7 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
        if (server->ops->check_trans2 &&
            server->ops->check_trans2(mid, server, buf, malformed))
                return;
+       mid->credits_received = smb2_get_credits_from_hdr(buf, server);
        mid->resp_buf = buf;
        mid->large_buf = server->large_buf;
        /* Was previous buf put in mpx struct for multi-rsp? */
index cd55af9b7cc5aca5669fb53018efb0ea29494bff..b5c1cba3e6a17c6b3bce6a2be53b2cf7c904456c 100644 (file)
@@ -151,13 +151,7 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
 static unsigned int
 smb2_get_credits(struct mid_q_entry *mid)
 {
-       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf;
-
-       if (mid->mid_state == MID_RESPONSE_RECEIVED
-           || mid->mid_state == MID_RESPONSE_MALFORMED)
-               return le16_to_cpu(shdr->CreditRequest);
-
-       return 0;
+       return mid->credits_received;
 }
 
 static int