@@ -946,6 +946,7 @@ static int ntfs_external_attr_find(const __le32 type,
946946 struct attr_record * a ;
947947 __le16 * al_name ;
948948 u32 al_name_len ;
949+ u32 attr_len , mft_free_len ;
949950 bool is_first_search = false;
950951 int err = 0 ;
951952 static const char * es = " Unmount and run chkdsk." ;
@@ -1209,13 +1210,23 @@ static int ntfs_external_attr_find(const __le32 type,
12091210 * with the same meanings as above.
12101211 */
12111212do_next_attr_loop :
1212- if ((u8 * )a < (u8 * )ctx -> mrec || (u8 * )a > (u8 * )ctx -> mrec +
1213- le32_to_cpu (ctx -> mrec -> bytes_allocated ))
1213+ if ((u8 * )a < (u8 * )ctx -> mrec ||
1214+ (u8 * )a >= (u8 * )ctx -> mrec + le32_to_cpu (ctx -> mrec -> bytes_allocated ) ||
1215+ (u8 * )a >= (u8 * )ctx -> mrec + le32_to_cpu (ctx -> mrec -> bytes_in_use ))
12141216 break ;
1215- if (a -> type == AT_END )
1217+
1218+ mft_free_len = le32_to_cpu (ctx -> mrec -> bytes_in_use ) -
1219+ ((u8 * )a - (u8 * )ctx -> mrec );
1220+ if (mft_free_len >= sizeof (a -> type ) && a -> type == AT_END )
12161221 continue ;
1217- if (!a -> length )
1222+
1223+ attr_len = le32_to_cpu (a -> length );
1224+ if (!attr_len ||
1225+ attr_len < offsetof(struct attr_record , data .resident .reserved ) +
1226+ sizeof (a -> data .resident .reserved ) ||
1227+ attr_len > mft_free_len )
12181228 break ;
1229+
12191230 if (al_entry -> instance != a -> instance )
12201231 goto do_next_attr ;
12211232 /*
@@ -1225,27 +1236,67 @@ static int ntfs_external_attr_find(const __le32 type,
12251236 */
12261237 if (al_entry -> type != a -> type )
12271238 break ;
1239+ if (a -> name_length && ((le16_to_cpu (a -> name_offset ) +
1240+ a -> name_length * sizeof (__le16 )) > attr_len ))
1241+ break ;
12281242 if (!ntfs_are_names_equal ((__le16 * )((u8 * )a +
12291243 le16_to_cpu (a -> name_offset )), a -> name_length ,
12301244 al_name , al_name_len , CASE_SENSITIVE ,
12311245 vol -> upcase , vol -> upcase_len ))
12321246 break ;
1247+
12331248 ctx -> attr = a ;
1249+
1250+ if (a -> non_resident ) {
1251+ u32 min_len ;
1252+ u16 mp_offset ;
1253+
1254+ min_len = offsetof(struct attr_record ,
1255+ data .non_resident .initialized_size ) +
1256+ sizeof (a -> data .non_resident .initialized_size );
1257+
1258+ if (le32_to_cpu (a -> length ) < min_len )
1259+ break ;
1260+
1261+ mp_offset =
1262+ le16_to_cpu (a -> data .non_resident .mapping_pairs_offset );
1263+ if (mp_offset < min_len || mp_offset > attr_len )
1264+ break ;
1265+ }
1266+
12341267 /*
12351268 * If no @val specified or @val specified and it matches, we
12361269 * have found it!
12371270 */
1238- if ((type == AT_UNUSED ) || !val || (!a -> non_resident && le32_to_cpu (
1239- a -> data .resident .value_length ) == val_len &&
1240- !memcmp ((u8 * )a +
1241- le16_to_cpu (a -> data .resident .value_offset ),
1242- val , val_len ))) {
1243- ntfs_debug ("Done, found." );
1244- return 0 ;
1271+ if ((type == AT_UNUSED ) || !val )
1272+ goto attr_found ;
1273+ if (!a -> non_resident ) {
1274+ u32 value_length = le32_to_cpu (a -> data .resident .value_length );
1275+ u16 value_offset = le16_to_cpu (a -> data .resident .value_offset );
1276+
1277+ if (attr_len < offsetof(struct attr_record , data .resident .reserved ) +
1278+ sizeof (a -> data .resident .reserved ))
1279+ break ;
1280+ if (value_length > attr_len || value_offset > attr_len - value_length )
1281+ break ;
1282+
1283+ value_length = ntfs_resident_attr_min_value_length (a -> type );
1284+ if (value_length && le32_to_cpu (a -> data .resident .value_length ) <
1285+ value_length ) {
1286+ pr_err ("Too small resident attribute value in MFT record %lld, type %#x\n" ,
1287+ (long long )ctx -> ntfs_ino -> mft_no , a -> type );
1288+ break ;
1289+ }
1290+ if (value_length == val_len &&
1291+ !memcmp ((u8 * )a + value_offset , val , val_len )) {
1292+ attr_found :
1293+ ntfs_debug ("Done, found." );
1294+ return 0 ;
1295+ }
12451296 }
12461297do_next_attr :
12471298 /* Proceed to the next attribute in the current mft record. */
1248- a = (struct attr_record * )((u8 * )a + le32_to_cpu ( a -> length ) );
1299+ a = (struct attr_record * )((u8 * )a + attr_len );
12491300 goto do_next_attr_loop ;
12501301 }
12511302
@@ -1260,9 +1311,13 @@ static int ntfs_external_attr_find(const __le32 type,
12601311 }
12611312
12621313 if (!err ) {
1314+ u64 mft_no = ctx -> al_entry ? MREF_LE (ctx -> al_entry -> mft_reference ) : 0 ;
1315+ u32 type = ctx -> al_entry ? le32_to_cpu (ctx -> al_entry -> type ) : 0 ;
1316+
12631317 ntfs_error (vol -> sb ,
1264- "Base inode 0x%llx contains corrupt attribute list attribute.%s" ,
1265- base_ni -> mft_no , es );
1318+ "Base inode 0x%llx contains corrupt attribute, mft %#llx, type %#x. %s" ,
1319+ (long long )base_ni -> mft_no , (long long )mft_no , type ,
1320+ "Unmount and run chkdsk." );
12661321 err = - EIO ;
12671322 }
12681323
0 commit comments