aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNamjae Jeon <linkinjeon@kernel.org>2023-10-04 18:30:14 +0900
committerSteve French <stfrench@microsoft.com>2023-10-04 20:21:48 -0500
commit7ca9da7d873ee8024e9548d3366101c2b6843eab (patch)
treeba0c28bb371ba3c7bf09de259470433e2d911d36
parentc69813471a1ec081a0b9bf0c6bd7e8afd818afce (diff)
downloadvfs-7ca9da7d873ee8024e9548d3366101c2b6843eab.tar.gz
ksmbd: fix race condition from parallel smb2 logoff requests
If parallel smb2 logoff requests come in before closing door, running request count becomes more than 1 even though connection status is set to KSMBD_SESS_NEED_RECONNECT. It can't get condition true, and sleep forever. This patch fix race condition problem by returning error if connection status was already set to KSMBD_SESS_NEED_RECONNECT. Reported-by: luosili <rootlab@huawei.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/smb/server/smb2pdu.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index b9d6e8e451ba2..e774c9855f7ff 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2164,17 +2164,17 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_debug(SMB, "request\n");
- sess_id = le64_to_cpu(req->hdr.SessionId);
-
- rsp->StructureSize = cpu_to_le16(4);
- err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
- if (err) {
- rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
+ ksmbd_conn_lock(conn);
+ if (!ksmbd_conn_good(conn)) {
+ ksmbd_conn_unlock(conn);
+ rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work);
- return err;
+ return -ENOENT;
}
-
+ sess_id = le64_to_cpu(req->hdr.SessionId);
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT);
+ ksmbd_conn_unlock(conn);
+
ksmbd_close_session_fds(work);
ksmbd_conn_wait_idle(conn, sess_id);
@@ -2196,6 +2196,14 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_free_user(sess->user);
sess->user = NULL;
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
+
+ rsp->StructureSize = cpu_to_le16(4);
+ err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
+ if (err) {
+ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
+ smb2_set_err_rsp(work);
+ return err;
+ }
return 0;
}