Commit f932fb9b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.13-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - fix ctime setting in setattr

 - fix reference count on user session to avoid potential race with
   session expire

 - fix query dir issue

* tag 'v6.13-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: set ATTR_CTIME flags when setting mtime
  ksmbd: fix racy issue from session lookup and expire
  ksmbd: retry iterate_dir in smb2_query_dir
parents 01abac26 21e46a79
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1016,6 +1016,8 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,

	ses_enc_key = enc ? sess->smb3encryptionkey :
		sess->smb3decryptionkey;
	if (enc)
		ksmbd_user_session_get(sess);
	memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);

	return 0;
+5 −1
Original line number Diff line number Diff line
@@ -263,8 +263,10 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,

	down_read(&conn->session_lock);
	sess = xa_load(&conn->sessions, id);
	if (sess)
	if (sess) {
		sess->last_active = jiffies;
		ksmbd_user_session_get(sess);
	}
	up_read(&conn->session_lock);
	return sess;
}
@@ -275,6 +277,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)

	down_read(&sessions_table_lock);
	sess = __session_lookup(id);
	if (sess)
		ksmbd_user_session_get(sess);
	up_read(&sessions_table_lock);

	return sess;
+2 −2
Original line number Diff line number Diff line
@@ -241,14 +241,14 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
	if (work->tcon)
		ksmbd_tree_connect_put(work->tcon);
	smb3_preauth_hash_rsp(work);
	if (work->sess)
		ksmbd_user_session_put(work->sess);
	if (work->sess && work->sess->enc && work->encrypted &&
	    conn->ops->encrypt_resp) {
		rc = conn->ops->encrypt_resp(work);
		if (rc < 0)
			conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
	}
	if (work->sess)
		ksmbd_user_session_put(work->sess);

	ksmbd_conn_write(work);
}
+28 −21
Original line number Diff line number Diff line
@@ -67,8 +67,10 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
		return false;

	sess = ksmbd_session_lookup_all(conn, id);
	if (sess)
	if (sess) {
		ksmbd_user_session_put(sess);
		return true;
	}
	pr_err("Invalid user session id: %llu\n", id);
	return false;
}
@@ -605,10 +607,8 @@ int smb2_check_user_session(struct ksmbd_work *work)

	/* Check for validity of user session */
	work->sess = ksmbd_session_lookup_all(conn, sess_id);
	if (work->sess) {
		ksmbd_user_session_get(work->sess);
	if (work->sess)
		return 1;
	}
	ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
	return -ENOENT;
}
@@ -1701,29 +1701,35 @@ 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;
@@ -1731,7 +1737,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
			goto out_err;
		}

		if (ksmbd_session_lookup(conn, sess_id)) {
		sess = ksmbd_session_lookup(conn, sess_id);
		if (!sess) {
			rc = -EACCES;
			goto out_err;
		}
@@ -1742,7 +1749,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
		}

		conn->binding = true;
		ksmbd_user_session_get(sess);
	} else if ((conn->dialect < SMB30_PROT_ID ||
		    server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
		   (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
@@ -1769,7 +1775,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
		}

		conn->binding = false;
		ksmbd_user_session_get(sess);
	}
	work->sess = sess;

@@ -2197,9 +2202,9 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
int smb2_session_logoff(struct ksmbd_work *work)
{
	struct ksmbd_conn *conn = work->conn;
	struct ksmbd_session *sess = work->sess;
	struct smb2_logoff_req *req;
	struct smb2_logoff_rsp *rsp;
	struct ksmbd_session *sess;
	u64 sess_id;
	int err;

@@ -2221,11 +2226,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
	ksmbd_close_session_fds(work);
	ksmbd_conn_wait_idle(conn);

	/*
	 * Re-lookup session to validate if session is deleted
	 * while waiting request complete
	 */
	sess = ksmbd_session_lookup_all(conn, sess_id);
	if (ksmbd_tree_conn_session_logoff(sess)) {
		ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
		rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
@@ -4228,6 +4228,7 @@ static bool __query_dir(struct dir_context *ctx, const char *name, int namlen,
	/* dot and dotdot entries are already reserved */
	if (!strcmp(".", name) || !strcmp("..", name))
		return true;
	d_info->num_scan++;
	if (ksmbd_share_veto_filename(priv->work->tcon->share_conf, name))
		return true;
	if (!match_pattern(name, namlen, priv->search_pattern))
@@ -4390,8 +4391,17 @@ int smb2_query_dir(struct ksmbd_work *work)
	query_dir_private.info_level		= req->FileInformationClass;
	dir_fp->readdir_data.private		= &query_dir_private;
	set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir);

again:
	d_info.num_scan = 0;
	rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx);
	/*
	 * num_entry can be 0 if the directory iteration stops before reaching
	 * the end of the directory and no file is matched with the search
	 * pattern.
	 */
	if (rc >= 0 && !d_info.num_entry && d_info.num_scan &&
	    d_info.out_buf_len > 0)
		goto again;
	/*
	 * req->OutputBufferLength is too small to contain even one entry.
	 * In this case, it immediately returns OutputBufferLength 0 to client.
@@ -6016,15 +6026,13 @@ static int set_file_basic_info(struct ksmbd_file *fp,
		attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
	}

	attrs.ia_valid |= ATTR_CTIME;
	if (file_info->ChangeTime)
		attrs.ia_ctime = ksmbd_NTtimeToUnix(file_info->ChangeTime);
	else
		attrs.ia_ctime = inode_get_ctime(inode);
		inode_set_ctime_to_ts(inode,
				ksmbd_NTtimeToUnix(file_info->ChangeTime));

	if (file_info->LastWriteTime) {
		attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime);
		attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
		attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME);
	}

	if (file_info->Attributes) {
@@ -6066,8 +6074,6 @@ static int set_file_basic_info(struct ksmbd_file *fp,
			return -EACCES;

		inode_lock(inode);
		inode_set_ctime_to_ts(inode, attrs.ia_ctime);
		attrs.ia_valid &= ~ATTR_CTIME;
		rc = notify_change(idmap, dentry, &attrs, NULL);
		inode_unlock(inode);
	}
@@ -8982,6 +8988,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
		       le64_to_cpu(tr_hdr->SessionId));
		return -ECONNABORTED;
	}
	ksmbd_user_session_put(sess);

	iov[0].iov_base = buf;
	iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ struct ksmbd_dir_info {
	char		*rptr;
	int		name_len;
	int		out_buf_len;
	int		num_scan;
	int		num_entry;
	int		data_count;
	int		last_entry_offset;