Commit c1883049 authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French
Browse files

ksmbd: fix multichannel connection failure



ksmbd check that the session of second channel is in the session list of
first connection. If it is in session list, multichannel connection
should not be allowed.

Fixes: b9562943 ("ksmbd: fix racy issue from session lookup and expire")
Reported-by: default avatarSean Heelan <seanheelan@gmail.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 15a9605f
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -259,6 +259,22 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
	up_write(&sessions_table_lock);
}

bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
				   unsigned long long id)
{
	struct ksmbd_session *sess;

	down_read(&conn->session_lock);
	sess = xa_load(&conn->sessions, id);
	if (sess) {
		up_read(&conn->session_lock);
		return true;
	}
	up_read(&conn->session_lock);

	return false;
}

struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
					   unsigned long long id)
{
+2 −0
Original line number Diff line number Diff line
@@ -87,6 +87,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
					   unsigned long long id);
bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
				     unsigned long long id);
int ksmbd_session_register(struct ksmbd_conn *conn,
			   struct ksmbd_session *sess);
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
+4 −8
Original line number Diff line number Diff line
@@ -1707,44 +1707,38 @@ int smb2_sess_setup(struct ksmbd_work *work)

		if (conn->dialect != sess->dialect) {
			rc = -EINVAL;
			ksmbd_user_session_put(sess);
			goto out_err;
		}

		if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
			rc = -EINVAL;
			ksmbd_user_session_put(sess);
			goto out_err;
		}

		if (strncmp(conn->ClientGUID, sess->ClientGUID,
			    SMB2_CLIENT_GUID_SIZE)) {
			rc = -ENOENT;
			ksmbd_user_session_put(sess);
			goto out_err;
		}

		if (sess->state == SMB2_SESSION_IN_PROGRESS) {
			rc = -EACCES;
			ksmbd_user_session_put(sess);
			goto out_err;
		}

		if (sess->state == SMB2_SESSION_EXPIRED) {
			rc = -EFAULT;
			ksmbd_user_session_put(sess);
			goto out_err;
		}
		ksmbd_user_session_put(sess);

		if (ksmbd_conn_need_reconnect(conn)) {
			rc = -EFAULT;
			ksmbd_user_session_put(sess);
			sess = NULL;
			goto out_err;
		}

		sess = ksmbd_session_lookup(conn, sess_id);
		if (!sess) {
		if (is_ksmbd_session_in_connection(conn, sess_id)) {
			rc = -EACCES;
			goto out_err;
		}
@@ -1910,6 +1904,8 @@ int smb2_sess_setup(struct ksmbd_work *work)

			sess->last_active = jiffies;
			sess->state = SMB2_SESSION_EXPIRED;
			ksmbd_user_session_put(sess);
			work->sess = NULL;
			if (try_delay) {
				ksmbd_conn_set_need_reconnect(conn);
				ssleep(5);