Commit 86a7964b authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French

CIFS: Fix NULL pointer dereference in mid callback

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: ee258d79 ("CIFS: Move credit processing to mid callbacks for SMB3")
Tested-by: default avatarFrank Sorenson <sorenson@redhat.com>
Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 9150c3ad
...@@ -1524,6 +1524,7 @@ struct mid_q_entry { ...@@ -1524,6 +1524,7 @@ struct mid_q_entry {
struct TCP_Server_Info *server; /* server corresponding to this mid */ struct TCP_Server_Info *server; /* server corresponding to this mid */
__u64 mid; /* multiplex id */ __u64 mid; /* multiplex id */
__u16 credits; /* number of credits consumed by this mid */ __u16 credits; /* number of credits consumed by this mid */
__u16 credits_received; /* number of credits from the response */
__u32 pid; /* process id */ __u32 pid; /* process id */
__u32 sequence_number; /* for CIFS signing */ __u32 sequence_number; /* for CIFS signing */
unsigned long when_alloc; /* when mid was created */ unsigned long when_alloc; /* when mid was created */
......
...@@ -905,6 +905,20 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed) ...@@ -905,6 +905,20 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
spin_unlock(&GlobalMid_Lock); 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 static void
handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
char *buf, int malformed) char *buf, int malformed)
...@@ -912,6 +926,7 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, ...@@ -912,6 +926,7 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
if (server->ops->check_trans2 && if (server->ops->check_trans2 &&
server->ops->check_trans2(mid, server, buf, malformed)) server->ops->check_trans2(mid, server, buf, malformed))
return; return;
mid->credits_received = smb2_get_credits_from_hdr(buf, server);
mid->resp_buf = buf; mid->resp_buf = buf;
mid->large_buf = server->large_buf; mid->large_buf = server->large_buf;
/* Was previous buf put in mpx struct for multi-rsp? */ /* Was previous buf put in mpx struct for multi-rsp? */
......
...@@ -151,13 +151,7 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype) ...@@ -151,13 +151,7 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
static unsigned int static unsigned int
smb2_get_credits(struct mid_q_entry *mid) smb2_get_credits(struct mid_q_entry *mid)
{ {
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf; return mid->credits_received;
if (mid->mid_state == MID_RESPONSE_RECEIVED
|| mid->mid_state == MID_RESPONSE_MALFORMED)
return le16_to_cpu(shdr->CreditRequest);
return 0;
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment