Skip to content

Commit 041bba4

Browse files
namjaejeonSteve French
authored andcommitted
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: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent e2b76ab commit 041bba4

File tree

4 files changed

+26
-26
lines changed

4 files changed

+26
-26
lines changed

fs/smb/server/ksmbd_work.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,11 @@ int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
160160
return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);
161161
}
162162

163-
void ksmbd_iov_reset(struct ksmbd_work *work)
163+
int allocate_interim_rsp_buf(struct ksmbd_work *work)
164164
{
165-
work->iov_idx = 0;
166-
work->iov_cnt = 0;
167-
*(__be32 *)work->iov[0].iov_base = 0;
165+
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
166+
if (!work->response_buf)
167+
return -ENOMEM;
168+
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
169+
return 0;
168170
}

fs/smb/server/ksmbd_work.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,5 @@ bool ksmbd_queue_work(struct ksmbd_work *work);
131131
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
132132
void *aux_buf, unsigned int aux_size);
133133
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len);
134-
void ksmbd_iov_reset(struct ksmbd_work *work);
134+
int allocate_interim_rsp_buf(struct ksmbd_work *work);
135135
#endif /* __KSMBD_WORK_H__ */

fs/smb/server/oplock.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -616,15 +616,6 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
616616
return 0;
617617
}
618618

619-
static inline int allocate_oplock_break_buf(struct ksmbd_work *work)
620-
{
621-
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
622-
if (!work->response_buf)
623-
return -ENOMEM;
624-
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
625-
return 0;
626-
}
627-
628619
/**
629620
* __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn
630621
* to client
@@ -647,7 +638,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
647638
if (!fp)
648639
goto out;
649640

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

755-
if (allocate_oplock_break_buf(work)) {
746+
if (allocate_interim_rsp_buf(work)) {
756747
ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");
757748
goto out;
758749
}
@@ -843,7 +834,6 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
843834
setup_async_work(in_work, NULL, NULL);
844835
smb2_send_interim_resp(in_work, STATUS_PENDING);
845836
list_del(&in_work->interim_entry);
846-
ksmbd_iov_reset(in_work);
847837
}
848838
INIT_WORK(&work->work, __smb2_lease_break_noti);
849839
ksmbd_queue_work(work);

fs/smb/server/smb2pdu.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
153153
err_rsp->ByteCount = 0;
154154
err_rsp->ErrorData[0] = 0;
155155
err = ksmbd_iov_pin_rsp(work, (void *)err_rsp,
156-
work->conn->vals->header_size +
157-
SMB2_ERROR_STRUCTURE_SIZE2);
156+
__SMB2_HEADER_STRUCTURE_SIZE +
157+
SMB2_ERROR_STRUCTURE_SIZE2);
158158
if (err)
159159
work->send_no_response = 1;
160160
}
@@ -709,13 +709,24 @@ void release_async_work(struct ksmbd_work *work)
709709
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
710710
{
711711
struct smb2_hdr *rsp_hdr;
712+
struct ksmbd_work *in_work = ksmbd_alloc_work_struct();
712713

713-
rsp_hdr = ksmbd_resp_buf_next(work);
714-
smb2_set_err_rsp(work);
714+
if (allocate_interim_rsp_buf(in_work)) {
715+
pr_err("smb_allocate_rsp_buf failed!\n");
716+
ksmbd_free_work_struct(in_work);
717+
return;
718+
}
719+
720+
in_work->conn = work->conn;
721+
memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
722+
__SMB2_HEADER_STRUCTURE_SIZE);
723+
724+
rsp_hdr = smb2_get_msg(in_work->response_buf);
725+
smb2_set_err_rsp(in_work);
715726
rsp_hdr->Status = status;
716727

717-
ksmbd_conn_write(work);
718-
rsp_hdr->Status = 0;
728+
ksmbd_conn_write(in_work);
729+
ksmbd_free_work_struct(in_work);
719730
}
720731

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

7052-
ksmbd_iov_reset(work);
7053-
70547063
if (work->state != KSMBD_WORK_ACTIVE) {
70557064
list_del(&smb_lock->llist);
70567065
spin_lock(&work->conn->llist_lock);
@@ -7068,7 +7077,6 @@ int smb2_lock(struct ksmbd_work *work)
70687077
goto out;
70697078
}
70707079

7071-
init_smb2_rsp_hdr(work);
70727080
rsp->hdr.Status =
70737081
STATUS_RANGE_NOT_LOCKED;
70747082
kfree(smb_lock);

0 commit comments

Comments
 (0)