Commit 1eb714c6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.12-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
 "Four fixes, all also marked for stable:

   - fix two potential use after free issues

   - fix OOM issue with many simultaneous requests

   - fix missing error check in RPC pipe handling"

* tag 'v6.12-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd:
  ksmbd: check outstanding simultaneous SMB operations
  ksmbd: fix slab-use-after-free in smb3_preauth_hash_rsp
  ksmbd: fix slab-use-after-free in ksmbd_smb2_session_create
  ksmbd: Fix the missing xa_store error check
parents c291c9cf 0a77d947
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
	atomic_set(&conn->req_running, 0);
	atomic_set(&conn->r_count, 0);
	atomic_set(&conn->refcnt, 1);
	atomic_set(&conn->mux_smb_requests, 0);
	conn->total_credits = 1;
	conn->outstanding_credits = 0;

+1 −0
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ struct ksmbd_conn {
	__le16				signing_algorithm;
	bool				binding;
	atomic_t			refcnt;
	atomic_t			mux_smb_requests;
};

struct ksmbd_conn_ops {
+10 −5
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ static int __rpc_method(char *rpc_name)

int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
{
	struct ksmbd_session_rpc *entry;
	struct ksmbd_session_rpc *entry, *old;
	struct ksmbd_rpc_command *resp;
	int method;

@@ -106,16 +106,19 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
	entry->id = ksmbd_ipc_id_alloc();
	if (entry->id < 0)
		goto free_entry;
	xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
	old = xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
	if (xa_is_err(old))
		goto free_id;

	resp = ksmbd_rpc_open(sess, entry->id);
	if (!resp)
		goto free_id;
		goto erase_xa;

	kvfree(resp);
	return entry->id;
free_id:
erase_xa:
	xa_erase(&sess->rpc_handle_list, entry->id);
free_id:
	ksmbd_rpc_id_free(entry->id);
free_entry:
	kfree(entry);
@@ -175,6 +178,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
	unsigned long id;
	struct ksmbd_session *sess;

	down_write(&sessions_table_lock);
	down_write(&conn->session_lock);
	xa_for_each(&conn->sessions, id, sess) {
		if (atomic_read(&sess->refcnt) == 0 &&
@@ -188,6 +192,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
		}
	}
	up_write(&conn->session_lock);
	up_write(&sessions_table_lock);
}

int ksmbd_session_register(struct ksmbd_conn *conn,
@@ -229,7 +234,6 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
			}
		}
	}
	up_write(&sessions_table_lock);

	down_write(&conn->session_lock);
	xa_for_each(&conn->sessions, id, sess) {
@@ -249,6 +253,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
		}
	}
	up_write(&conn->session_lock);
	up_write(&sessions_table_lock);
}

struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
+12 −8
Original line number Diff line number Diff line
@@ -238,11 +238,11 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
	} while (is_chained == true);

send:
	if (work->sess)
		ksmbd_user_session_put(work->sess);
	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);
@@ -270,6 +270,7 @@ static void handle_ksmbd_work(struct work_struct *wk)

	ksmbd_conn_try_dequeue_request(work);
	ksmbd_free_work_struct(work);
	atomic_dec(&conn->mux_smb_requests);
	/*
	 * Checking waitqueue to dropping pending requests on
	 * disconnection. waitqueue_active is safe because it
@@ -291,6 +292,15 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
	struct ksmbd_work *work;
	int err;

	err = ksmbd_init_smb_server(conn);
	if (err)
		return 0;

	if (atomic_inc_return(&conn->mux_smb_requests) >= conn->vals->max_credits) {
		atomic_dec_return(&conn->mux_smb_requests);
		return -ENOSPC;
	}

	work = ksmbd_alloc_work_struct();
	if (!work) {
		pr_err("allocation for work failed\n");
@@ -301,12 +311,6 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
	work->request_buf = conn->request_buf;
	conn->request_buf = NULL;

	err = ksmbd_init_smb_server(work);
	if (err) {
		ksmbd_free_work_struct(work);
		return 0;
	}

	ksmbd_conn_enqueue_request(work);
	atomic_inc(&conn->r_count);
	/* update activity on connection */
+7 −3
Original line number Diff line number Diff line
@@ -388,6 +388,10 @@ static struct smb_version_ops smb1_server_ops = {
	.set_rsp_status = set_smb1_rsp_status,
};

static struct smb_version_values smb1_server_values = {
	.max_credits = SMB2_MAX_CREDITS,
};

static int smb1_negotiate(struct ksmbd_work *work)
{
	return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
@@ -399,18 +403,18 @@ static struct smb_version_cmds smb1_server_cmds[1] = {

static int init_smb1_server(struct ksmbd_conn *conn)
{
	conn->vals = &smb1_server_values;
	conn->ops = &smb1_server_ops;
	conn->cmds = smb1_server_cmds;
	conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
	return 0;
}

int ksmbd_init_smb_server(struct ksmbd_work *work)
int ksmbd_init_smb_server(struct ksmbd_conn *conn)
{
	struct ksmbd_conn *conn = work->conn;
	__le32 proto;

	proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
	proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;
	if (conn->need_neg == false) {
		if (proto == SMB1_PROTO_NUMBER)
			return -EINVAL;
Loading