@@ -2102,16 +2102,22 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work)
2102
2102
* smb2_set_ea() - handler for setting extended attributes using set
2103
2103
* info command
2104
2104
* @eabuf: set info command buffer
2105
+ * @buf_len: set info command buffer length
2105
2106
* @path: dentry path for get ea
2106
2107
*
2107
2108
* Return: 0 on success, otherwise error
2108
2109
*/
2109
- static int smb2_set_ea (struct smb2_ea_info * eabuf , struct path * path )
2110
+ static int smb2_set_ea (struct smb2_ea_info * eabuf , unsigned int buf_len ,
2111
+ struct path * path )
2110
2112
{
2111
2113
struct user_namespace * user_ns = mnt_user_ns (path -> mnt );
2112
2114
char * attr_name = NULL , * value ;
2113
2115
int rc = 0 ;
2114
- int next = 0 ;
2116
+ unsigned int next = 0 ;
2117
+
2118
+ if (buf_len < sizeof (struct smb2_ea_info ) + eabuf -> EaNameLength +
2119
+ le16_to_cpu (eabuf -> EaValueLength ))
2120
+ return - EINVAL ;
2115
2121
2116
2122
attr_name = kmalloc (XATTR_NAME_MAX + 1 , GFP_KERNEL );
2117
2123
if (!attr_name )
@@ -2176,7 +2182,13 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, struct path *path)
2176
2182
2177
2183
next :
2178
2184
next = le32_to_cpu (eabuf -> NextEntryOffset );
2185
+ if (next == 0 || buf_len < next )
2186
+ break ;
2187
+ buf_len -= next ;
2179
2188
eabuf = (struct smb2_ea_info * )((char * )eabuf + next );
2189
+ if (next < (u32 )eabuf -> EaNameLength + le16_to_cpu (eabuf -> EaValueLength ))
2190
+ break ;
2191
+
2180
2192
} while (next != 0 );
2181
2193
2182
2194
kfree (attr_name );
@@ -2757,7 +2769,15 @@ int smb2_open(struct ksmbd_work *work)
2757
2769
created = true;
2758
2770
user_ns = mnt_user_ns (path .mnt );
2759
2771
if (ea_buf ) {
2760
- rc = smb2_set_ea (& ea_buf -> ea , & path );
2772
+ if (le32_to_cpu (ea_buf -> ccontext .DataLength ) <
2773
+ sizeof (struct smb2_ea_info )) {
2774
+ rc = - EINVAL ;
2775
+ goto err_out ;
2776
+ }
2777
+
2778
+ rc = smb2_set_ea (& ea_buf -> ea ,
2779
+ le32_to_cpu (ea_buf -> ccontext .DataLength ),
2780
+ & path );
2761
2781
if (rc == - EOPNOTSUPP )
2762
2782
rc = 0 ;
2763
2783
else if (rc )
@@ -5341,14 +5361,18 @@ static int smb2_rename(struct ksmbd_work *work,
5341
5361
static int smb2_create_link (struct ksmbd_work * work ,
5342
5362
struct ksmbd_share_config * share ,
5343
5363
struct smb2_file_link_info * file_info ,
5344
- struct file * filp ,
5364
+ unsigned int buf_len , struct file * filp ,
5345
5365
struct nls_table * local_nls )
5346
5366
{
5347
5367
char * link_name = NULL , * target_name = NULL , * pathname = NULL ;
5348
5368
struct path path ;
5349
5369
bool file_present = true;
5350
5370
int rc ;
5351
5371
5372
+ if (buf_len < (u64 )sizeof (struct smb2_file_link_info ) +
5373
+ le32_to_cpu (file_info -> FileNameLength ))
5374
+ return - EINVAL ;
5375
+
5352
5376
ksmbd_debug (SMB , "setting FILE_LINK_INFORMATION\n" );
5353
5377
pathname = kmalloc (PATH_MAX , GFP_KERNEL );
5354
5378
if (!pathname )
@@ -5408,10 +5432,10 @@ static int smb2_create_link(struct ksmbd_work *work,
5408
5432
return rc ;
5409
5433
}
5410
5434
5411
- static int set_file_basic_info (struct ksmbd_file * fp , char * buf ,
5435
+ static int set_file_basic_info (struct ksmbd_file * fp ,
5436
+ struct smb2_file_basic_info * file_info ,
5412
5437
struct ksmbd_share_config * share )
5413
5438
{
5414
- struct smb2_file_basic_info * file_info ;
5415
5439
struct iattr attrs ;
5416
5440
struct timespec64 ctime ;
5417
5441
struct file * filp ;
@@ -5422,7 +5446,6 @@ static int set_file_basic_info(struct ksmbd_file *fp, char *buf,
5422
5446
if (!(fp -> daccess & FILE_WRITE_ATTRIBUTES_LE ))
5423
5447
return - EACCES ;
5424
5448
5425
- file_info = (struct smb2_file_basic_info * )buf ;
5426
5449
attrs .ia_valid = 0 ;
5427
5450
filp = fp -> filp ;
5428
5451
inode = file_inode (filp );
@@ -5499,23 +5522,22 @@ static int set_file_basic_info(struct ksmbd_file *fp, char *buf,
5499
5522
}
5500
5523
5501
5524
static int set_file_allocation_info (struct ksmbd_work * work ,
5502
- struct ksmbd_file * fp , char * buf )
5525
+ struct ksmbd_file * fp ,
5526
+ struct smb2_file_alloc_info * file_alloc_info )
5503
5527
{
5504
5528
/*
5505
5529
* TODO : It's working fine only when store dos attributes
5506
5530
* is not yes. need to implement a logic which works
5507
5531
* properly with any smb.conf option
5508
5532
*/
5509
5533
5510
- struct smb2_file_alloc_info * file_alloc_info ;
5511
5534
loff_t alloc_blks ;
5512
5535
struct inode * inode ;
5513
5536
int rc ;
5514
5537
5515
5538
if (!(fp -> daccess & FILE_WRITE_DATA_LE ))
5516
5539
return - EACCES ;
5517
5540
5518
- file_alloc_info = (struct smb2_file_alloc_info * )buf ;
5519
5541
alloc_blks = (le64_to_cpu (file_alloc_info -> AllocationSize ) + 511 ) >> 9 ;
5520
5542
inode = file_inode (fp -> filp );
5521
5543
@@ -5551,17 +5573,15 @@ static int set_file_allocation_info(struct ksmbd_work *work,
5551
5573
}
5552
5574
5553
5575
static int set_end_of_file_info (struct ksmbd_work * work , struct ksmbd_file * fp ,
5554
- char * buf )
5576
+ struct smb2_file_eof_info * file_eof_info )
5555
5577
{
5556
- struct smb2_file_eof_info * file_eof_info ;
5557
5578
loff_t newsize ;
5558
5579
struct inode * inode ;
5559
5580
int rc ;
5560
5581
5561
5582
if (!(fp -> daccess & FILE_WRITE_DATA_LE ))
5562
5583
return - EACCES ;
5563
5584
5564
- file_eof_info = (struct smb2_file_eof_info * )buf ;
5565
5585
newsize = le64_to_cpu (file_eof_info -> EndOfFile );
5566
5586
inode = file_inode (fp -> filp );
5567
5587
@@ -5588,7 +5608,8 @@ static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp,
5588
5608
}
5589
5609
5590
5610
static int set_rename_info (struct ksmbd_work * work , struct ksmbd_file * fp ,
5591
- char * buf )
5611
+ struct smb2_file_rename_info * rename_info ,
5612
+ unsigned int buf_len )
5592
5613
{
5593
5614
struct user_namespace * user_ns ;
5594
5615
struct ksmbd_file * parent_fp ;
@@ -5601,6 +5622,10 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
5601
5622
return - EACCES ;
5602
5623
}
5603
5624
5625
+ if (buf_len < (u64 )sizeof (struct smb2_file_rename_info ) +
5626
+ le32_to_cpu (rename_info -> FileNameLength ))
5627
+ return - EINVAL ;
5628
+
5604
5629
user_ns = file_mnt_user_ns (fp -> filp );
5605
5630
if (ksmbd_stream_fd (fp ))
5606
5631
goto next ;
@@ -5623,14 +5648,13 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
5623
5648
}
5624
5649
}
5625
5650
next :
5626
- return smb2_rename (work , fp , user_ns ,
5627
- (struct smb2_file_rename_info * )buf ,
5651
+ return smb2_rename (work , fp , user_ns , rename_info ,
5628
5652
work -> sess -> conn -> local_nls );
5629
5653
}
5630
5654
5631
- static int set_file_disposition_info (struct ksmbd_file * fp , char * buf )
5655
+ static int set_file_disposition_info (struct ksmbd_file * fp ,
5656
+ struct smb2_file_disposition_info * file_info )
5632
5657
{
5633
- struct smb2_file_disposition_info * file_info ;
5634
5658
struct inode * inode ;
5635
5659
5636
5660
if (!(fp -> daccess & FILE_DELETE_LE )) {
@@ -5639,7 +5663,6 @@ static int set_file_disposition_info(struct ksmbd_file *fp, char *buf)
5639
5663
}
5640
5664
5641
5665
inode = file_inode (fp -> filp );
5642
- file_info = (struct smb2_file_disposition_info * )buf ;
5643
5666
if (file_info -> DeletePending ) {
5644
5667
if (S_ISDIR (inode -> i_mode ) &&
5645
5668
ksmbd_vfs_empty_dir (fp ) == - ENOTEMPTY )
@@ -5651,15 +5674,14 @@ static int set_file_disposition_info(struct ksmbd_file *fp, char *buf)
5651
5674
return 0 ;
5652
5675
}
5653
5676
5654
- static int set_file_position_info (struct ksmbd_file * fp , char * buf )
5677
+ static int set_file_position_info (struct ksmbd_file * fp ,
5678
+ struct smb2_file_pos_info * file_info )
5655
5679
{
5656
- struct smb2_file_pos_info * file_info ;
5657
5680
loff_t current_byte_offset ;
5658
5681
unsigned long sector_size ;
5659
5682
struct inode * inode ;
5660
5683
5661
5684
inode = file_inode (fp -> filp );
5662
- file_info = (struct smb2_file_pos_info * )buf ;
5663
5685
current_byte_offset = le64_to_cpu (file_info -> CurrentByteOffset );
5664
5686
sector_size = inode -> i_sb -> s_blocksize ;
5665
5687
@@ -5675,12 +5697,11 @@ static int set_file_position_info(struct ksmbd_file *fp, char *buf)
5675
5697
return 0 ;
5676
5698
}
5677
5699
5678
- static int set_file_mode_info (struct ksmbd_file * fp , char * buf )
5700
+ static int set_file_mode_info (struct ksmbd_file * fp ,
5701
+ struct smb2_file_mode_info * file_info )
5679
5702
{
5680
- struct smb2_file_mode_info * file_info ;
5681
5703
__le32 mode ;
5682
5704
5683
- file_info = (struct smb2_file_mode_info * )buf ;
5684
5705
mode = file_info -> Mode ;
5685
5706
5686
5707
if ((mode & ~FILE_MODE_INFO_MASK ) ||
@@ -5710,40 +5731,74 @@ static int set_file_mode_info(struct ksmbd_file *fp, char *buf)
5710
5731
* TODO: need to implement an error handling for STATUS_INFO_LENGTH_MISMATCH
5711
5732
*/
5712
5733
static int smb2_set_info_file (struct ksmbd_work * work , struct ksmbd_file * fp ,
5713
- int info_class , char * buf ,
5734
+ struct smb2_set_info_req * req ,
5714
5735
struct ksmbd_share_config * share )
5715
5736
{
5716
- switch (info_class ) {
5737
+ unsigned int buf_len = le32_to_cpu (req -> BufferLength );
5738
+
5739
+ switch (req -> FileInfoClass ) {
5717
5740
case FILE_BASIC_INFORMATION :
5718
- return set_file_basic_info (fp , buf , share );
5741
+ {
5742
+ if (buf_len < sizeof (struct smb2_file_basic_info ))
5743
+ return - EINVAL ;
5719
5744
5745
+ return set_file_basic_info (fp , (struct smb2_file_basic_info * )req -> Buffer , share );
5746
+ }
5720
5747
case FILE_ALLOCATION_INFORMATION :
5721
- return set_file_allocation_info (work , fp , buf );
5748
+ {
5749
+ if (buf_len < sizeof (struct smb2_file_alloc_info ))
5750
+ return - EINVAL ;
5722
5751
5752
+ return set_file_allocation_info (work , fp ,
5753
+ (struct smb2_file_alloc_info * )req -> Buffer );
5754
+ }
5723
5755
case FILE_END_OF_FILE_INFORMATION :
5724
- return set_end_of_file_info (work , fp , buf );
5756
+ {
5757
+ if (buf_len < sizeof (struct smb2_file_eof_info ))
5758
+ return - EINVAL ;
5725
5759
5760
+ return set_end_of_file_info (work , fp ,
5761
+ (struct smb2_file_eof_info * )req -> Buffer );
5762
+ }
5726
5763
case FILE_RENAME_INFORMATION :
5764
+ {
5727
5765
if (!test_tree_conn_flag (work -> tcon , KSMBD_TREE_CONN_FLAG_WRITABLE )) {
5728
5766
ksmbd_debug (SMB ,
5729
5767
"User does not have write permission\n" );
5730
5768
return - EACCES ;
5731
5769
}
5732
- return set_rename_info (work , fp , buf );
5733
5770
5771
+ if (buf_len < sizeof (struct smb2_file_rename_info ))
5772
+ return - EINVAL ;
5773
+
5774
+ return set_rename_info (work , fp ,
5775
+ (struct smb2_file_rename_info * )req -> Buffer ,
5776
+ buf_len );
5777
+ }
5734
5778
case FILE_LINK_INFORMATION :
5779
+ {
5780
+ if (buf_len < sizeof (struct smb2_file_link_info ))
5781
+ return - EINVAL ;
5782
+
5735
5783
return smb2_create_link (work , work -> tcon -> share_conf ,
5736
- (struct smb2_file_link_info * )buf , fp -> filp ,
5784
+ (struct smb2_file_link_info * )req -> Buffer ,
5785
+ buf_len , fp -> filp ,
5737
5786
work -> sess -> conn -> local_nls );
5738
-
5787
+ }
5739
5788
case FILE_DISPOSITION_INFORMATION :
5789
+ {
5740
5790
if (!test_tree_conn_flag (work -> tcon , KSMBD_TREE_CONN_FLAG_WRITABLE )) {
5741
5791
ksmbd_debug (SMB ,
5742
5792
"User does not have write permission\n" );
5743
5793
return - EACCES ;
5744
5794
}
5745
- return set_file_disposition_info (fp , buf );
5746
5795
5796
+ if (buf_len < sizeof (struct smb2_file_disposition_info ))
5797
+ return - EINVAL ;
5798
+
5799
+ return set_file_disposition_info (fp ,
5800
+ (struct smb2_file_disposition_info * )req -> Buffer );
5801
+ }
5747
5802
case FILE_FULL_EA_INFORMATION :
5748
5803
{
5749
5804
if (!(fp -> daccess & FILE_WRITE_EA_LE )) {
@@ -5752,18 +5807,29 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
5752
5807
return - EACCES ;
5753
5808
}
5754
5809
5755
- return smb2_set_ea ((struct smb2_ea_info * )buf ,
5756
- & fp -> filp -> f_path );
5757
- }
5810
+ if (buf_len < sizeof (struct smb2_ea_info ))
5811
+ return - EINVAL ;
5758
5812
5813
+ return smb2_set_ea ((struct smb2_ea_info * )req -> Buffer ,
5814
+ buf_len , & fp -> filp -> f_path );
5815
+ }
5759
5816
case FILE_POSITION_INFORMATION :
5760
- return set_file_position_info (fp , buf );
5817
+ {
5818
+ if (buf_len < sizeof (struct smb2_file_pos_info ))
5819
+ return - EINVAL ;
5761
5820
5821
+ return set_file_position_info (fp , (struct smb2_file_pos_info * )req -> Buffer );
5822
+ }
5762
5823
case FILE_MODE_INFORMATION :
5763
- return set_file_mode_info (fp , buf );
5824
+ {
5825
+ if (buf_len < sizeof (struct smb2_file_mode_info ))
5826
+ return - EINVAL ;
5827
+
5828
+ return set_file_mode_info (fp , (struct smb2_file_mode_info * )req -> Buffer );
5829
+ }
5764
5830
}
5765
5831
5766
- pr_err ("Unimplemented Fileinfoclass :%d\n" , info_class );
5832
+ pr_err ("Unimplemented Fileinfoclass :%d\n" , req -> FileInfoClass );
5767
5833
return - EOPNOTSUPP ;
5768
5834
}
5769
5835
@@ -5824,8 +5890,7 @@ int smb2_set_info(struct ksmbd_work *work)
5824
5890
switch (req -> InfoType ) {
5825
5891
case SMB2_O_INFO_FILE :
5826
5892
ksmbd_debug (SMB , "GOT SMB2_O_INFO_FILE\n" );
5827
- rc = smb2_set_info_file (work , fp , req -> FileInfoClass ,
5828
- req -> Buffer , work -> tcon -> share_conf );
5893
+ rc = smb2_set_info_file (work , fp , req , work -> tcon -> share_conf );
5829
5894
break ;
5830
5895
case SMB2_O_INFO_SECURITY :
5831
5896
ksmbd_debug (SMB , "GOT SMB2_O_INFO_SECURITY\n" );
0 commit comments