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

ksmbd: fix wrong interim response on compound



If smb2_lock or smb2_open request is compound, ksmbd could send wrong
interim response to client. ksmbd allocate new interim buffer instead of
using resonse buffer to support compound request.

Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent e2b76ab8
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -160,9 +160,11 @@ int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
	return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);
}

void ksmbd_iov_reset(struct ksmbd_work *work)
int allocate_interim_rsp_buf(struct ksmbd_work *work)
{
	work->iov_idx = 0;
	work->iov_cnt = 0;
	*(__be32 *)work->iov[0].iov_base = 0;
	work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
	if (!work->response_buf)
		return -ENOMEM;
	work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -131,5 +131,5 @@ bool ksmbd_queue_work(struct ksmbd_work *work);
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
			   void *aux_buf, unsigned int aux_size);
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len);
void ksmbd_iov_reset(struct ksmbd_work *work);
int allocate_interim_rsp_buf(struct ksmbd_work *work);
#endif /* __KSMBD_WORK_H__ */
+2 −12
Original line number Diff line number Diff line
@@ -616,15 +616,6 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
	return 0;
}

static inline int allocate_oplock_break_buf(struct ksmbd_work *work)
{
	work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
	if (!work->response_buf)
		return -ENOMEM;
	work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
	return 0;
}

/**
 * __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn
 * to client
@@ -647,7 +638,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
	if (!fp)
		goto out;

	if (allocate_oplock_break_buf(work)) {
	if (allocate_interim_rsp_buf(work)) {
		pr_err("smb2_allocate_rsp_buf failed! ");
		ksmbd_fd_put(work, fp);
		goto out;
@@ -752,7 +743,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
	struct lease_break_info *br_info = work->request_buf;
	struct smb2_hdr *rsp_hdr;

	if (allocate_oplock_break_buf(work)) {
	if (allocate_interim_rsp_buf(work)) {
		ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");
		goto out;
	}
@@ -843,7 +834,6 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
			setup_async_work(in_work, NULL, NULL);
			smb2_send_interim_resp(in_work, STATUS_PENDING);
			list_del(&in_work->interim_entry);
			ksmbd_iov_reset(in_work);
		}
		INIT_WORK(&work->work, __smb2_lease_break_noti);
		ksmbd_queue_work(work);
+17 −9
Original line number Diff line number Diff line
@@ -153,7 +153,7 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
		err_rsp->ByteCount = 0;
		err_rsp->ErrorData[0] = 0;
		err = ksmbd_iov_pin_rsp(work, (void *)err_rsp,
				  work->conn->vals->header_size +
					__SMB2_HEADER_STRUCTURE_SIZE +
						SMB2_ERROR_STRUCTURE_SIZE2);
		if (err)
			work->send_no_response = 1;
@@ -709,13 +709,24 @@ void release_async_work(struct ksmbd_work *work)
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
{
	struct smb2_hdr *rsp_hdr;
	struct ksmbd_work *in_work = ksmbd_alloc_work_struct();

	rsp_hdr = ksmbd_resp_buf_next(work);
	smb2_set_err_rsp(work);
	if (allocate_interim_rsp_buf(in_work)) {
		pr_err("smb_allocate_rsp_buf failed!\n");
		ksmbd_free_work_struct(in_work);
		return;
	}

	in_work->conn = work->conn;
	memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
	       __SMB2_HEADER_STRUCTURE_SIZE);

	rsp_hdr = smb2_get_msg(in_work->response_buf);
	smb2_set_err_rsp(in_work);
	rsp_hdr->Status = status;

	ksmbd_conn_write(work);
	rsp_hdr->Status = 0;
	ksmbd_conn_write(in_work);
	ksmbd_free_work_struct(in_work);
}

static __le32 smb2_get_reparse_tag_special_file(umode_t mode)
@@ -7049,8 +7060,6 @@ int smb2_lock(struct ksmbd_work *work)
				list_del(&work->fp_entry);
				spin_unlock(&fp->f_lock);

				ksmbd_iov_reset(work);

				if (work->state != KSMBD_WORK_ACTIVE) {
					list_del(&smb_lock->llist);
					spin_lock(&work->conn->llist_lock);
@@ -7068,7 +7077,6 @@ int smb2_lock(struct ksmbd_work *work)
						goto out;
					}

					init_smb2_rsp_hdr(work);
					rsp->hdr.Status =
						STATUS_RANGE_NOT_LOCKED;
					kfree(smb_lock);