@@ -690,6 +690,7 @@ static void set_posix_acl_entries_dacl(struct user_namespace *user_ns,
690690static void set_ntacl_dacl (struct user_namespace * user_ns ,
691691 struct smb_acl * pndacl ,
692692 struct smb_acl * nt_dacl ,
693+ unsigned int aces_size ,
693694 const struct smb_sid * pownersid ,
694695 const struct smb_sid * pgrpsid ,
695696 struct smb_fattr * fattr )
@@ -703,9 +704,19 @@ static void set_ntacl_dacl(struct user_namespace *user_ns,
703704 if (nt_num_aces ) {
704705 ntace = (struct smb_ace * )((char * )nt_dacl + sizeof (struct smb_acl ));
705706 for (i = 0 ; i < nt_num_aces ; i ++ ) {
706- memcpy ((char * )pndace + size , ntace , le16_to_cpu (ntace -> size ));
707- size += le16_to_cpu (ntace -> size );
708- ntace = (struct smb_ace * )((char * )ntace + le16_to_cpu (ntace -> size ));
707+ unsigned short nt_ace_size ;
708+
709+ if (offsetof(struct smb_ace , access_req ) > aces_size )
710+ break ;
711+
712+ nt_ace_size = le16_to_cpu (ntace -> size );
713+ if (nt_ace_size > aces_size )
714+ break ;
715+
716+ memcpy ((char * )pndace + size , ntace , nt_ace_size );
717+ size += nt_ace_size ;
718+ aces_size -= nt_ace_size ;
719+ ntace = (struct smb_ace * )((char * )ntace + nt_ace_size );
709720 num_aces ++ ;
710721 }
711722 }
@@ -878,7 +889,7 @@ int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
878889/* Convert permission bits from mode to equivalent CIFS ACL */
879890int build_sec_desc (struct user_namespace * user_ns ,
880891 struct smb_ntsd * pntsd , struct smb_ntsd * ppntsd ,
881- int addition_info , __u32 * secdesclen ,
892+ int ppntsd_size , int addition_info , __u32 * secdesclen ,
882893 struct smb_fattr * fattr )
883894{
884895 int rc = 0 ;
@@ -938,15 +949,25 @@ int build_sec_desc(struct user_namespace *user_ns,
938949
939950 if (!ppntsd ) {
940951 set_mode_dacl (user_ns , dacl_ptr , fattr );
941- } else if (!ppntsd -> dacloffset ) {
942- goto out ;
943952 } else {
944953 struct smb_acl * ppdacl_ptr ;
954+ unsigned int dacl_offset = le32_to_cpu (ppntsd -> dacloffset );
955+ int ppdacl_size , ntacl_size = ppntsd_size - dacl_offset ;
956+
957+ if (!dacl_offset ||
958+ (dacl_offset + sizeof (struct smb_acl ) > ppntsd_size ))
959+ goto out ;
960+
961+ ppdacl_ptr = (struct smb_acl * )((char * )ppntsd + dacl_offset );
962+ ppdacl_size = le16_to_cpu (ppdacl_ptr -> size );
963+ if (ppdacl_size > ntacl_size ||
964+ ppdacl_size < sizeof (struct smb_acl ))
965+ goto out ;
945966
946- ppdacl_ptr = (struct smb_acl * )((char * )ppntsd +
947- le32_to_cpu (ppntsd -> dacloffset ));
948967 set_ntacl_dacl (user_ns , dacl_ptr , ppdacl_ptr ,
949- nowner_sid_ptr , ngroup_sid_ptr , fattr );
968+ ntacl_size - sizeof (struct smb_acl ),
969+ nowner_sid_ptr , ngroup_sid_ptr ,
970+ fattr );
950971 }
951972 pntsd -> dacloffset = cpu_to_le32 (offset );
952973 offset += le16_to_cpu (dacl_ptr -> size );
@@ -980,24 +1001,31 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
9801001 struct smb_sid owner_sid , group_sid ;
9811002 struct dentry * parent = path -> dentry -> d_parent ;
9821003 struct user_namespace * user_ns = mnt_user_ns (path -> mnt );
983- int inherited_flags = 0 , flags = 0 , i , ace_cnt = 0 , nt_size = 0 ;
984- int rc = 0 , num_aces , dacloffset , pntsd_type , acl_len ;
1004+ int inherited_flags = 0 , flags = 0 , i , ace_cnt = 0 , nt_size = 0 , pdacl_size ;
1005+ int rc = 0 , num_aces , dacloffset , pntsd_type , pntsd_size , acl_len , aces_size ;
9851006 char * aces_base ;
9861007 bool is_dir = S_ISDIR (d_inode (path -> dentry )-> i_mode );
9871008
988- acl_len = ksmbd_vfs_get_sd_xattr (conn , user_ns ,
989- parent , & parent_pntsd );
990- if (acl_len <= 0 )
1009+ pntsd_size = ksmbd_vfs_get_sd_xattr (conn , user_ns ,
1010+ parent , & parent_pntsd );
1011+ if (pntsd_size <= 0 )
9911012 return - ENOENT ;
9921013 dacloffset = le32_to_cpu (parent_pntsd -> dacloffset );
993- if (!dacloffset ) {
1014+ if (!dacloffset || ( dacloffset + sizeof ( struct smb_acl ) > pntsd_size ) ) {
9941015 rc = - EINVAL ;
9951016 goto free_parent_pntsd ;
9961017 }
9971018
9981019 parent_pdacl = (struct smb_acl * )((char * )parent_pntsd + dacloffset );
1020+ acl_len = pntsd_size - dacloffset ;
9991021 num_aces = le32_to_cpu (parent_pdacl -> num_aces );
10001022 pntsd_type = le16_to_cpu (parent_pntsd -> type );
1023+ pdacl_size = le16_to_cpu (parent_pdacl -> size );
1024+
1025+ if (pdacl_size > acl_len || pdacl_size < sizeof (struct smb_acl )) {
1026+ rc = - EINVAL ;
1027+ goto free_parent_pntsd ;
1028+ }
10011029
10021030 aces_base = kmalloc (sizeof (struct smb_ace ) * num_aces * 2 , GFP_KERNEL );
10031031 if (!aces_base ) {
@@ -1008,11 +1036,23 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10081036 aces = (struct smb_ace * )aces_base ;
10091037 parent_aces = (struct smb_ace * )((char * )parent_pdacl +
10101038 sizeof (struct smb_acl ));
1039+ aces_size = acl_len - sizeof (struct smb_acl );
10111040
10121041 if (pntsd_type & DACL_AUTO_INHERITED )
10131042 inherited_flags = INHERITED_ACE ;
10141043
10151044 for (i = 0 ; i < num_aces ; i ++ ) {
1045+ int pace_size ;
1046+
1047+ if (offsetof(struct smb_ace , access_req ) > aces_size )
1048+ break ;
1049+
1050+ pace_size = le16_to_cpu (parent_aces -> size );
1051+ if (pace_size > aces_size )
1052+ break ;
1053+
1054+ aces_size -= pace_size ;
1055+
10161056 flags = parent_aces -> flags ;
10171057 if (!smb_inherit_flags (flags , is_dir ))
10181058 goto pass ;
@@ -1057,8 +1097,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10571097 aces = (struct smb_ace * )((char * )aces + le16_to_cpu (aces -> size ));
10581098 ace_cnt ++ ;
10591099pass :
1060- parent_aces =
1061- (struct smb_ace * )((char * )parent_aces + le16_to_cpu (parent_aces -> size ));
1100+ parent_aces = (struct smb_ace * )((char * )parent_aces + pace_size );
10621101 }
10631102
10641103 if (nt_size > 0 ) {
@@ -1153,7 +1192,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
11531192 struct smb_ntsd * pntsd = NULL ;
11541193 struct smb_acl * pdacl ;
11551194 struct posix_acl * posix_acls ;
1156- int rc = 0 , acl_size ;
1195+ int rc = 0 , pntsd_size , acl_size , aces_size , pdacl_size , dacl_offset ;
11571196 struct smb_sid sid ;
11581197 int granted = le32_to_cpu (* pdaccess & ~FILE_MAXIMAL_ACCESS_LE );
11591198 struct smb_ace * ace ;
@@ -1162,49 +1201,50 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
11621201 struct smb_ace * others_ace = NULL ;
11631202 struct posix_acl_entry * pa_entry ;
11641203 unsigned int sid_type = SIDOWNER ;
1165- char * end_of_acl ;
1204+ unsigned short ace_size ;
11661205
11671206 ksmbd_debug (SMB , "check permission using windows acl\n" );
1168- acl_size = ksmbd_vfs_get_sd_xattr (conn , user_ns ,
1169- path -> dentry , & pntsd );
1170- if (acl_size <= 0 || !pntsd || !pntsd -> dacloffset ) {
1171- kfree (pntsd );
1172- return 0 ;
1173- }
1207+ pntsd_size = ksmbd_vfs_get_sd_xattr (conn , user_ns ,
1208+ path -> dentry , & pntsd );
1209+ if (pntsd_size <= 0 || !pntsd )
1210+ goto err_out ;
1211+
1212+ dacl_offset = le32_to_cpu (pntsd -> dacloffset );
1213+ if (!dacl_offset ||
1214+ (dacl_offset + sizeof (struct smb_acl ) > pntsd_size ))
1215+ goto err_out ;
11741216
11751217 pdacl = (struct smb_acl * )((char * )pntsd + le32_to_cpu (pntsd -> dacloffset ));
1176- end_of_acl = ((char * )pntsd ) + acl_size ;
1177- if (end_of_acl <= (char * )pdacl ) {
1178- kfree (pntsd );
1179- return 0 ;
1180- }
1218+ acl_size = pntsd_size - dacl_offset ;
1219+ pdacl_size = le16_to_cpu (pdacl -> size );
11811220
1182- if (end_of_acl < (char * )pdacl + le16_to_cpu (pdacl -> size ) ||
1183- le16_to_cpu (pdacl -> size ) < sizeof (struct smb_acl )) {
1184- kfree (pntsd );
1185- return 0 ;
1186- }
1221+ if (pdacl_size > acl_size || pdacl_size < sizeof (struct smb_acl ))
1222+ goto err_out ;
11871223
11881224 if (!pdacl -> num_aces ) {
1189- if (!(le16_to_cpu ( pdacl -> size ) - sizeof (struct smb_acl )) &&
1225+ if (!(pdacl_size - sizeof (struct smb_acl )) &&
11901226 * pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE )) {
11911227 rc = - EACCES ;
11921228 goto err_out ;
11931229 }
1194- kfree (pntsd );
1195- return 0 ;
1230+ goto err_out ;
11961231 }
11971232
11981233 if (* pdaccess & FILE_MAXIMAL_ACCESS_LE ) {
11991234 granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES |
12001235 DELETE ;
12011236
12021237 ace = (struct smb_ace * )((char * )pdacl + sizeof (struct smb_acl ));
1238+ aces_size = acl_size - sizeof (struct smb_acl );
12031239 for (i = 0 ; i < le32_to_cpu (pdacl -> num_aces ); i ++ ) {
1240+ if (offsetof(struct smb_ace , access_req ) > aces_size )
1241+ break ;
1242+ ace_size = le16_to_cpu (ace -> size );
1243+ if (ace_size > aces_size )
1244+ break ;
1245+ aces_size -= ace_size ;
12041246 granted |= le32_to_cpu (ace -> access_req );
12051247 ace = (struct smb_ace * )((char * )ace + le16_to_cpu (ace -> size ));
1206- if (end_of_acl < (char * )ace )
1207- goto err_out ;
12081248 }
12091249
12101250 if (!pdacl -> num_aces )
@@ -1216,7 +1256,15 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
12161256 id_to_sid (uid , sid_type , & sid );
12171257
12181258 ace = (struct smb_ace * )((char * )pdacl + sizeof (struct smb_acl ));
1259+ aces_size = acl_size - sizeof (struct smb_acl );
12191260 for (i = 0 ; i < le32_to_cpu (pdacl -> num_aces ); i ++ ) {
1261+ if (offsetof(struct smb_ace , access_req ) > aces_size )
1262+ break ;
1263+ ace_size = le16_to_cpu (ace -> size );
1264+ if (ace_size > aces_size )
1265+ break ;
1266+ aces_size -= ace_size ;
1267+
12201268 if (!compare_sids (& sid , & ace -> sid ) ||
12211269 !compare_sids (& sid_unix_NFS_mode , & ace -> sid )) {
12221270 found = 1 ;
@@ -1226,8 +1274,6 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
12261274 others_ace = ace ;
12271275
12281276 ace = (struct smb_ace * )((char * )ace + le16_to_cpu (ace -> size ));
1229- if (end_of_acl < (char * )ace )
1230- goto err_out ;
12311277 }
12321278
12331279 if (* pdaccess & FILE_MAXIMAL_ACCESS_LE && found ) {
0 commit comments