Skip to content

Commit 39bdc41

Browse files
namjaejeongregkh
authored andcommitted
ksmbd: fix potencial out-of-bounds when buffer offset is invalid
[ Upstream commit c6cd2e8 ] 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: stable@vger.kernel.org Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 9e4937c commit 39bdc41

File tree

2 files changed

+42
-29
lines changed

2 files changed

+42
-29
lines changed

fs/smb/server/smb2misc.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
101101
*len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength);
102102
break;
103103
case SMB2_TREE_CONNECT:
104-
*off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset);
104+
*off = max_t(unsigned short int,
105+
le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset),
106+
offsetof(struct smb2_tree_connect_req, Buffer));
105107
*len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength);
106108
break;
107109
case SMB2_CREATE:
@@ -110,7 +112,6 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
110112
max_t(unsigned short int,
111113
le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset),
112114
offsetof(struct smb2_create_req, Buffer));
113-
114115
unsigned short int name_len =
115116
le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength);
116117

@@ -131,11 +132,15 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
131132
break;
132133
}
133134
case SMB2_QUERY_INFO:
134-
*off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset);
135+
*off = max_t(unsigned int,
136+
le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset),
137+
offsetof(struct smb2_query_info_req, Buffer));
135138
*len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength);
136139
break;
137140
case SMB2_SET_INFO:
138-
*off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset);
141+
*off = max_t(unsigned int,
142+
le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset),
143+
offsetof(struct smb2_set_info_req, Buffer));
139144
*len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength);
140145
break;
141146
case SMB2_READ:
@@ -145,7 +150,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
145150
case SMB2_WRITE:
146151
if (((struct smb2_write_req *)hdr)->DataOffset ||
147152
((struct smb2_write_req *)hdr)->Length) {
148-
*off = max_t(unsigned int,
153+
*off = max_t(unsigned short int,
149154
le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),
150155
offsetof(struct smb2_write_req, Buffer));
151156
*len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);
@@ -156,7 +161,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
156161
*len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength);
157162
break;
158163
case SMB2_QUERY_DIRECTORY:
159-
*off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset);
164+
*off = max_t(unsigned short int,
165+
le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset),
166+
offsetof(struct smb2_query_directory_req, Buffer));
160167
*len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength);
161168
break;
162169
case SMB2_LOCK:
@@ -171,7 +178,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
171178
break;
172179
}
173180
case SMB2_IOCTL:
174-
*off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset);
181+
*off = max_t(unsigned int,
182+
le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset),
183+
offsetof(struct smb2_ioctl_req, Buffer));
175184
*len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount);
176185
break;
177186
default:

fs/smb/server/smb2pdu.c

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

19321932
WORK_BUFFERS(work, req, rsp);
19331933

1934-
treename = smb_strndup_from_utf16(req->Buffer,
1934+
treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset),
19351935
le16_to_cpu(req->PathLength), true,
19361936
conn->local_nls);
19371937
if (IS_ERR(treename)) {
@@ -2844,7 +2844,7 @@ int smb2_open(struct ksmbd_work *work)
28442844
goto err_out2;
28452845
}
28462846

2847-
name = smb2_get_name(req->Buffer,
2847+
name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset),
28482848
le16_to_cpu(req->NameLength),
28492849
work->conn->local_nls);
28502850
if (IS_ERR(name)) {
@@ -4309,7 +4309,7 @@ int smb2_query_dir(struct ksmbd_work *work)
43094309
}
43104310

43114311
srch_flag = req->Flags;
4312-
srch_ptr = smb_strndup_from_utf16(req->Buffer,
4312+
srch_ptr = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->FileNameOffset),
43134313
le16_to_cpu(req->FileNameLength), 1,
43144314
conn->local_nls);
43154315
if (IS_ERR(srch_ptr)) {
@@ -4569,7 +4569,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
45694569
sizeof(struct smb2_ea_info_req))
45704570
return -EINVAL;
45714571

4572-
ea_req = (struct smb2_ea_info_req *)req->Buffer;
4572+
ea_req = (struct smb2_ea_info_req *)((char *)req +
4573+
le16_to_cpu(req->InputBufferOffset));
45734574
} else {
45744575
/* need to send all EAs, if no specific EA is requested*/
45754576
if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY)
@@ -6216,38 +6217,39 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
62166217
struct ksmbd_share_config *share)
62176218
{
62186219
unsigned int buf_len = le32_to_cpu(req->BufferLength);
6220+
char *buffer = (char *)req + le16_to_cpu(req->BufferOffset);
62196221

62206222
switch (req->FileInfoClass) {
62216223
case FILE_BASIC_INFORMATION:
62226224
{
62236225
if (buf_len < sizeof(struct smb2_file_basic_info))
62246226
return -EINVAL;
62256227

6226-
return set_file_basic_info(fp, (struct smb2_file_basic_info *)req->Buffer, share);
6228+
return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share);
62276229
}
62286230
case FILE_ALLOCATION_INFORMATION:
62296231
{
62306232
if (buf_len < sizeof(struct smb2_file_alloc_info))
62316233
return -EINVAL;
62326234

62336235
return set_file_allocation_info(work, fp,
6234-
(struct smb2_file_alloc_info *)req->Buffer);
6236+
(struct smb2_file_alloc_info *)buffer);
62356237
}
62366238
case FILE_END_OF_FILE_INFORMATION:
62376239
{
62386240
if (buf_len < sizeof(struct smb2_file_eof_info))
62396241
return -EINVAL;
62406242

62416243
return set_end_of_file_info(work, fp,
6242-
(struct smb2_file_eof_info *)req->Buffer);
6244+
(struct smb2_file_eof_info *)buffer);
62436245
}
62446246
case FILE_RENAME_INFORMATION:
62456247
{
62466248
if (buf_len < sizeof(struct smb2_file_rename_info))
62476249
return -EINVAL;
62486250

62496251
return set_rename_info(work, fp,
6250-
(struct smb2_file_rename_info *)req->Buffer,
6252+
(struct smb2_file_rename_info *)buffer,
62516253
buf_len);
62526254
}
62536255
case FILE_LINK_INFORMATION:
@@ -6256,7 +6258,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
62566258
return -EINVAL;
62576259

62586260
return smb2_create_link(work, work->tcon->share_conf,
6259-
(struct smb2_file_link_info *)req->Buffer,
6261+
(struct smb2_file_link_info *)buffer,
62606262
buf_len, fp->filp,
62616263
work->conn->local_nls);
62626264
}
@@ -6266,7 +6268,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
62666268
return -EINVAL;
62676269

62686270
return set_file_disposition_info(fp,
6269-
(struct smb2_file_disposition_info *)req->Buffer);
6271+
(struct smb2_file_disposition_info *)buffer);
62706272
}
62716273
case FILE_FULL_EA_INFORMATION:
62726274
{
@@ -6279,22 +6281,22 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
62796281
if (buf_len < sizeof(struct smb2_ea_info))
62806282
return -EINVAL;
62816283

6282-
return smb2_set_ea((struct smb2_ea_info *)req->Buffer,
6284+
return smb2_set_ea((struct smb2_ea_info *)buffer,
62836285
buf_len, &fp->filp->f_path, true);
62846286
}
62856287
case FILE_POSITION_INFORMATION:
62866288
{
62876289
if (buf_len < sizeof(struct smb2_file_pos_info))
62886290
return -EINVAL;
62896291

6290-
return set_file_position_info(fp, (struct smb2_file_pos_info *)req->Buffer);
6292+
return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer);
62916293
}
62926294
case FILE_MODE_INFORMATION:
62936295
{
62946296
if (buf_len < sizeof(struct smb2_file_mode_info))
62956297
return -EINVAL;
62966298

6297-
return set_file_mode_info(fp, (struct smb2_file_mode_info *)req->Buffer);
6299+
return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer);
62986300
}
62996301
}
63006302

@@ -6375,7 +6377,7 @@ int smb2_set_info(struct ksmbd_work *work)
63756377
}
63766378
rc = smb2_set_info_sec(fp,
63776379
le32_to_cpu(req->AdditionalInformation),
6378-
req->Buffer,
6380+
(char *)req + le16_to_cpu(req->BufferOffset),
63796381
le32_to_cpu(req->BufferLength));
63806382
ksmbd_revert_fsids(work);
63816383
break;
@@ -7821,7 +7823,7 @@ static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id,
78217823
struct smb2_ioctl_rsp *rsp)
78227824
{
78237825
struct ksmbd_rpc_command *rpc_resp;
7824-
char *data_buf = (char *)&req->Buffer[0];
7826+
char *data_buf = (char *)req + le32_to_cpu(req->InputOffset);
78257827
int nbytes = 0;
78267828

78277829
rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf,
@@ -7934,6 +7936,7 @@ int smb2_ioctl(struct ksmbd_work *work)
79347936
u64 id = KSMBD_NO_FID;
79357937
struct ksmbd_conn *conn = work->conn;
79367938
int ret = 0;
7939+
char *buffer;
79377940

79387941
if (work->next_smb2_rcv_hdr_off) {
79397942
req = ksmbd_req_buf_next(work);
@@ -7956,6 +7959,8 @@ int smb2_ioctl(struct ksmbd_work *work)
79567959
goto out;
79577960
}
79587961

7962+
buffer = (char *)req + le32_to_cpu(req->InputOffset);
7963+
79597964
cnt_code = le32_to_cpu(req->CtlCode);
79607965
ret = smb2_calc_max_out_buf_len(work, 48,
79617966
le32_to_cpu(req->MaxOutputResponse));
@@ -8013,7 +8018,7 @@ int smb2_ioctl(struct ksmbd_work *work)
80138018
}
80148019

80158020
ret = fsctl_validate_negotiate_info(conn,
8016-
(struct validate_negotiate_info_req *)&req->Buffer[0],
8021+
(struct validate_negotiate_info_req *)buffer,
80178022
(struct validate_negotiate_info_rsp *)&rsp->Buffer[0],
80188023
in_buf_len);
80198024
if (ret < 0)
@@ -8066,7 +8071,7 @@ int smb2_ioctl(struct ksmbd_work *work)
80668071
rsp->VolatileFileId = req->VolatileFileId;
80678072
rsp->PersistentFileId = req->PersistentFileId;
80688073
fsctl_copychunk(work,
8069-
(struct copychunk_ioctl_req *)&req->Buffer[0],
8074+
(struct copychunk_ioctl_req *)buffer,
80708075
le32_to_cpu(req->CtlCode),
80718076
le32_to_cpu(req->InputCount),
80728077
req->VolatileFileId,
@@ -8079,8 +8084,7 @@ int smb2_ioctl(struct ksmbd_work *work)
80798084
goto out;
80808085
}
80818086

8082-
ret = fsctl_set_sparse(work, id,
8083-
(struct file_sparse *)&req->Buffer[0]);
8087+
ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer);
80848088
if (ret < 0)
80858089
goto out;
80868090
break;
@@ -8103,7 +8107,7 @@ int smb2_ioctl(struct ksmbd_work *work)
81038107
}
81048108

81058109
zero_data =
8106-
(struct file_zero_data_information *)&req->Buffer[0];
8110+
(struct file_zero_data_information *)buffer;
81078111

81088112
off = le64_to_cpu(zero_data->FileOffset);
81098113
bfz = le64_to_cpu(zero_data->BeyondFinalZero);
@@ -8134,7 +8138,7 @@ int smb2_ioctl(struct ksmbd_work *work)
81348138
}
81358139

81368140
ret = fsctl_query_allocated_ranges(work, id,
8137-
(struct file_allocated_range_buffer *)&req->Buffer[0],
8141+
(struct file_allocated_range_buffer *)buffer,
81388142
(struct file_allocated_range_buffer *)&rsp->Buffer[0],
81398143
out_buf_len /
81408144
sizeof(struct file_allocated_range_buffer), &nbytes);
@@ -8178,7 +8182,7 @@ int smb2_ioctl(struct ksmbd_work *work)
81788182
goto out;
81798183
}
81808184

8181-
dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0];
8185+
dup_ext = (struct duplicate_extents_to_file *)buffer;
81828186

81838187
fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle,
81848188
dup_ext->PersistentFileHandle);

0 commit comments

Comments
 (0)