Unverified Commit 1c9231cb authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!1621 fix three CVEs by backport mainline patchs

Merge Pull Request from: @ci-robot 
 
PR sync from: ZhaoLong Wang <wangzhaolong1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/6ETLQBKJNMKNALJRDIYCV27MJA2XG66X/ 
mainline patch f5c779b7("ksmbd: fix racy issue from session setup and
logoff") It fixes three CVEs:

 CVE-2023-32250
 CVE-2023-32252
 CVE-2023-32257

In order to successfully apply the patch, we chose to incorporate the
related pre-installed bugfix patch.

Colin Ian King (1):
  ksmbd: Fix spelling mistake "excceed" -> "exceeded"

Dawei Li (1):
  ksmbd: Implements sess->ksmbd_chann_list as xarray

Namjae Jeon (2):
  ksmbd: limit pdu length size according to connection status
  ksmbd: fix racy issue from session setup and logoff


-- 
2.34.3
 
https://gitee.com/src-openeuler/kernel/issues/I7BG0L
https://gitee.com/openeuler/kernel/issues/I7CETC 
 
Link:https://gitee.com/openeuler/kernel/pulls/1621

 

Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 0c40785a 2e1b3ccd
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
		return NULL;

	conn->need_neg = true;
	conn->status = KSMBD_SESS_NEW;
	ksmbd_conn_set_new(conn);
	conn->local_nls = load_nls("utf8");
	if (!conn->local_nls)
		conn->local_nls = load_nls_default();
@@ -143,12 +143,12 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
	return ret;
}

static void ksmbd_conn_lock(struct ksmbd_conn *conn)
void ksmbd_conn_lock(struct ksmbd_conn *conn)
{
	mutex_lock(&conn->srv_mutex);
}

static void ksmbd_conn_unlock(struct ksmbd_conn *conn)
void ksmbd_conn_unlock(struct ksmbd_conn *conn)
{
	mutex_unlock(&conn->srv_mutex);
}
@@ -239,7 +239,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
	if (!ksmbd_server_running())
		return false;

	if (conn->status == KSMBD_SESS_EXITING)
	if (ksmbd_conn_exiting(conn))
		return false;

	if (kthread_should_stop())
@@ -274,7 +274,7 @@ int ksmbd_conn_handler_loop(void *p)
{
	struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
	struct ksmbd_transport *t = conn->transport;
	unsigned int pdu_size;
	unsigned int pdu_size, max_allowed_pdu_size;
	char hdr_buf[4] = {0,};
	int size;

@@ -299,13 +299,26 @@ int ksmbd_conn_handler_loop(void *p)
		pdu_size = get_rfc1002_len(hdr_buf);
		ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);

		if (ksmbd_conn_good(conn))
			max_allowed_pdu_size =
				SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
		else
			max_allowed_pdu_size = SMB3_MAX_MSGSIZE;

		if (pdu_size > max_allowed_pdu_size) {
			pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n",
					pdu_size, max_allowed_pdu_size,
					READ_ONCE(conn->status));
			break;
		}

		/*
		 * Check if pdu size is valid (min : smb header size,
		 * max : 0x00FFFFFF).
		 */
		if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE ||
		    pdu_size > MAX_STREAM_PROT_LEN) {
			continue;
			break;
		}

		/* 4 for rfc1002 length field */
@@ -400,7 +413,7 @@ static void stop_sessions(void)
		if (task)
			ksmbd_debug(CONN, "Stop session handler %s/%d\n",
				    task->comm, task_pid_nr(task));
		conn->status = KSMBD_SESS_EXITING;
		ksmbd_conn_set_exiting(conn);
		if (t->ops->shutdown) {
			read_unlock(&conn_list_lock);
			t->ops->shutdown(t);
+23 −16
Original line number Diff line number Diff line
@@ -154,6 +154,8 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
int ksmbd_conn_handler_loop(void *p);
int ksmbd_conn_transport_init(void);
void ksmbd_conn_transport_destroy(void);
void ksmbd_conn_lock(struct ksmbd_conn *conn);
void ksmbd_conn_unlock(struct ksmbd_conn *conn);

/*
 * WARNING
@@ -161,43 +163,48 @@ void ksmbd_conn_transport_destroy(void);
 * This is a hack. We will move status to a proper place once we land
 * a multi-sessions support.
 */
static inline bool ksmbd_conn_good(struct ksmbd_work *work)
static inline bool ksmbd_conn_good(struct ksmbd_conn *conn)
{
	return work->conn->status == KSMBD_SESS_GOOD;
	return READ_ONCE(conn->status) == KSMBD_SESS_GOOD;
}

static inline bool ksmbd_conn_need_negotiate(struct ksmbd_work *work)
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn)
{
	return work->conn->status == KSMBD_SESS_NEED_NEGOTIATE;
	return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE;
}

static inline bool ksmbd_conn_need_reconnect(struct ksmbd_work *work)
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn)
{
	return work->conn->status == KSMBD_SESS_NEED_RECONNECT;
	return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT;
}

static inline bool ksmbd_conn_exiting(struct ksmbd_work *work)
static inline bool ksmbd_conn_exiting(struct ksmbd_conn *conn)
{
	return work->conn->status == KSMBD_SESS_EXITING;
	return READ_ONCE(conn->status) == KSMBD_SESS_EXITING;
}

static inline void ksmbd_conn_set_good(struct ksmbd_work *work)
static inline void ksmbd_conn_set_new(struct ksmbd_conn *conn)
{
	work->conn->status = KSMBD_SESS_GOOD;
	WRITE_ONCE(conn->status, KSMBD_SESS_NEW);
}

static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_work *work)
static inline void ksmbd_conn_set_good(struct ksmbd_conn *conn)
{
	work->conn->status = KSMBD_SESS_NEED_NEGOTIATE;
	WRITE_ONCE(conn->status, KSMBD_SESS_GOOD);
}

static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_work *work)
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn)
{
	work->conn->status = KSMBD_SESS_NEED_RECONNECT;
	WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE);
}

static inline void ksmbd_conn_set_exiting(struct ksmbd_work *work)
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn)
{
	work->conn->status = KSMBD_SESS_EXITING;
	WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT);
}

static inline void ksmbd_conn_set_exiting(struct ksmbd_conn *conn)
{
	WRITE_ONCE(conn->status, KSMBD_SESS_EXITING);
}
#endif /* __CONNECTION_H__ */
+25 −37
Original line number Diff line number Diff line
@@ -30,15 +30,15 @@ struct ksmbd_session_rpc {

static void free_channel_list(struct ksmbd_session *sess)
{
	struct channel *chann, *tmp;
	struct channel *chann;
	unsigned long index;

	write_lock(&sess->chann_lock);
	list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
				 chann_list) {
		list_del(&chann->chann_list);
	xa_for_each(&sess->ksmbd_chann_list, index, chann) {
		xa_erase(&sess->ksmbd_chann_list, index);
		kfree(chann);
	}
	write_unlock(&sess->chann_lock);

	xa_destroy(&sess->ksmbd_chann_list);
}

static void __session_rpc_close(struct ksmbd_session *sess,
@@ -188,21 +188,15 @@ int ksmbd_session_register(struct ksmbd_conn *conn,

static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
{
	struct channel *chann, *tmp;
	struct channel *chann;

	chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
	if (!chann)
		return -ENOENT;

	write_lock(&sess->chann_lock);
	list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
				 chann_list) {
		if (chann->conn == conn) {
			list_del(&chann->chann_list);
	kfree(chann);
			write_unlock(&sess->chann_lock);
			return 0;
		}
	}
	write_unlock(&sess->chann_lock);

	return -ENOENT;
	return 0;
}

void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
@@ -232,7 +226,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
	return;

sess_destroy:
	if (list_empty(&sess->ksmbd_chann_list)) {
	if (xa_empty(&sess->ksmbd_chann_list)) {
		xa_erase(&conn->sessions, sess->id);
		ksmbd_session_destroy(sess);
	}
@@ -318,6 +312,9 @@ static struct ksmbd_session *__session_create(int protocol)
	struct ksmbd_session *sess;
	int ret;

	if (protocol != CIFDS_SESSION_FLAG_SMB2)
		return NULL;

	sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
	if (!sess)
		return NULL;
@@ -325,32 +322,23 @@ static struct ksmbd_session *__session_create(int protocol)
	if (ksmbd_init_file_table(&sess->file_table))
		goto error;

	sess->state = SMB2_SESSION_IN_PROGRESS;
	set_session_flag(sess, protocol);
	xa_init(&sess->tree_conns);
	INIT_LIST_HEAD(&sess->ksmbd_chann_list);
	xa_init(&sess->ksmbd_chann_list);
	INIT_LIST_HEAD(&sess->rpc_handle_list);
	sess->sequence_number = 1;
	rwlock_init(&sess->chann_lock);

	switch (protocol) {
	case CIFDS_SESSION_FLAG_SMB2:
	ret = __init_smb2_session(sess);
		break;
	default:
		ret = -EINVAL;
		break;
	}

	if (ret)
		goto error;

	ida_init(&sess->tree_conn_ida);

	if (protocol == CIFDS_SESSION_FLAG_SMB2) {
	down_write(&sessions_table_lock);
	hash_add(sessions_table, &sess->hlist, sess->id);
	up_write(&sessions_table_lock);
	}

	return sess;

error:
+1 −3
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ struct ksmbd_file_table;
struct channel {
	__u8			smb3signingkey[SMB3_SIGN_KEY_SIZE];
	struct ksmbd_conn	*conn;
	struct list_head	chann_list;
};

struct preauth_session {
@@ -50,8 +49,7 @@ struct ksmbd_session {
	char				sess_key[CIFS_KEY_SIZE];

	struct hlist_node		hlist;
	rwlock_t			chann_lock;
	struct list_head		ksmbd_chann_list;
	struct xarray			ksmbd_chann_list;
	struct xarray			tree_conns;
	struct ida			tree_conn_ida;
	struct list_head		rpc_handle_list;
+2 −1
Original line number Diff line number Diff line
@@ -93,7 +93,8 @@ static inline int check_conn_state(struct ksmbd_work *work)
{
	struct smb_hdr *rsp_hdr;

	if (ksmbd_conn_exiting(work) || ksmbd_conn_need_reconnect(work)) {
	if (ksmbd_conn_exiting(work->conn) ||
	    ksmbd_conn_need_reconnect(work->conn)) {
		rsp_hdr = work->response_buf;
		rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
		return 1;
Loading