@@ -3402,20 +3402,24 @@ int smb2_open(struct ksmbd_work *work)
34023402 KSMBD_SHARE_FLAG_ACL_XATTR )) {
34033403 struct smb_fattr fattr ;
34043404 struct smb_ntsd * pntsd ;
3405- int pntsd_size , ace_num = 0 ;
3405+ int pntsd_size ;
3406+ size_t scratch_len ;
34063407
34073408 ksmbd_acls_fattr (& fattr , idmap , inode );
3408- if (fattr .cf_acls )
3409- ace_num = fattr .cf_acls -> a_count ;
3410- if (fattr .cf_dacls )
3411- ace_num += fattr .cf_dacls -> a_count ;
3412-
3413- pntsd = kmalloc (sizeof (struct smb_ntsd ) +
3414- sizeof (struct smb_sid ) * 3 +
3415- sizeof (struct smb_acl ) +
3416- sizeof (struct smb_ace ) * ace_num * 2 ,
3417- KSMBD_DEFAULT_GFP );
3409+ scratch_len = smb_acl_sec_desc_scratch_len (& fattr ,
3410+ NULL , 0 ,
3411+ OWNER_SECINFO | GROUP_SECINFO |
3412+ DACL_SECINFO );
3413+ if (!scratch_len || scratch_len == SIZE_MAX ) {
3414+ rc = - EFBIG ;
3415+ posix_acl_release (fattr .cf_acls );
3416+ posix_acl_release (fattr .cf_dacls );
3417+ goto err_out ;
3418+ }
3419+
3420+ pntsd = kvzalloc (scratch_len , KSMBD_DEFAULT_GFP );
34183421 if (!pntsd ) {
3422+ rc = - ENOMEM ;
34193423 posix_acl_release (fattr .cf_acls );
34203424 posix_acl_release (fattr .cf_dacls );
34213425 goto err_out ;
@@ -3430,7 +3434,7 @@ int smb2_open(struct ksmbd_work *work)
34303434 posix_acl_release (fattr .cf_acls );
34313435 posix_acl_release (fattr .cf_dacls );
34323436 if (rc ) {
3433- kfree (pntsd );
3437+ kvfree (pntsd );
34343438 goto err_out ;
34353439 }
34363440
@@ -3440,7 +3444,7 @@ int smb2_open(struct ksmbd_work *work)
34403444 pntsd ,
34413445 pntsd_size ,
34423446 false);
3443- kfree (pntsd );
3447+ kvfree (pntsd );
34443448 if (rc )
34453449 pr_err ("failed to store ntacl in xattr : %d\n" ,
34463450 rc );
@@ -5372,8 +5376,9 @@ static int smb2_get_info_file(struct ksmbd_work *work,
53725376 if (test_share_config_flag (work -> tcon -> share_conf ,
53735377 KSMBD_SHARE_FLAG_PIPE )) {
53745378 /* smb2 info file called for pipe */
5375- return smb2_get_info_file_pipe (work -> sess , req , rsp ,
5379+ rc = smb2_get_info_file_pipe (work -> sess , req , rsp ,
53765380 work -> response_buf );
5381+ goto iov_pin_out ;
53775382 }
53785383
53795384 if (work -> next_smb2_rcv_hdr_off ) {
@@ -5473,6 +5478,12 @@ static int smb2_get_info_file(struct ksmbd_work *work,
54735478 rc = buffer_check_err (le32_to_cpu (req -> OutputBufferLength ),
54745479 rsp , work -> response_buf );
54755480 ksmbd_fd_put (work , fp );
5481+
5482+ iov_pin_out :
5483+ if (!rc )
5484+ rc = ksmbd_iov_pin_rsp (work , (void * )rsp ,
5485+ offsetof(struct smb2_query_info_rsp , Buffer ) +
5486+ le32_to_cpu (rsp -> OutputBufferLength ));
54765487 return rc ;
54775488}
54785489
@@ -5699,6 +5710,11 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
56995710 rc = buffer_check_err (le32_to_cpu (req -> OutputBufferLength ),
57005711 rsp , work -> response_buf );
57015712 path_put (& path );
5713+
5714+ if (!rc )
5715+ rc = ksmbd_iov_pin_rsp (work , (void * )rsp ,
5716+ offsetof(struct smb2_query_info_rsp , Buffer ) +
5717+ le32_to_cpu (rsp -> OutputBufferLength ));
57025718 return rc ;
57035719}
57045720
@@ -5708,20 +5724,26 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
57085724{
57095725 struct ksmbd_file * fp ;
57105726 struct mnt_idmap * idmap ;
5711- struct smb_ntsd * pntsd = ( struct smb_ntsd * ) rsp -> Buffer , * ppntsd = NULL ;
5727+ struct smb_ntsd * pntsd = NULL , * ppntsd = NULL ;
57125728 struct smb_fattr fattr = {{0 }};
57135729 struct inode * inode ;
57145730 __u32 secdesclen = 0 ;
57155731 unsigned int id = KSMBD_NO_FID , pid = KSMBD_NO_FID ;
57165732 int addition_info = le32_to_cpu (req -> AdditionalInformation );
5717- int rc = 0 , ppntsd_size = 0 ;
5733+ int rc = 0 , ppntsd_size = 0 , max_len ;
5734+ size_t scratch_len = 0 ;
57185735
57195736 if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
57205737 PROTECTED_DACL_SECINFO |
57215738 UNPROTECTED_DACL_SECINFO )) {
57225739 ksmbd_debug (SMB , "Unsupported addition info: 0x%x)\n" ,
57235740 addition_info );
57245741
5742+ pntsd = kzalloc (ALIGN (sizeof (struct smb_ntsd ), 8 ),
5743+ KSMBD_DEFAULT_GFP );
5744+ if (!pntsd )
5745+ return - ENOMEM ;
5746+
57255747 pntsd -> revision = cpu_to_le16 (1 );
57265748 pntsd -> type = cpu_to_le16 (SELF_RELATIVE | DACL_PROTECTED );
57275749 pntsd -> osidoffset = 0 ;
@@ -5730,9 +5752,7 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
57305752 pntsd -> dacloffset = 0 ;
57315753
57325754 secdesclen = sizeof (struct smb_ntsd );
5733- rsp -> OutputBufferLength = cpu_to_le32 (secdesclen );
5734-
5735- return 0 ;
5755+ goto iov_pin ;
57365756 }
57375757
57385758 if (work -> next_smb2_rcv_hdr_off ) {
@@ -5764,18 +5784,58 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
57645784 & ppntsd );
57655785
57665786 /* Check if sd buffer size exceeds response buffer size */
5767- if (smb2_resp_buf_len (work , 8 ) > ppntsd_size )
5768- rc = build_sec_desc (idmap , pntsd , ppntsd , ppntsd_size ,
5769- addition_info , & secdesclen , & fattr );
5787+ max_len = smb2_calc_max_out_buf_len (work ,
5788+ offsetof(struct smb2_query_info_rsp , Buffer ),
5789+ le32_to_cpu (req -> OutputBufferLength ));
5790+ if (max_len < 0 ) {
5791+ rc = - EINVAL ;
5792+ goto release_acl ;
5793+ }
5794+
5795+ scratch_len = smb_acl_sec_desc_scratch_len (& fattr , ppntsd ,
5796+ ppntsd_size , addition_info );
5797+ if (!scratch_len || scratch_len == SIZE_MAX ) {
5798+ rc = - EFBIG ;
5799+ goto release_acl ;
5800+ }
5801+
5802+ pntsd = kvzalloc (scratch_len , KSMBD_DEFAULT_GFP );
5803+ if (!pntsd ) {
5804+ rc = - ENOMEM ;
5805+ goto release_acl ;
5806+ }
5807+
5808+ rc = build_sec_desc (idmap , pntsd , ppntsd , ppntsd_size ,
5809+ addition_info , & secdesclen , & fattr );
5810+
5811+ release_acl :
57705812 posix_acl_release (fattr .cf_acls );
57715813 posix_acl_release (fattr .cf_dacls );
57725814 kfree (ppntsd );
57735815 ksmbd_fd_put (work , fp );
5816+
5817+ if (!rc && ALIGN (secdesclen , 8 ) > scratch_len )
5818+ rc = - EFBIG ;
57745819 if (rc )
5775- return rc ;
5820+ goto err_out ;
57765821
5822+ iov_pin :
57775823 rsp -> OutputBufferLength = cpu_to_le32 (secdesclen );
5778- return 0 ;
5824+ rc = buffer_check_err (le32_to_cpu (req -> OutputBufferLength ),
5825+ rsp , work -> response_buf );
5826+ if (rc )
5827+ goto err_out ;
5828+
5829+ rc = ksmbd_iov_pin_rsp_read (work , (void * )rsp ,
5830+ offsetof(struct smb2_query_info_rsp , Buffer ),
5831+ pntsd , secdesclen );
5832+ err_out :
5833+ if (rc ) {
5834+ rsp -> OutputBufferLength = 0 ;
5835+ kvfree (pntsd );
5836+ }
5837+
5838+ return rc ;
57795839}
57805840
57815841/**
@@ -5799,6 +5859,9 @@ int smb2_query_info(struct ksmbd_work *work)
57995859 goto err_out ;
58005860 }
58015861
5862+ rsp -> StructureSize = cpu_to_le16 (9 );
5863+ rsp -> OutputBufferOffset = cpu_to_le16 (72 );
5864+
58025865 switch (req -> InfoType ) {
58035866 case SMB2_O_INFO_FILE :
58045867 ksmbd_debug (SMB , "GOT SMB2_O_INFO_FILE\n" );
@@ -5819,14 +5882,6 @@ int smb2_query_info(struct ksmbd_work *work)
58195882 }
58205883 ksmbd_revert_fsids (work );
58215884
5822- if (!rc ) {
5823- rsp -> StructureSize = cpu_to_le16 (9 );
5824- rsp -> OutputBufferOffset = cpu_to_le16 (72 );
5825- rc = ksmbd_iov_pin_rsp (work , (void * )rsp ,
5826- offsetof(struct smb2_query_info_rsp , Buffer ) +
5827- le32_to_cpu (rsp -> OutputBufferLength ));
5828- }
5829-
58305885err_out :
58315886 if (rc < 0 ) {
58325887 if (rc == - EACCES )
@@ -5837,6 +5892,8 @@ int smb2_query_info(struct ksmbd_work *work)
58375892 rsp -> hdr .Status = STATUS_UNEXPECTED_IO_ERROR ;
58385893 else if (rc == - ENOMEM )
58395894 rsp -> hdr .Status = STATUS_INSUFFICIENT_RESOURCES ;
5895+ else if (rc == - EINVAL && rsp -> hdr .Status == 0 )
5896+ rsp -> hdr .Status = STATUS_INVALID_PARAMETER ;
58405897 else if (rc == - EOPNOTSUPP || rsp -> hdr .Status == 0 )
58415898 rsp -> hdr .Status = STATUS_INVALID_INFO_CLASS ;
58425899 smb2_set_err_rsp (work );
0 commit comments