Skip to content

Commit 53bea74

Browse files
namjaejeonvijay-suman
authored andcommitted
ksmbd: fix potencial out-of-bounds when buffer offset is invalid
commit c6cd2e8 upstream. I found potencial out-of-bounds when buffer offset fields of a few requests is invalid. This patch set the minimum value of buffer offset field to ->Buffer offset to validate buffer length. Cc: [email protected] Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]> Signed-off-by: Bin Lan <[email protected]> Signed-off-by: He Zhe <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit 480469f145e5abf83361e608734e421b7d99693d) Signed-off-by: Vijayendra Suman <[email protected]>
1 parent fe75ac0 commit 53bea74

File tree

2 files changed

+41
-28
lines changed

2 files changed

+41
-28
lines changed

fs/ksmbd/smb2misc.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
102102
*len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength);
103103
break;
104104
case SMB2_TREE_CONNECT:
105-
*off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset);
105+
*off = max_t(unsigned short int,
106+
le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset),
107+
offsetof(struct smb2_tree_connect_req, Buffer));
106108
*len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength);
107109
break;
108110
case SMB2_CREATE:
@@ -129,11 +131,15 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
129131
break;
130132
}
131133
case SMB2_QUERY_INFO:
132-
*off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset);
134+
*off = max_t(unsigned int,
135+
le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset),
136+
offsetof(struct smb2_query_info_req, Buffer));
133137
*len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength);
134138
break;
135139
case SMB2_SET_INFO:
136-
*off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset);
140+
*off = max_t(unsigned int,
141+
le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset),
142+
offsetof(struct smb2_set_info_req, Buffer));
137143
*len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength);
138144
break;
139145
case SMB2_READ:
@@ -143,7 +149,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
143149
case SMB2_WRITE:
144150
if (((struct smb2_write_req *)hdr)->DataOffset ||
145151
((struct smb2_write_req *)hdr)->Length) {
146-
*off = max_t(unsigned int,
152+
*off = max_t(unsigned short int,
147153
le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),
148154
offsetof(struct smb2_write_req, Buffer) - 4);
149155
*len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);
@@ -154,7 +160,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
154160
*len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength);
155161
break;
156162
case SMB2_QUERY_DIRECTORY:
157-
*off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset);
163+
*off = max_t(unsigned short int,
164+
le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset),
165+
offsetof(struct smb2_query_directory_req, Buffer));
158166
*len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength);
159167
break;
160168
case SMB2_LOCK:
@@ -169,7 +177,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
169177
break;
170178
}
171179
case SMB2_IOCTL:
172-
*off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset);
180+
*off = max_t(unsigned int,
181+
le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset),
182+
offsetof(struct smb2_ioctl_req, Buffer));
173183
*len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount);
174184
break;
175185
default:

fs/ksmbd/smb2pdu.c

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,7 +1967,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
19671967

19681968
WORK_BUFFERS(work, req, rsp);
19691969

1970-
treename = smb_strndup_from_utf16(req->Buffer,
1970+
treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset),
19711971
le16_to_cpu(req->PathLength), true,
19721972
conn->local_nls);
19731973
if (IS_ERR(treename)) {
@@ -2714,7 +2714,7 @@ int smb2_open(struct ksmbd_work *work)
27142714
goto err_out2;
27152715
}
27162716

2717-
name = smb2_get_name(req->Buffer,
2717+
name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset),
27182718
le16_to_cpu(req->NameLength),
27192719
work->conn->local_nls);
27202720
if (IS_ERR(name)) {
@@ -4086,7 +4086,7 @@ int smb2_query_dir(struct ksmbd_work *work)
40864086
}
40874087

40884088
srch_flag = req->Flags;
4089-
srch_ptr = smb_strndup_from_utf16(req->Buffer,
4089+
srch_ptr = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->FileNameOffset),
40904090
le16_to_cpu(req->FileNameLength), 1,
40914091
conn->local_nls);
40924092
if (IS_ERR(srch_ptr)) {
@@ -4346,7 +4346,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
43464346
sizeof(struct smb2_ea_info_req))
43474347
return -EINVAL;
43484348

4349-
ea_req = (struct smb2_ea_info_req *)req->Buffer;
4349+
ea_req = (struct smb2_ea_info_req *)((char *)req +
4350+
le16_to_cpu(req->InputBufferOffset));
43504351
} else {
43514352
/* need to send all EAs, if no specific EA is requested*/
43524353
if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY)
@@ -5952,38 +5953,39 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
59525953
struct ksmbd_share_config *share)
59535954
{
59545955
unsigned int buf_len = le32_to_cpu(req->BufferLength);
5956+
char *buffer = (char *)req + le16_to_cpu(req->BufferOffset);
59555957

59565958
switch (req->FileInfoClass) {
59575959
case FILE_BASIC_INFORMATION:
59585960
{
59595961
if (buf_len < sizeof(struct smb2_file_basic_info))
59605962
return -EINVAL;
59615963

5962-
return set_file_basic_info(fp, (struct smb2_file_basic_info *)req->Buffer, share);
5964+
return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share);
59635965
}
59645966
case FILE_ALLOCATION_INFORMATION:
59655967
{
59665968
if (buf_len < sizeof(struct smb2_file_alloc_info))
59675969
return -EINVAL;
59685970

59695971
return set_file_allocation_info(work, fp,
5970-
(struct smb2_file_alloc_info *)req->Buffer);
5972+
(struct smb2_file_alloc_info *)buffer);
59715973
}
59725974
case FILE_END_OF_FILE_INFORMATION:
59735975
{
59745976
if (buf_len < sizeof(struct smb2_file_eof_info))
59755977
return -EINVAL;
59765978

59775979
return set_end_of_file_info(work, fp,
5978-
(struct smb2_file_eof_info *)req->Buffer);
5980+
(struct smb2_file_eof_info *)buffer);
59795981
}
59805982
case FILE_RENAME_INFORMATION:
59815983
{
59825984
if (buf_len < sizeof(struct smb2_file_rename_info))
59835985
return -EINVAL;
59845986

59855987
return set_rename_info(work, fp,
5986-
(struct smb2_file_rename_info *)req->Buffer,
5988+
(struct smb2_file_rename_info *)buffer,
59875989
buf_len);
59885990
}
59895991
case FILE_LINK_INFORMATION:
@@ -5992,7 +5994,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
59925994
return -EINVAL;
59935995

59945996
return smb2_create_link(work, work->tcon->share_conf,
5995-
(struct smb2_file_link_info *)req->Buffer,
5997+
(struct smb2_file_link_info *)buffer,
59965998
buf_len, fp->filp,
59975999
work->conn->local_nls);
59986000
}
@@ -6002,7 +6004,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
60026004
return -EINVAL;
60036005

60046006
return set_file_disposition_info(fp,
6005-
(struct smb2_file_disposition_info *)req->Buffer);
6007+
(struct smb2_file_disposition_info *)buffer);
60066008
}
60076009
case FILE_FULL_EA_INFORMATION:
60086010
{
@@ -6015,22 +6017,22 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
60156017
if (buf_len < sizeof(struct smb2_ea_info))
60166018
return -EINVAL;
60176019

6018-
return smb2_set_ea((struct smb2_ea_info *)req->Buffer,
6020+
return smb2_set_ea((struct smb2_ea_info *)buffer,
60196021
buf_len, &fp->filp->f_path, true);
60206022
}
60216023
case FILE_POSITION_INFORMATION:
60226024
{
60236025
if (buf_len < sizeof(struct smb2_file_pos_info))
60246026
return -EINVAL;
60256027

6026-
return set_file_position_info(fp, (struct smb2_file_pos_info *)req->Buffer);
6028+
return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer);
60276029
}
60286030
case FILE_MODE_INFORMATION:
60296031
{
60306032
if (buf_len < sizeof(struct smb2_file_mode_info))
60316033
return -EINVAL;
60326034

6033-
return set_file_mode_info(fp, (struct smb2_file_mode_info *)req->Buffer);
6035+
return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer);
60346036
}
60356037
}
60366038

@@ -6111,7 +6113,7 @@ int smb2_set_info(struct ksmbd_work *work)
61116113
}
61126114
rc = smb2_set_info_sec(fp,
61136115
le32_to_cpu(req->AdditionalInformation),
6114-
req->Buffer,
6116+
(char *)req + le16_to_cpu(req->BufferOffset),
61156117
le32_to_cpu(req->BufferLength));
61166118
ksmbd_revert_fsids(work);
61176119
break;
@@ -7563,7 +7565,7 @@ static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id,
75637565
struct smb2_ioctl_rsp *rsp)
75647566
{
75657567
struct ksmbd_rpc_command *rpc_resp;
7566-
char *data_buf = (char *)&req->Buffer[0];
7568+
char *data_buf = (char *)req + le32_to_cpu(req->InputOffset);
75677569
int nbytes = 0;
75687570

75697571
rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf,
@@ -7676,6 +7678,7 @@ int smb2_ioctl(struct ksmbd_work *work)
76767678
u64 id = KSMBD_NO_FID;
76777679
struct ksmbd_conn *conn = work->conn;
76787680
int ret = 0;
7681+
char *buffer;
76797682

76807683
if (work->next_smb2_rcv_hdr_off) {
76817684
req = ksmbd_req_buf_next(work);
@@ -7698,6 +7701,7 @@ int smb2_ioctl(struct ksmbd_work *work)
76987701
goto out;
76997702
}
77007703

7704+
buffer = (char *)req + le32_to_cpu(req->InputOffset);
77017705
cnt_code = le32_to_cpu(req->CntCode);
77027706
ret = smb2_calc_max_out_buf_len(work, 48,
77037707
le32_to_cpu(req->MaxOutputResponse));
@@ -7755,7 +7759,7 @@ int smb2_ioctl(struct ksmbd_work *work)
77557759
}
77567760

77577761
ret = fsctl_validate_negotiate_info(conn,
7758-
(struct validate_negotiate_info_req *)&req->Buffer[0],
7762+
(struct validate_negotiate_info_req *)buffer,
77597763
(struct validate_negotiate_info_rsp *)&rsp->Buffer[0],
77607764
in_buf_len);
77617765
if (ret < 0)
@@ -7808,7 +7812,7 @@ int smb2_ioctl(struct ksmbd_work *work)
78087812
rsp->VolatileFileId = req->VolatileFileId;
78097813
rsp->PersistentFileId = req->PersistentFileId;
78107814
fsctl_copychunk(work,
7811-
(struct copychunk_ioctl_req *)&req->Buffer[0],
7815+
(struct copychunk_ioctl_req *)buffer,
78127816
le32_to_cpu(req->CntCode),
78137817
le32_to_cpu(req->InputCount),
78147818
req->VolatileFileId,
@@ -7821,8 +7825,7 @@ int smb2_ioctl(struct ksmbd_work *work)
78217825
goto out;
78227826
}
78237827

7824-
ret = fsctl_set_sparse(work, id,
7825-
(struct file_sparse *)&req->Buffer[0]);
7828+
ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer);
78267829
if (ret < 0)
78277830
goto out;
78287831
break;
@@ -7845,7 +7848,7 @@ int smb2_ioctl(struct ksmbd_work *work)
78457848
}
78467849

78477850
zero_data =
7848-
(struct file_zero_data_information *)&req->Buffer[0];
7851+
(struct file_zero_data_information *)buffer;
78497852

78507853
off = le64_to_cpu(zero_data->FileOffset);
78517854
bfz = le64_to_cpu(zero_data->BeyondFinalZero);
@@ -7876,7 +7879,7 @@ int smb2_ioctl(struct ksmbd_work *work)
78767879
}
78777880

78787881
ret = fsctl_query_allocated_ranges(work, id,
7879-
(struct file_allocated_range_buffer *)&req->Buffer[0],
7882+
(struct file_allocated_range_buffer *)buffer,
78807883
(struct file_allocated_range_buffer *)&rsp->Buffer[0],
78817884
out_buf_len /
78827885
sizeof(struct file_allocated_range_buffer), &nbytes);
@@ -7920,7 +7923,7 @@ int smb2_ioctl(struct ksmbd_work *work)
79207923
goto out;
79217924
}
79227925

7923-
dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0];
7926+
dup_ext = (struct duplicate_extents_to_file *)buffer;
79247927

79257928
fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle,
79267929
dup_ext->PersistentFileHandle);

0 commit comments

Comments
 (0)