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

ksmbd: fix use-after-free in ksmbd_session_rpc_open



A UAF issue can occur due to a race condition between
ksmbd_session_rpc_open() and __session_rpc_close().
Add rpc_lock to the session to protect it.

Cc: stable@vger.kernel.org
Reported-by: default avatarNorbert Szetei <norbert@doyensec.com>
Tested-by: default avatarNorbert Szetei <norbert@doyensec.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent af5226ab
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -59,10 +59,12 @@ static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
	struct ksmbd_session_rpc *entry;
	long index;

	down_write(&sess->rpc_lock);
	xa_for_each(&sess->rpc_handle_list, index, entry) {
		xa_erase(&sess->rpc_handle_list, index);
		__session_rpc_close(sess, entry);
	}
	up_write(&sess->rpc_lock);

	xa_destroy(&sess->rpc_handle_list);
}
@@ -92,7 +94,7 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
{
	struct ksmbd_session_rpc *entry, *old;
	struct ksmbd_rpc_command *resp;
	int method;
	int method, id;

	method = __rpc_method(rpc_name);
	if (!method)
@@ -102,26 +104,29 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
	if (!entry)
		return -ENOMEM;

	down_read(&sess->rpc_lock);
	entry->method = method;
	entry->id = ksmbd_ipc_id_alloc();
	if (entry->id < 0)
	entry->id = id = ksmbd_ipc_id_alloc();
	if (id < 0)
		goto free_entry;
	old = xa_store(&sess->rpc_handle_list, entry->id, entry, KSMBD_DEFAULT_GFP);
	old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP);
	if (xa_is_err(old))
		goto free_id;

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

	up_read(&sess->rpc_lock);
	kvfree(resp);
	return entry->id;
	return id;
erase_xa:
	xa_erase(&sess->rpc_handle_list, entry->id);
free_id:
	ksmbd_rpc_id_free(entry->id);
free_entry:
	kfree(entry);
	up_read(&sess->rpc_lock);
	return -EINVAL;
}

@@ -129,9 +134,11 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
{
	struct ksmbd_session_rpc *entry;

	down_write(&sess->rpc_lock);
	entry = xa_erase(&sess->rpc_handle_list, id);
	if (entry)
		__session_rpc_close(sess, entry);
	up_write(&sess->rpc_lock);
}

int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
@@ -439,6 +446,7 @@ static struct ksmbd_session *__session_create(int protocol)
	sess->sequence_number = 1;
	rwlock_init(&sess->tree_conns_lock);
	atomic_set(&sess->refcnt, 2);
	init_rwsem(&sess->rpc_lock);

	ret = __init_smb2_session(sess);
	if (ret)
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ struct ksmbd_session {
	rwlock_t			tree_conns_lock;

	atomic_t			refcnt;
	struct rw_semaphore		rpc_lock;
};

static inline int test_session_flag(struct ksmbd_session *sess, int bit)