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

Merge tag 'v6.15-rc4-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix three potential use after frees: in session logoff, in krb5 auth,
   and in RPC open

 - Fix missing rc check in session setup authentication

* tag 'v6.15-rc4-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: fix use-after-free in session logoff
  ksmbd: fix use-after-free in kerberos authentication
  ksmbd: fix use-after-free in ksmbd_session_rpc_open
  smb: server: smb2pdu: check return value of xa_store()
parents 78109c59 2fc9feff
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -550,7 +550,19 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
		retval = -ENOMEM;
		goto out;
	}

	if (!sess->user) {
		/* First successful authentication */
		sess->user = user;
	} else {
		if (!ksmbd_compare_user(sess->user, user)) {
			ksmbd_debug(AUTH, "different user tried to reuse session\n");
			retval = -EPERM;
			ksmbd_free_user(user);
			goto out;
		}
		ksmbd_free_user(user);
	}

	memcpy(sess->sess_key, resp->payload, resp->session_key_len);
	memcpy(out_blob, resp->payload + resp->session_key_len,
+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)
+7 −11
Original line number Diff line number Diff line
@@ -1445,7 +1445,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
{
	struct ksmbd_conn *conn = work->conn;
	struct ksmbd_session *sess = work->sess;
	struct channel *chann = NULL;
	struct channel *chann = NULL, *old;
	struct ksmbd_user *user;
	u64 prev_id;
	int sz, rc;
@@ -1557,7 +1557,12 @@ static int ntlm_authenticate(struct ksmbd_work *work,
				return -ENOMEM;

			chann->conn = conn;
			xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP);
			old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
					KSMBD_DEFAULT_GFP);
			if (xa_is_err(old)) {
				kfree(chann);
				return xa_err(old);
			}
		}
	}

@@ -1602,11 +1607,6 @@ static int krb5_authenticate(struct ksmbd_work *work,
	if (prev_sess_id && prev_sess_id != sess->id)
		destroy_previous_session(conn, sess->user, prev_sess_id);

	if (sess->state == SMB2_SESSION_VALID) {
		ksmbd_free_user(sess->user);
		sess->user = NULL;
	}

	retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
					 out_blob, &out_len);
	if (retval) {
@@ -2249,10 +2249,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
	sess->state = SMB2_SESSION_EXPIRED;
	up_write(&conn->session_lock);

	if (sess->user) {
		ksmbd_free_user(sess->user);
		sess->user = NULL;
	}
	ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_SETUP);

	rsp->StructureSize = cpu_to_le16(4);