stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, Pavel Shilovsky <pshilov@microsoft.com>
Subject: [PATCH 4.4 51/60] CIFS: Fix a possible memory corruption during reconnect
Date: Wed,  4 Jan 2017 21:47:36 +0100	[thread overview]
Message-ID: <20170104200708.150685442@linuxfoundation.org> (raw)
In-Reply-To: <20170104200705.627445996@linuxfoundation.org>

4.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Pavel Shilovsky <pshilov@microsoft.com>

commit 53e0e11efe9289535b060a51d4cf37c25e0d0f2b upstream.

We can not unlock/lock cifs_tcp_ses_lock while walking through ses
and tcon lists because it can corrupt list iterator pointers and
a tcon structure can be released if we don't hold an extra reference.
Fix it by moving a reconnect process to a separate delayed work
and acquiring a reference to every tcon that needs to be reconnected.
Also do not send an echo request on newly established connections.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 fs/cifs/cifsglob.h  |    3 ++
 fs/cifs/cifsproto.h |    3 ++
 fs/cifs/connect.c   |   34 ++++++++++++++++++-----
 fs/cifs/smb2pdu.c   |   75 +++++++++++++++++++++++++++++++++++-----------------
 fs/cifs/smb2proto.h |    1 
 5 files changed, 85 insertions(+), 31 deletions(-)

--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -627,6 +627,8 @@ struct TCP_Server_Info {
 #ifdef CONFIG_CIFS_SMB2
 	unsigned int	max_read;
 	unsigned int	max_write;
+	struct delayed_work reconnect; /* reconnect workqueue job */
+	struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
 #endif /* CONFIG_CIFS_SMB2 */
 };
 
@@ -826,6 +828,7 @@ cap_unix(struct cifs_ses *ses)
 struct cifs_tcon {
 	struct list_head tcon_list;
 	int tc_count;
+	struct list_head rlist; /* reconnect list */
 	struct list_head openFileList;
 	spinlock_t open_file_lock; /* protects list above */
 	struct cifs_ses *ses;	/* pointer to session associated with */
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -205,6 +205,9 @@ extern void cifs_add_pending_open_locked
 					 struct tcon_link *tlink,
 					 struct cifs_pending_open *open);
 extern void cifs_del_pending_open(struct cifs_pending_open *open);
+extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
+				 int from_reconnect);
+extern void cifs_put_tcon(struct cifs_tcon *tcon);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -52,6 +52,9 @@
 #include "nterr.h"
 #include "rfc1002pdu.h"
 #include "fscache.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
@@ -2113,8 +2116,8 @@ cifs_find_tcp_session(struct smb_vol *vo
 	return NULL;
 }
 
-static void
-cifs_put_tcp_session(struct TCP_Server_Info *server)
+void
+cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
 {
 	struct task_struct *task;
 
@@ -2131,6 +2134,19 @@ cifs_put_tcp_session(struct TCP_Server_I
 
 	cancel_delayed_work_sync(&server->echo);
 
+#ifdef CONFIG_CIFS_SMB2
+	if (from_reconnect)
+		/*
+		 * Avoid deadlock here: reconnect work calls
+		 * cifs_put_tcp_session() at its end. Need to be sure
+		 * that reconnect work does nothing with server pointer after
+		 * that step.
+		 */
+		cancel_delayed_work(&server->reconnect);
+	else
+		cancel_delayed_work_sync(&server->reconnect);
+#endif
+
 	spin_lock(&GlobalMid_Lock);
 	server->tcpStatus = CifsExiting;
 	spin_unlock(&GlobalMid_Lock);
@@ -2195,6 +2211,10 @@ cifs_get_tcp_session(struct smb_vol *vol
 	INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
 	INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
 	INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
+#ifdef CONFIG_CIFS_SMB2
+	INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
+	mutex_init(&tcp_ses->reconnect_mutex);
+#endif
 	memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
 	       sizeof(tcp_ses->srcaddr));
 	memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
@@ -2347,7 +2367,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
 	spin_unlock(&cifs_tcp_ses_lock);
 
 	sesInfoFree(ses);
-	cifs_put_tcp_session(server);
+	cifs_put_tcp_session(server, 0);
 }
 
 #ifdef CONFIG_KEYS
@@ -2521,7 +2541,7 @@ cifs_get_smb_ses(struct TCP_Server_Info
 		mutex_unlock(&ses->session_mutex);
 
 		/* existing SMB ses has a server reference already */
-		cifs_put_tcp_session(server);
+		cifs_put_tcp_session(server, 0);
 		free_xid(xid);
 		return ses;
 	}
@@ -2611,7 +2631,7 @@ cifs_find_tcon(struct cifs_ses *ses, con
 	return NULL;
 }
 
-static void
+void
 cifs_put_tcon(struct cifs_tcon *tcon)
 {
 	unsigned int xid;
@@ -3767,7 +3787,7 @@ mount_fail_check:
 		else if (ses)
 			cifs_put_smb_ses(ses);
 		else
-			cifs_put_tcp_session(server);
+			cifs_put_tcp_session(server, 0);
 		bdi_destroy(&cifs_sb->bdi);
 	}
 
@@ -4078,7 +4098,7 @@ cifs_construct_tcon(struct cifs_sb_info
 	ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
 	if (IS_ERR(ses)) {
 		tcon = (struct cifs_tcon *)ses;
-		cifs_put_tcp_session(master_tcon->ses->server);
+		cifs_put_tcp_session(master_tcon->ses->server, 0);
 		goto out;
 	}
 
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1822,6 +1822,54 @@ smb2_echo_callback(struct mid_q_entry *m
 	add_credits(server, credits_received, CIFS_ECHO_OP);
 }
 
+void smb2_reconnect_server(struct work_struct *work)
+{
+	struct TCP_Server_Info *server = container_of(work,
+					struct TCP_Server_Info, reconnect.work);
+	struct cifs_ses *ses;
+	struct cifs_tcon *tcon, *tcon2;
+	struct list_head tmp_list;
+	int tcon_exist = false;
+
+	/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
+	mutex_lock(&server->reconnect_mutex);
+
+	INIT_LIST_HEAD(&tmp_list);
+	cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
+
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+		list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+			if (tcon->need_reconnect) {
+				tcon->tc_count++;
+				list_add_tail(&tcon->rlist, &tmp_list);
+				tcon_exist = true;
+			}
+		}
+	}
+	/*
+	 * Get the reference to server struct to be sure that the last call of
+	 * cifs_put_tcon() in the loop below won't release the server pointer.
+	 */
+	if (tcon_exist)
+		server->srv_count++;
+
+	spin_unlock(&cifs_tcp_ses_lock);
+
+	list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
+		smb2_reconnect(SMB2_ECHO, tcon);
+		list_del_init(&tcon->rlist);
+		cifs_put_tcon(tcon);
+	}
+
+	cifs_dbg(FYI, "Reconnecting tcons finished\n");
+	mutex_unlock(&server->reconnect_mutex);
+
+	/* now we can safely release srv struct */
+	if (tcon_exist)
+		cifs_put_tcp_session(server, 1);
+}
+
 int
 SMB2_echo(struct TCP_Server_Info *server)
 {
@@ -1834,32 +1882,11 @@ SMB2_echo(struct TCP_Server_Info *server
 	cifs_dbg(FYI, "In echo request\n");
 
 	if (server->tcpStatus == CifsNeedNegotiate) {
-		struct list_head *tmp, *tmp2;
-		struct cifs_ses *ses;
-		struct cifs_tcon *tcon;
-
-		cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
-		spin_lock(&cifs_tcp_ses_lock);
-		list_for_each(tmp, &server->smb_ses_list) {
-			ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
-			list_for_each(tmp2, &ses->tcon_list) {
-				tcon = list_entry(tmp2, struct cifs_tcon,
-						  tcon_list);
-				/* add check for persistent handle reconnect */
-				if (tcon && tcon->need_reconnect) {
-					spin_unlock(&cifs_tcp_ses_lock);
-					rc = smb2_reconnect(SMB2_ECHO, tcon);
-					spin_lock(&cifs_tcp_ses_lock);
-				}
-			}
-		}
-		spin_unlock(&cifs_tcp_ses_lock);
+		/* No need to send echo on newly established connections */
+		queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
+		return rc;
 	}
 
-	/* if no session, renegotiate failed above */
-	if (server->tcpStatus == CifsNeedNegotiate)
-		return -EIO;
-
 	rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
 	if (rc)
 		return rc;
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -95,6 +95,7 @@ extern int smb2_open_file(const unsigned
 extern int smb2_unlock_range(struct cifsFileInfo *cfile,
 			     struct file_lock *flock, const unsigned int xid);
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
+extern void smb2_reconnect_server(struct work_struct *work);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details

  parent reply	other threads:[~2017-01-04 20:47 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20170104205105epcas5p4dfb9f8f2e2771bc19858b096e326c051@epcas5p4.samsung.com>
2017-01-04 20:46 ` [PATCH 4.4 00/60] 4.4.40-stable review Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 01/60] btrfs: limit async_work allocation and worker func duration Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 02/60] Btrfs: fix tree search logic when replaying directory entry deletes Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 03/60] btrfs: store and load values of stripes_min/stripes_max in balance status item Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 04/60] Btrfs: fix qgroup rescan worker initialization Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 05/60] USB: serial: option: add support for Telit LE922A PIDs 0x1040, 0x1041 Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 06/60] USB: serial: option: add dlink dwm-158 Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 07/60] USB: serial: kl5kusb105: fix open error path Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 08/60] USB: cdc-acm: add device id for GW Instek AFG-125 Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 09/60] usb: hub: Fix auto-remount of safely removed or ejected USB-3 devices Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 10/60] usb: gadget: f_uac2: fix error handling at afunc_bind Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 11/60] usb: gadget: composite: correctly initialize ep->maxpacket Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 12/60] USB: UHCI: report non-PME wakeup signalling for Intel hardware Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 13/60] ALSA: usb-audio: Add QuickCam Communicate Deluxe/S7500 to volume_control_quirks Greg Kroah-Hartman
2017-01-04 20:46   ` [PATCH 4.4 14/60] ALSA: hiface: Fix M2Tech hiFace driver sampling rate change Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 15/60] ALSA: hda/ca0132 - Add quirk for Alienware 15 R2 2016 Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 16/60] ALSA: hda - ignore the assoc and seq when comparing pin configurations Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 17/60] ALSA: hda - fix headset-mic problem on a Dell laptop Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 18/60] ALSA: hda - Gate the mic jack on HP Z1 Gen3 AiO Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 19/60] ALSA: hda: when comparing pin configurations, ignore assoc in addition to seq Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 20/60] clk: ti: omap36xx: Work around sprz319 advisory 2.1 Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 21/60] Btrfs: fix memory leak in reading btree blocks Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 22/60] Btrfs: bail out if block group has different mixed flag Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 23/60] Btrfs: return gracefully from balance if fs tree is corrupted Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 24/60] Btrfs: dont leak reloc root nodes on error Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 25/60] Btrfs: fix memory leak in do_walk_down Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 26/60] Btrfs: dont BUG() during drop snapshot Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 27/60] btrfs: make file clone aware of fatal signals Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 28/60] block_dev: dont test bdev->bd_contains when it is not stable Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 29/60] mm: Add a user_ns owner to mm_struct and fix ptrace permission checks Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 30/60] ptrace: Capture the ptracers creds not PT_PTRACE_CAP Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 32/60] ext4: fix mballoc breakage with 64k block size Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 33/60] ext4: fix stack memory corruption " Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 34/60] ext4: use more strict checks for inodes_per_block on mount Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 35/60] ext4: fix in-superblock mount options processing Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 36/60] ext4: add sanity checking to count_overhead() Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 37/60] ext4: reject inodes with negative size Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 38/60] ext4: return -ENOMEM instead of success Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 39/60] ext4: do not perform data journaling when data is encrypted Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 40/60] f2fs: set ->owner for debugfs status files file_operations Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 41/60] loop: return proper error from loop_queue_rq() Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 42/60] mm/vmscan.c: set correct defer count for shrinker Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 43/60] fs: exec: apply CLOEXEC before changing dumpable task flags Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 44/60] exec: Ensure mm->user_ns contains the execed files Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 45/60] usb: gadget: composite: always set ep->mult to a sensible value Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 46/60] blk-mq: Do not invoke .queue_rq() for a stopped queue Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 47/60] dm flakey: return -EINVAL on interval bounds error in flakey_ctr() Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 48/60] dm crypt: mark key as invalid until properly loaded Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 49/60] dm space map metadata: fix struct sm_metadata leak on failed create Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 50/60] ASoC: intel: Fix crash at suspend/resume without card registration Greg Kroah-Hartman
2017-01-04 20:47   ` Greg Kroah-Hartman [this message]
2017-01-04 20:47   ` [PATCH 4.4 52/60] CIFS: Fix missing nls unload in smb2_reconnect() Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 53/60] CIFS: Fix a possible memory corruption in push locks Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 54/60] kernel/watchdog: use nmi registers snapshot in hardlockup handler Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 55/60] kernel/debug/debug_core.c: more properly delay for secondary CPUs Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 56/60] tpm xen: Remove bogus tpm_chip_unregister Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 57/60] xen/gntdev: Use VM_MIXEDMAP instead of VM_IO to avoid NUMA balancing Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 58/60] arm/xen: Use alloc_percpu rather than __alloc_percpu Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 59/60] xfs: set AGI buffer type in xlog_recover_clear_agi_bucket Greg Kroah-Hartman
2017-01-04 20:47   ` [PATCH 4.4 60/60] driver core: fix race between creating/querying glue dir and its cleanup Greg Kroah-Hartman
2017-01-05  0:42   ` [PATCH 4.4 00/60] 4.4.40-stable review Shuah Khan
2017-01-05  5:25   ` Guenter Roeck
2017-01-05 15:33   ` Guillaume Nault
2017-01-05 20:35     ` Greg Kroah-Hartman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170104200708.150685442@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pshilov@microsoft.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).