cifs: fix race in assemble_neg_contexts()
authorPaulo Alcantara <pc@cjr.nz>
Thu, 29 Dec 2022 15:33:56 +0000 (12:33 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Jan 2023 06:24:32 +0000 (07:24 +0100)
[ Upstream commit 775e44d6d86dca400d614cbda5dab4def4951fe7 ]

Serialise access of TCP_Server_Info::hostname in
assemble_neg_contexts() by holding the server's mutex otherwise it
might end up accessing an already-freed hostname pointer from
cifs_reconnect() or cifs_resolve_server().

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Reviewed-by: Enzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/cifs/smb2pdu.c

index 4ac5b1b..727f16b 100644 (file)
@@ -541,9 +541,10 @@ static void
 assemble_neg_contexts(struct smb2_negotiate_req *req,
                      struct TCP_Server_Info *server, unsigned int *total_len)
 {
-       char *pneg_ctxt;
-       char *hostname = NULL;
        unsigned int ctxt_len, neg_context_count;
+       struct TCP_Server_Info *pserver;
+       char *pneg_ctxt;
+       char *hostname;
 
        if (*total_len > 200) {
                /* In case length corrupted don't want to overrun smb buffer */
@@ -574,8 +575,9 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
         * secondary channels don't have the hostname field populated
         * use the hostname field in the primary channel instead
         */
-       hostname = CIFS_SERVER_IS_CHAN(server) ?
-               server->primary_server->hostname : server->hostname;
+       pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+       cifs_server_lock(pserver);
+       hostname = pserver->hostname;
        if (hostname && (hostname[0] != 0)) {
                ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
                                              hostname);
@@ -584,6 +586,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
                neg_context_count = 3;
        } else
                neg_context_count = 2;
+       cifs_server_unlock(pserver);
 
        build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
        *total_len += sizeof(struct smb2_posix_neg_context);