| From 364b799b15fd0a686507105885c01c54fcbf6f76 Mon Sep 17 00:00:00 2001 |
| From: Pavel Shilovsky <pshilov@microsoft.com> |
| Date: Thu, 21 Nov 2019 11:35:13 -0800 |
| Subject: [PATCH] CIFS: Fix NULL pointer dereference in mid callback |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h |
| index 7b98889d4308..507c5e6a6ffd 100644 |
| --- a/fs/cifs/cifsglob.h |
| +++ b/fs/cifs/cifsglob.h |
| @@ -1509,6 +1509,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 */ |
| diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c |
| index 9a5a09a7cccd..8ed44f388d9d 100644 |
| --- a/fs/cifs/connect.c |
| +++ b/fs/cifs/connect.c |
| @@ -894,6 +894,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) |
| @@ -901,6 +915,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? */ |
| diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c |
| index 0011e6bdaa9a..24a7618470ec 100644 |
| --- a/fs/cifs/smb2ops.c |
| +++ b/fs/cifs/smb2ops.c |
| @@ -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 |
| -- |
| 2.7.4 |
| |