@@ -3762,6 +3762,24 @@ static int verify_info_level(int info_level)
3762
3762
return 0 ;
3763
3763
}
3764
3764
3765
+ static int smb2_calc_max_out_buf_len (struct ksmbd_work * work ,
3766
+ unsigned short hdr2_len ,
3767
+ unsigned int out_buf_len )
3768
+ {
3769
+ int free_len ;
3770
+
3771
+ if (out_buf_len > work -> conn -> vals -> max_trans_size )
3772
+ return - EINVAL ;
3773
+
3774
+ free_len = (int )(work -> response_sz -
3775
+ (get_rfc1002_len (work -> response_buf ) + 4 )) -
3776
+ hdr2_len ;
3777
+ if (free_len < 0 )
3778
+ return - EINVAL ;
3779
+
3780
+ return min_t (int , out_buf_len , free_len );
3781
+ }
3782
+
3765
3783
int smb2_query_dir (struct ksmbd_work * work )
3766
3784
{
3767
3785
struct ksmbd_conn * conn = work -> conn ;
@@ -3838,9 +3856,13 @@ int smb2_query_dir(struct ksmbd_work *work)
3838
3856
memset (& d_info , 0 , sizeof (struct ksmbd_dir_info ));
3839
3857
d_info .wptr = (char * )rsp -> Buffer ;
3840
3858
d_info .rptr = (char * )rsp -> Buffer ;
3841
- d_info .out_buf_len = (work -> response_sz - (get_rfc1002_len (rsp_org ) + 4 ));
3842
- d_info .out_buf_len = min_t (int , d_info .out_buf_len , le32_to_cpu (req -> OutputBufferLength )) -
3843
- sizeof (struct smb2_query_directory_rsp );
3859
+ d_info .out_buf_len =
3860
+ smb2_calc_max_out_buf_len (work , 8 ,
3861
+ le32_to_cpu (req -> OutputBufferLength ));
3862
+ if (d_info .out_buf_len < 0 ) {
3863
+ rc = - EINVAL ;
3864
+ goto err_out ;
3865
+ }
3844
3866
d_info .flags = srch_flag ;
3845
3867
3846
3868
/*
@@ -4074,12 +4096,11 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
4074
4096
le32_to_cpu (req -> Flags ));
4075
4097
}
4076
4098
4077
- buf_free_len = work -> response_sz -
4078
- (get_rfc1002_len (rsp_org ) + 4 ) -
4079
- sizeof (struct smb2_query_info_rsp );
4080
-
4081
- if (le32_to_cpu (req -> OutputBufferLength ) < buf_free_len )
4082
- buf_free_len = le32_to_cpu (req -> OutputBufferLength );
4099
+ buf_free_len =
4100
+ smb2_calc_max_out_buf_len (work , 8 ,
4101
+ le32_to_cpu (req -> OutputBufferLength ));
4102
+ if (buf_free_len < 0 )
4103
+ return - EINVAL ;
4083
4104
4084
4105
rc = ksmbd_vfs_listxattr (path -> dentry , & xattr_list );
4085
4106
if (rc < 0 ) {
@@ -4390,6 +4411,8 @@ static void get_file_stream_info(struct ksmbd_work *work,
4390
4411
struct path * path = & fp -> filp -> f_path ;
4391
4412
ssize_t xattr_list_len ;
4392
4413
int nbytes = 0 , streamlen , stream_name_len , next , idx = 0 ;
4414
+ int buf_free_len ;
4415
+ struct smb2_query_info_req * req = ksmbd_req_buf_next (work );
4393
4416
4394
4417
generic_fillattr (file_mnt_user_ns (fp -> filp ), file_inode (fp -> filp ),
4395
4418
& stat );
@@ -4403,6 +4426,12 @@ static void get_file_stream_info(struct ksmbd_work *work,
4403
4426
goto out ;
4404
4427
}
4405
4428
4429
+ buf_free_len =
4430
+ smb2_calc_max_out_buf_len (work , 8 ,
4431
+ le32_to_cpu (req -> OutputBufferLength ));
4432
+ if (buf_free_len < 0 )
4433
+ goto out ;
4434
+
4406
4435
while (idx < xattr_list_len ) {
4407
4436
stream_name = xattr_list + idx ;
4408
4437
streamlen = strlen (stream_name );
@@ -4427,6 +4456,10 @@ static void get_file_stream_info(struct ksmbd_work *work,
4427
4456
streamlen = snprintf (stream_buf , streamlen + 1 ,
4428
4457
":%s" , & stream_name [XATTR_NAME_STREAM_LEN ]);
4429
4458
4459
+ next = sizeof (struct smb2_file_stream_info ) + streamlen * 2 ;
4460
+ if (next > buf_free_len )
4461
+ break ;
4462
+
4430
4463
file_info = (struct smb2_file_stream_info * )& rsp -> Buffer [nbytes ];
4431
4464
streamlen = smbConvertToUTF16 ((__le16 * )file_info -> StreamName ,
4432
4465
stream_buf , streamlen ,
@@ -4437,12 +4470,13 @@ static void get_file_stream_info(struct ksmbd_work *work,
4437
4470
file_info -> StreamSize = cpu_to_le64 (stream_name_len );
4438
4471
file_info -> StreamAllocationSize = cpu_to_le64 (stream_name_len );
4439
4472
4440
- next = sizeof (struct smb2_file_stream_info ) + streamlen ;
4441
4473
nbytes += next ;
4474
+ buf_free_len -= next ;
4442
4475
file_info -> NextEntryOffset = cpu_to_le32 (next );
4443
4476
}
4444
4477
4445
- if (!S_ISDIR (stat .mode )) {
4478
+ if (!S_ISDIR (stat .mode ) &&
4479
+ buf_free_len >= sizeof (struct smb2_file_stream_info ) + 7 * 2 ) {
4446
4480
file_info = (struct smb2_file_stream_info * )
4447
4481
& rsp -> Buffer [nbytes ];
4448
4482
streamlen = smbConvertToUTF16 ((__le16 * )file_info -> StreamName ,
@@ -7453,11 +7487,13 @@ int smb2_ioctl(struct ksmbd_work *work)
7453
7487
}
7454
7488
7455
7489
cnt_code = le32_to_cpu (req -> CntCode );
7456
- out_buf_len = le32_to_cpu (req -> MaxOutputResponse );
7457
- out_buf_len =
7458
- min_t (u32 , work -> response_sz - work -> next_smb2_rsp_hdr_off -
7459
- (offsetof(struct smb2_ioctl_rsp , Buffer ) - 4 ),
7460
- out_buf_len );
7490
+ ret = smb2_calc_max_out_buf_len (work , 48 ,
7491
+ le32_to_cpu (req -> MaxOutputResponse ));
7492
+ if (ret < 0 ) {
7493
+ rsp -> hdr .Status = STATUS_INVALID_PARAMETER ;
7494
+ goto out ;
7495
+ }
7496
+ out_buf_len = (unsigned int )ret ;
7461
7497
in_buf_len = le32_to_cpu (req -> InputCount );
7462
7498
7463
7499
switch (cnt_code ) {
0 commit comments