Commit 8976e9d0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.5-rc-ksmbd-server-fixes-part1' of git://git.samba.org/ksmbd

Pull ksmbd server updates from Steve French:

 - two fixes for compounding bugs (make sure no out of bound reads with
   less common combinations of commands in the compound)

 - eight minor cleanup patches (e.g. simplifying return values, replace
   one element array, use of kzalloc where simpler)

 - fix for clang warning on possible overflow in filename conversion

* tag '6.5-rc-ksmbd-server-fixes-part1' of git://git.samba.org/ksmbd:
  ksmbd: avoid field overflow warning
  ksmbd: Replace one-element array with flexible-array member
  ksmbd: Use struct_size() helper in ksmbd_negotiate_smb_dialect()
  ksmbd: add missing compound request handing in some commands
  ksmbd: fix out of bounds read in smb2_sess_setup
  ksmbd: Replace the ternary conditional operator with min()
  ksmbd: use kvzalloc instead of kvmalloc
  ksmbd: Change the return value of ksmbd_vfs_query_maximal_access to void
  ksmbd: return a literal instead of 'err' in ksmbd_vfs_kern_path_locked()
  ksmbd: use kzalloc() instead of __GFP_ZERO
  ksmbd: remove unused ksmbd_tree_conn_share function
parents ee152be1 9cedc58b
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -120,17 +120,6 @@ struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
	return tcon;
}

struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess,
						 unsigned int id)
{
	struct ksmbd_tree_connect *tc;

	tc = ksmbd_tree_conn_lookup(sess, id);
	if (tc)
		return tc->share_conf;
	return NULL;
}

int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
{
	int ret = 0;
+0 −3
Original line number Diff line number Diff line
@@ -53,9 +53,6 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
						  unsigned int id);

struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess,
						 unsigned int id);

int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess);

#endif /* __TREE_CONNECT_MANAGEMENT_H__ */
+75 −46
Original line number Diff line number Diff line
@@ -543,7 +543,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
	if (le32_to_cpu(hdr->NextCommand) > 0)
		sz = large_sz;

	work->response_buf = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO);
	work->response_buf = kvzalloc(sz, GFP_KERNEL);
	if (!work->response_buf)
		return -ENOMEM;

@@ -1322,9 +1322,8 @@ static int decode_negotiation_token(struct ksmbd_conn *conn,

static int ntlm_negotiate(struct ksmbd_work *work,
			  struct negotiate_message *negblob,
			  size_t negblob_len)
			  size_t negblob_len, struct smb2_sess_setup_rsp *rsp)
{
	struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf);
	struct challenge_message *chgblob;
	unsigned char *spnego_blob = NULL;
	u16 spnego_blob_len;
@@ -1429,10 +1428,10 @@ static struct ksmbd_user *session_user(struct ksmbd_conn *conn,
	return user;
}

static int ntlm_authenticate(struct ksmbd_work *work)
static int ntlm_authenticate(struct ksmbd_work *work,
			     struct smb2_sess_setup_req *req,
			     struct smb2_sess_setup_rsp *rsp)
{
	struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf);
	struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf);
	struct ksmbd_conn *conn = work->conn;
	struct ksmbd_session *sess = work->sess;
	struct channel *chann = NULL;
@@ -1566,10 +1565,10 @@ static int ntlm_authenticate(struct ksmbd_work *work)
}

#ifdef CONFIG_SMB_SERVER_KERBEROS5
static int krb5_authenticate(struct ksmbd_work *work)
static int krb5_authenticate(struct ksmbd_work *work,
			     struct smb2_sess_setup_req *req,
			     struct smb2_sess_setup_rsp *rsp)
{
	struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf);
	struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf);
	struct ksmbd_conn *conn = work->conn;
	struct ksmbd_session *sess = work->sess;
	char *in_blob, *out_blob;
@@ -1647,7 +1646,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
	return 0;
}
#else
static int krb5_authenticate(struct ksmbd_work *work)
static int krb5_authenticate(struct ksmbd_work *work,
			     struct smb2_sess_setup_req *req,
			     struct smb2_sess_setup_rsp *rsp)
{
	return -EOPNOTSUPP;
}
@@ -1656,8 +1657,8 @@ static int krb5_authenticate(struct ksmbd_work *work)
int smb2_sess_setup(struct ksmbd_work *work)
{
	struct ksmbd_conn *conn = work->conn;
	struct smb2_sess_setup_req *req = smb2_get_msg(work->request_buf);
	struct smb2_sess_setup_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_sess_setup_req *req;
	struct smb2_sess_setup_rsp *rsp;
	struct ksmbd_session *sess;
	struct negotiate_message *negblob;
	unsigned int negblob_len, negblob_off;
@@ -1665,6 +1666,8 @@ int smb2_sess_setup(struct ksmbd_work *work)

	ksmbd_debug(SMB, "Received request for session setup\n");

	WORK_BUFFERS(work, req, rsp);

	rsp->StructureSize = cpu_to_le16(9);
	rsp->SessionFlags = 0;
	rsp->SecurityBufferOffset = cpu_to_le16(72);
@@ -1786,7 +1789,7 @@ int smb2_sess_setup(struct ksmbd_work *work)

		if (conn->preferred_auth_mech &
				(KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) {
			rc = krb5_authenticate(work);
			rc = krb5_authenticate(work, req, rsp);
			if (rc) {
				rc = -EINVAL;
				goto out_err;
@@ -1800,7 +1803,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
			sess->Preauth_HashValue = NULL;
		} else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
			if (negblob->MessageType == NtLmNegotiate) {
				rc = ntlm_negotiate(work, negblob, negblob_len);
				rc = ntlm_negotiate(work, negblob, negblob_len, rsp);
				if (rc)
					goto out_err;
				rsp->hdr.Status =
@@ -1813,7 +1816,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
						le16_to_cpu(rsp->SecurityBufferLength) - 1);

			} else if (negblob->MessageType == NtLmAuthenticate) {
				rc = ntlm_authenticate(work);
				rc = ntlm_authenticate(work, req, rsp);
				if (rc)
					goto out_err;

@@ -1911,14 +1914,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
int smb2_tree_connect(struct ksmbd_work *work)
{
	struct ksmbd_conn *conn = work->conn;
	struct smb2_tree_connect_req *req = smb2_get_msg(work->request_buf);
	struct smb2_tree_connect_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_tree_connect_req *req;
	struct smb2_tree_connect_rsp *rsp;
	struct ksmbd_session *sess = work->sess;
	char *treename = NULL, *name = NULL;
	struct ksmbd_tree_conn_status status;
	struct ksmbd_share_config *share;
	int rc = -EINVAL;

	WORK_BUFFERS(work, req, rsp);

	treename = smb_strndup_from_utf16(req->Buffer,
					  le16_to_cpu(req->PathLength), true,
					  conn->local_nls);
@@ -2087,19 +2092,19 @@ static int smb2_create_open_flags(bool file_present, __le32 access,
 */
int smb2_tree_disconnect(struct ksmbd_work *work)
{
	struct smb2_tree_disconnect_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_tree_disconnect_rsp *rsp;
	struct smb2_tree_disconnect_req *req;
	struct ksmbd_session *sess = work->sess;
	struct ksmbd_tree_connect *tcon = work->tcon;

	WORK_BUFFERS(work, req, rsp);

	rsp->StructureSize = cpu_to_le16(4);
	inc_rfc1001_len(work->response_buf, 4);

	ksmbd_debug(SMB, "request\n");

	if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) {
		struct smb2_tree_disconnect_req *req =
			smb2_get_msg(work->request_buf);

		ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);

		rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
@@ -2122,10 +2127,14 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
int smb2_session_logoff(struct ksmbd_work *work)
{
	struct ksmbd_conn *conn = work->conn;
	struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_logoff_req *req;
	struct smb2_logoff_rsp *rsp;
	struct ksmbd_session *sess;
	struct smb2_logoff_req *req = smb2_get_msg(work->request_buf);
	u64 sess_id = le64_to_cpu(req->hdr.SessionId);
	u64 sess_id;

	WORK_BUFFERS(work, req, rsp);

	sess_id = le64_to_cpu(req->hdr.SessionId);

	rsp->StructureSize = cpu_to_le16(4);
	inc_rfc1001_len(work->response_buf, 4);
@@ -2165,12 +2174,14 @@ int smb2_session_logoff(struct ksmbd_work *work)
 */
static noinline int create_smb2_pipe(struct ksmbd_work *work)
{
	struct smb2_create_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_create_req *req = smb2_get_msg(work->request_buf);
	struct smb2_create_rsp *rsp;
	struct smb2_create_req *req;
	int id;
	int err;
	char *name;

	WORK_BUFFERS(work, req, rsp);

	name = smb_strndup_from_utf16(req->Buffer, le16_to_cpu(req->NameLength),
				      1, work->conn->local_nls);
	if (IS_ERR(name)) {
@@ -2872,11 +2883,9 @@ int smb2_open(struct ksmbd_work *work)
		if (!file_present) {
			daccess = cpu_to_le32(GENERIC_ALL_FLAGS);
		} else {
			rc = ksmbd_vfs_query_maximal_access(idmap,
			ksmbd_vfs_query_maximal_access(idmap,
							    path.dentry,
							    &daccess);
			if (rc)
				goto err_out;
			already_permitted = true;
		}
		maximal_access = daccess;
@@ -5305,8 +5314,10 @@ int smb2_query_info(struct ksmbd_work *work)
static noinline int smb2_close_pipe(struct ksmbd_work *work)
{
	u64 id;
	struct smb2_close_req *req = smb2_get_msg(work->request_buf);
	struct smb2_close_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_close_req *req;
	struct smb2_close_rsp *rsp;

	WORK_BUFFERS(work, req, rsp);

	id = req->VolatileFileId;
	ksmbd_session_rpc_close(work->sess, id);
@@ -5448,6 +5459,9 @@ int smb2_echo(struct ksmbd_work *work)
{
	struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf);

	if (work->next_smb2_rcv_hdr_off)
		rsp = ksmbd_resp_buf_next(work);

	rsp->StructureSize = cpu_to_le16(4);
	rsp->Reserved = 0;
	inc_rfc1001_len(work->response_buf, 4);
@@ -6082,8 +6096,10 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
	int nbytes = 0, err;
	u64 id;
	struct ksmbd_rpc_command *rpc_resp;
	struct smb2_read_req *req = smb2_get_msg(work->request_buf);
	struct smb2_read_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_read_req *req;
	struct smb2_read_rsp *rsp;

	WORK_BUFFERS(work, req, rsp);

	id = req->VolatileFileId;

@@ -6096,7 +6112,7 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
		}

		work->aux_payload_buf =
			kvmalloc(rpc_resp->payload_sz, GFP_KERNEL | __GFP_ZERO);
			kvmalloc(rpc_resp->payload_sz, GFP_KERNEL);
		if (!work->aux_payload_buf) {
			err = -ENOMEM;
			goto out;
@@ -6248,7 +6264,7 @@ int smb2_read(struct ksmbd_work *work)
	ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n",
		    fp->filp, offset, length);

	work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
	work->aux_payload_buf = kvzalloc(length, GFP_KERNEL);
	if (!work->aux_payload_buf) {
		err = -ENOMEM;
		goto out;
@@ -6331,14 +6347,16 @@ int smb2_read(struct ksmbd_work *work)
 */
static noinline int smb2_write_pipe(struct ksmbd_work *work)
{
	struct smb2_write_req *req = smb2_get_msg(work->request_buf);
	struct smb2_write_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_write_req *req;
	struct smb2_write_rsp *rsp;
	struct ksmbd_rpc_command *rpc_resp;
	u64 id = 0;
	int err = 0, ret = 0;
	char *data_buf;
	size_t length;

	WORK_BUFFERS(work, req, rsp);

	length = le32_to_cpu(req->Length);
	id = req->VolatileFileId;

@@ -6397,7 +6415,7 @@ static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work,
	int ret;
	ssize_t nbytes;

	data_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO);
	data_buf = kvzalloc(length, GFP_KERNEL);
	if (!data_buf)
		return -ENOMEM;

@@ -6607,6 +6625,9 @@ int smb2_cancel(struct ksmbd_work *work)
	struct ksmbd_work *iter;
	struct list_head *command_list;

	if (work->next_smb2_rcv_hdr_off)
		hdr = ksmbd_resp_buf_next(work);

	ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n",
		    hdr->MessageId, hdr->Flags);

@@ -6766,8 +6787,8 @@ static inline bool lock_defer_pending(struct file_lock *fl)
 */
int smb2_lock(struct ksmbd_work *work)
{
	struct smb2_lock_req *req = smb2_get_msg(work->request_buf);
	struct smb2_lock_rsp *rsp = smb2_get_msg(work->response_buf);
	struct smb2_lock_req *req;
	struct smb2_lock_rsp *rsp;
	struct smb2_lock_element *lock_ele;
	struct ksmbd_file *fp = NULL;
	struct file_lock *flock = NULL;
@@ -6784,6 +6805,8 @@ int smb2_lock(struct ksmbd_work *work)
	LIST_HEAD(rollback_list);
	int prior_lock = 0;

	WORK_BUFFERS(work, req, rsp);

	ksmbd_debug(SMB, "Received lock request\n");
	fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
	if (!fp) {
@@ -7897,8 +7920,8 @@ int smb2_ioctl(struct ksmbd_work *work)
 */
static void smb20_oplock_break_ack(struct ksmbd_work *work)
{
	struct smb2_oplock_break *req = smb2_get_msg(work->request_buf);
	struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf);
	struct smb2_oplock_break *req;
	struct smb2_oplock_break *rsp;
	struct ksmbd_file *fp;
	struct oplock_info *opinfo = NULL;
	__le32 err = 0;
@@ -7907,6 +7930,8 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
	char req_oplevel = 0, rsp_oplevel = 0;
	unsigned int oplock_change_type;

	WORK_BUFFERS(work, req, rsp);

	volatile_id = req->VolatileFid;
	persistent_id = req->PersistentFid;
	req_oplevel = req->OplockLevel;
@@ -8041,8 +8066,8 @@ static int check_lease_state(struct lease *lease, __le32 req_state)
static void smb21_lease_break_ack(struct ksmbd_work *work)
{
	struct ksmbd_conn *conn = work->conn;
	struct smb2_lease_ack *req = smb2_get_msg(work->request_buf);
	struct smb2_lease_ack *rsp = smb2_get_msg(work->response_buf);
	struct smb2_lease_ack *req;
	struct smb2_lease_ack *rsp;
	struct oplock_info *opinfo;
	__le32 err = 0;
	int ret = 0;
@@ -8050,6 +8075,8 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
	__le32 lease_state;
	struct lease *lease;

	WORK_BUFFERS(work, req, rsp);

	ksmbd_debug(OPLOCK, "smb21 lease break, lease state(0x%x)\n",
		    le32_to_cpu(req->LeaseState));
	opinfo = lookup_lease_in_table(conn, req->LeaseKey);
@@ -8175,8 +8202,10 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
 */
int smb2_oplock_break(struct ksmbd_work *work)
{
	struct smb2_oplock_break *req = smb2_get_msg(work->request_buf);
	struct smb2_oplock_break *rsp = smb2_get_msg(work->response_buf);
	struct smb2_oplock_break *req;
	struct smb2_oplock_break *rsp;

	WORK_BUFFERS(work, req, rsp);

	switch (le16_to_cpu(req->StructureSize)) {
	case OP_BREAK_STRUCT_SIZE_20:
+4 −4
Original line number Diff line number Diff line
@@ -266,7 +266,7 @@ static int ksmbd_negotiate_smb_dialect(void *buf)
		if (smb2_neg_size > smb_buf_length)
			goto err_out;

		if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >
		if (struct_size(req, Dialects, le16_to_cpu(req->DialectCount)) >
		    smb_buf_length)
			goto err_out;

@@ -359,8 +359,8 @@ static int smb1_check_user_session(struct ksmbd_work *work)
 */
static int smb1_allocate_rsp_buf(struct ksmbd_work *work)
{
	work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE,
			GFP_KERNEL | __GFP_ZERO);
	work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE,
			GFP_KERNEL);
	work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;

	if (!work->response_buf) {
@@ -536,7 +536,7 @@ int ksmbd_extract_shortname(struct ksmbd_conn *conn, const char *longname,
	out[baselen + 3] = PERIOD;

	if (dot_present)
		memcpy(&out[baselen + 4], extension, 4);
		memcpy(out + baselen + 4, extension, 4);
	else
		out[baselen + 4] = '\0';
	smbConvertToUTF16((__le16 *)shortname, out, PATH_MAX,
+1 −1
Original line number Diff line number Diff line
@@ -200,7 +200,7 @@ struct smb_hdr {
struct smb_negotiate_req {
	struct smb_hdr hdr;     /* wct = 0 */
	__le16 ByteCount;
	unsigned char DialectsArray[1];
	unsigned char DialectsArray[];
} __packed;

struct smb_negotiate_rsp {
Loading