@@ -7023,24 +7023,26 @@ int smb2_lock(struct ksmbd_work *work)
7023
7023
return err ;
7024
7024
}
7025
7025
7026
- static int fsctl_copychunk (struct ksmbd_work * work , struct smb2_ioctl_req * req ,
7026
+ static int fsctl_copychunk (struct ksmbd_work * work ,
7027
+ struct copychunk_ioctl_req * ci_req ,
7028
+ unsigned int cnt_code ,
7029
+ unsigned int input_count ,
7030
+ unsigned long long volatile_id ,
7031
+ unsigned long long persistent_id ,
7027
7032
struct smb2_ioctl_rsp * rsp )
7028
7033
{
7029
- struct copychunk_ioctl_req * ci_req ;
7030
7034
struct copychunk_ioctl_rsp * ci_rsp ;
7031
7035
struct ksmbd_file * src_fp = NULL , * dst_fp = NULL ;
7032
7036
struct srv_copychunk * chunks ;
7033
7037
unsigned int i , chunk_count , chunk_count_written = 0 ;
7034
7038
unsigned int chunk_size_written = 0 ;
7035
7039
loff_t total_size_written = 0 ;
7036
- int ret , cnt_code ;
7040
+ int ret = 0 ;
7037
7041
7038
- cnt_code = le32_to_cpu (req -> CntCode );
7039
- ci_req = (struct copychunk_ioctl_req * )& req -> Buffer [0 ];
7040
7042
ci_rsp = (struct copychunk_ioctl_rsp * )& rsp -> Buffer [0 ];
7041
7043
7042
- rsp -> VolatileFileId = req -> VolatileFileId ;
7043
- rsp -> PersistentFileId = req -> PersistentFileId ;
7044
+ rsp -> VolatileFileId = cpu_to_le64 ( volatile_id ) ;
7045
+ rsp -> PersistentFileId = cpu_to_le64 ( persistent_id ) ;
7044
7046
ci_rsp -> ChunksWritten =
7045
7047
cpu_to_le32 (ksmbd_server_side_copy_max_chunk_count ());
7046
7048
ci_rsp -> ChunkBytesWritten =
@@ -7050,12 +7052,13 @@ static int fsctl_copychunk(struct ksmbd_work *work, struct smb2_ioctl_req *req,
7050
7052
7051
7053
chunks = (struct srv_copychunk * )& ci_req -> Chunks [0 ];
7052
7054
chunk_count = le32_to_cpu (ci_req -> ChunkCount );
7055
+ if (chunk_count == 0 )
7056
+ goto out ;
7053
7057
total_size_written = 0 ;
7054
7058
7055
7059
/* verify the SRV_COPYCHUNK_COPY packet */
7056
7060
if (chunk_count > ksmbd_server_side_copy_max_chunk_count () ||
7057
- le32_to_cpu (req -> InputCount ) <
7058
- offsetof(struct copychunk_ioctl_req , Chunks ) +
7061
+ input_count < offsetof(struct copychunk_ioctl_req , Chunks ) +
7059
7062
chunk_count * sizeof (struct srv_copychunk )) {
7060
7063
rsp -> hdr .Status = STATUS_INVALID_PARAMETER ;
7061
7064
return - EINVAL ;
@@ -7076,9 +7079,7 @@ static int fsctl_copychunk(struct ksmbd_work *work, struct smb2_ioctl_req *req,
7076
7079
7077
7080
src_fp = ksmbd_lookup_foreign_fd (work ,
7078
7081
le64_to_cpu (ci_req -> ResumeKey [0 ]));
7079
- dst_fp = ksmbd_lookup_fd_slow (work ,
7080
- le64_to_cpu (req -> VolatileFileId ),
7081
- le64_to_cpu (req -> PersistentFileId ));
7082
+ dst_fp = ksmbd_lookup_fd_slow (work , volatile_id , persistent_id );
7082
7083
ret = - EINVAL ;
7083
7084
if (!src_fp ||
7084
7085
src_fp -> persistent_id != le64_to_cpu (ci_req -> ResumeKey [1 ])) {
@@ -7153,8 +7154,8 @@ static __be32 idev_ipv4_address(struct in_device *idev)
7153
7154
}
7154
7155
7155
7156
static int fsctl_query_iface_info_ioctl (struct ksmbd_conn * conn ,
7156
- struct smb2_ioctl_req * req ,
7157
- struct smb2_ioctl_rsp * rsp )
7157
+ struct smb2_ioctl_rsp * rsp ,
7158
+ unsigned int out_buf_len )
7158
7159
{
7159
7160
struct network_interface_info_ioctl_rsp * nii_rsp = NULL ;
7160
7161
int nbytes = 0 ;
@@ -7166,6 +7167,12 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn,
7166
7167
7167
7168
rtnl_lock ();
7168
7169
for_each_netdev (& init_net , netdev ) {
7170
+ if (out_buf_len <
7171
+ nbytes + sizeof (struct network_interface_info_ioctl_rsp )) {
7172
+ rtnl_unlock ();
7173
+ return - ENOSPC ;
7174
+ }
7175
+
7169
7176
if (netdev -> type == ARPHRD_LOOPBACK )
7170
7177
continue ;
7171
7178
@@ -7245,23 +7252,23 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn,
7245
7252
if (nii_rsp )
7246
7253
nii_rsp -> Next = 0 ;
7247
7254
7248
- if (!nbytes ) {
7249
- rsp -> hdr .Status = STATUS_BUFFER_TOO_SMALL ;
7250
- return - EINVAL ;
7251
- }
7252
-
7253
7255
rsp -> PersistentFileId = cpu_to_le64 (SMB2_NO_FID );
7254
7256
rsp -> VolatileFileId = cpu_to_le64 (SMB2_NO_FID );
7255
7257
return nbytes ;
7256
7258
}
7257
7259
7258
7260
static int fsctl_validate_negotiate_info (struct ksmbd_conn * conn ,
7259
7261
struct validate_negotiate_info_req * neg_req ,
7260
- struct validate_negotiate_info_rsp * neg_rsp )
7262
+ struct validate_negotiate_info_rsp * neg_rsp ,
7263
+ unsigned int in_buf_len )
7261
7264
{
7262
7265
int ret = 0 ;
7263
7266
int dialect ;
7264
7267
7268
+ if (in_buf_len < sizeof (struct validate_negotiate_info_req ) +
7269
+ le16_to_cpu (neg_req -> DialectCount ) * sizeof (__le16 ))
7270
+ return - EINVAL ;
7271
+
7265
7272
dialect = ksmbd_lookup_dialect_by_id (neg_req -> Dialects ,
7266
7273
neg_req -> DialectCount );
7267
7274
if (dialect == BAD_PROT_ID || dialect != conn -> dialect ) {
@@ -7295,7 +7302,7 @@ static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn,
7295
7302
static int fsctl_query_allocated_ranges (struct ksmbd_work * work , u64 id ,
7296
7303
struct file_allocated_range_buffer * qar_req ,
7297
7304
struct file_allocated_range_buffer * qar_rsp ,
7298
- int in_count , int * out_count )
7305
+ unsigned int in_count , unsigned int * out_count )
7299
7306
{
7300
7307
struct ksmbd_file * fp ;
7301
7308
loff_t start , length ;
@@ -7322,7 +7329,8 @@ static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id,
7322
7329
}
7323
7330
7324
7331
static int fsctl_pipe_transceive (struct ksmbd_work * work , u64 id ,
7325
- int out_buf_len , struct smb2_ioctl_req * req ,
7332
+ unsigned int out_buf_len ,
7333
+ struct smb2_ioctl_req * req ,
7326
7334
struct smb2_ioctl_rsp * rsp )
7327
7335
{
7328
7336
struct ksmbd_rpc_command * rpc_resp ;
@@ -7436,8 +7444,7 @@ int smb2_ioctl(struct ksmbd_work *work)
7436
7444
{
7437
7445
struct smb2_ioctl_req * req ;
7438
7446
struct smb2_ioctl_rsp * rsp , * rsp_org ;
7439
- int cnt_code , nbytes = 0 ;
7440
- int out_buf_len ;
7447
+ unsigned int cnt_code , nbytes = 0 , out_buf_len , in_buf_len ;
7441
7448
u64 id = KSMBD_NO_FID ;
7442
7449
struct ksmbd_conn * conn = work -> conn ;
7443
7450
int ret = 0 ;
@@ -7466,7 +7473,11 @@ int smb2_ioctl(struct ksmbd_work *work)
7466
7473
7467
7474
cnt_code = le32_to_cpu (req -> CntCode );
7468
7475
out_buf_len = le32_to_cpu (req -> MaxOutputResponse );
7469
- out_buf_len = min (KSMBD_IPC_MAX_PAYLOAD , out_buf_len );
7476
+ out_buf_len =
7477
+ min_t (u32 , work -> response_sz - work -> next_smb2_rsp_hdr_off -
7478
+ (offsetof(struct smb2_ioctl_rsp , Buffer ) - 4 ),
7479
+ out_buf_len );
7480
+ in_buf_len = le32_to_cpu (req -> InputCount );
7470
7481
7471
7482
switch (cnt_code ) {
7472
7483
case FSCTL_DFS_GET_REFERRALS :
@@ -7494,6 +7505,7 @@ int smb2_ioctl(struct ksmbd_work *work)
7494
7505
break ;
7495
7506
}
7496
7507
case FSCTL_PIPE_TRANSCEIVE :
7508
+ out_buf_len = min_t (u32 , KSMBD_IPC_MAX_PAYLOAD , out_buf_len );
7497
7509
nbytes = fsctl_pipe_transceive (work , id , out_buf_len , req , rsp );
7498
7510
break ;
7499
7511
case FSCTL_VALIDATE_NEGOTIATE_INFO :
@@ -7502,9 +7514,16 @@ int smb2_ioctl(struct ksmbd_work *work)
7502
7514
goto out ;
7503
7515
}
7504
7516
7517
+ if (in_buf_len < sizeof (struct validate_negotiate_info_req ))
7518
+ return - EINVAL ;
7519
+
7520
+ if (out_buf_len < sizeof (struct validate_negotiate_info_rsp ))
7521
+ return - EINVAL ;
7522
+
7505
7523
ret = fsctl_validate_negotiate_info (conn ,
7506
7524
(struct validate_negotiate_info_req * )& req -> Buffer [0 ],
7507
- (struct validate_negotiate_info_rsp * )& rsp -> Buffer [0 ]);
7525
+ (struct validate_negotiate_info_rsp * )& rsp -> Buffer [0 ],
7526
+ in_buf_len );
7508
7527
if (ret < 0 )
7509
7528
goto out ;
7510
7529
@@ -7513,9 +7532,10 @@ int smb2_ioctl(struct ksmbd_work *work)
7513
7532
rsp -> VolatileFileId = cpu_to_le64 (SMB2_NO_FID );
7514
7533
break ;
7515
7534
case FSCTL_QUERY_NETWORK_INTERFACE_INFO :
7516
- nbytes = fsctl_query_iface_info_ioctl (conn , req , rsp );
7517
- if (nbytes < 0 )
7535
+ ret = fsctl_query_iface_info_ioctl (conn , rsp , out_buf_len );
7536
+ if (ret < 0 )
7518
7537
goto out ;
7538
+ nbytes = ret ;
7519
7539
break ;
7520
7540
case FSCTL_REQUEST_RESUME_KEY :
7521
7541
if (out_buf_len < sizeof (struct resume_key_ioctl_rsp )) {
@@ -7540,15 +7560,33 @@ int smb2_ioctl(struct ksmbd_work *work)
7540
7560
goto out ;
7541
7561
}
7542
7562
7563
+ if (in_buf_len < sizeof (struct copychunk_ioctl_req )) {
7564
+ ret = - EINVAL ;
7565
+ goto out ;
7566
+ }
7567
+
7543
7568
if (out_buf_len < sizeof (struct copychunk_ioctl_rsp )) {
7544
7569
ret = - EINVAL ;
7545
7570
goto out ;
7546
7571
}
7547
7572
7548
7573
nbytes = sizeof (struct copychunk_ioctl_rsp );
7549
- fsctl_copychunk (work , req , rsp );
7574
+ rsp -> VolatileFileId = req -> VolatileFileId ;
7575
+ rsp -> PersistentFileId = req -> PersistentFileId ;
7576
+ fsctl_copychunk (work ,
7577
+ (struct copychunk_ioctl_req * )& req -> Buffer [0 ],
7578
+ le32_to_cpu (req -> CntCode ),
7579
+ le32_to_cpu (req -> InputCount ),
7580
+ le64_to_cpu (req -> VolatileFileId ),
7581
+ le64_to_cpu (req -> PersistentFileId ),
7582
+ rsp );
7550
7583
break ;
7551
7584
case FSCTL_SET_SPARSE :
7585
+ if (in_buf_len < sizeof (struct file_sparse )) {
7586
+ ret = - EINVAL ;
7587
+ goto out ;
7588
+ }
7589
+
7552
7590
ret = fsctl_set_sparse (work , id ,
7553
7591
(struct file_sparse * )& req -> Buffer [0 ]);
7554
7592
if (ret < 0 )
@@ -7567,6 +7605,11 @@ int smb2_ioctl(struct ksmbd_work *work)
7567
7605
goto out ;
7568
7606
}
7569
7607
7608
+ if (in_buf_len < sizeof (struct file_zero_data_information )) {
7609
+ ret = - EINVAL ;
7610
+ goto out ;
7611
+ }
7612
+
7570
7613
zero_data =
7571
7614
(struct file_zero_data_information * )& req -> Buffer [0 ];
7572
7615
@@ -7586,6 +7629,11 @@ int smb2_ioctl(struct ksmbd_work *work)
7586
7629
break ;
7587
7630
}
7588
7631
case FSCTL_QUERY_ALLOCATED_RANGES :
7632
+ if (in_buf_len < sizeof (struct file_allocated_range_buffer )) {
7633
+ ret = - EINVAL ;
7634
+ goto out ;
7635
+ }
7636
+
7589
7637
ret = fsctl_query_allocated_ranges (work , id ,
7590
7638
(struct file_allocated_range_buffer * )& req -> Buffer [0 ],
7591
7639
(struct file_allocated_range_buffer * )& rsp -> Buffer [0 ],
@@ -7626,6 +7674,11 @@ int smb2_ioctl(struct ksmbd_work *work)
7626
7674
struct duplicate_extents_to_file * dup_ext ;
7627
7675
loff_t src_off , dst_off , length , cloned ;
7628
7676
7677
+ if (in_buf_len < sizeof (struct duplicate_extents_to_file )) {
7678
+ ret = - EINVAL ;
7679
+ goto out ;
7680
+ }
7681
+
7629
7682
dup_ext = (struct duplicate_extents_to_file * )& req -> Buffer [0 ];
7630
7683
7631
7684
fp_in = ksmbd_lookup_fd_slow (work , dup_ext -> VolatileFileHandle ,
@@ -7696,6 +7749,8 @@ int smb2_ioctl(struct ksmbd_work *work)
7696
7749
rsp -> hdr .Status = STATUS_OBJECT_NAME_NOT_FOUND ;
7697
7750
else if (ret == - EOPNOTSUPP )
7698
7751
rsp -> hdr .Status = STATUS_NOT_SUPPORTED ;
7752
+ else if (ret == - ENOSPC )
7753
+ rsp -> hdr .Status = STATUS_BUFFER_TOO_SMALL ;
7699
7754
else if (ret < 0 || rsp -> hdr .Status == 0 )
7700
7755
rsp -> hdr .Status = STATUS_INVALID_PARAMETER ;
7701
7756
smb2_set_err_rsp (work );
0 commit comments