@@ -1629,13 +1629,49 @@ pub struct AssociatedProperty {
1629
1629
pub property : ItemProperty ,
1630
1630
}
1631
1631
1632
+ const MAX_IPMA_ASSOCIATION_COUNT : u64 = u8:: MAX as u64 ;
1633
+
1634
+ /// Parse an ItemPropertyAssociation box
1635
+ /// See HEIF (ISO 23008-12:2017) § 9.3.1
1632
1636
fn read_ipma < T : Read > (
1633
1637
src : & mut BMFFBox < T > ,
1634
1638
( version, flags) : ( u8 , u32 ) ,
1635
1639
) -> Result < TryVec < Association > > {
1636
- let mut associations = TryVec :: new ( ) ;
1640
+ // Static analysis shows that none of this unchecked arithmetic can fail
1641
+ let entry_count: u64 = be_u32 ( src) ?. into ( ) ;
1642
+ let min_entry_bytes: u64 = 1 /* association_count */ + if version == 0 { 2 } else { 4 } ;
1643
+ let total_non_association_bytes = entry_count * min_entry_bytes;
1644
+ let total_association_bytes;
1645
+
1646
+ if let Some ( difference) = src. bytes_left ( ) . checked_sub ( total_non_association_bytes) {
1647
+ // All the storage for the `essential` and `property_index` parts (assuming a valid ipma box size)
1648
+ total_association_bytes = difference;
1649
+ } else {
1650
+ return Err ( Error :: InvalidData (
1651
+ "ipma box below minimum size for entry_count" ,
1652
+ ) ) ;
1653
+ }
1654
+
1655
+ let num_association_bytes = if flags & 1 == 1 { 2 } else { 1 } ;
1656
+
1657
+ // total_association_bytes must be a multiple of num_association_bytes
1658
+ if total_association_bytes % num_association_bytes != 0 {
1659
+ return Err ( Error :: InvalidData ( "ipma box has invalid size" ) ) ;
1660
+ }
1661
+
1662
+ let max_association_bytes_per_entry = MAX_IPMA_ASSOCIATION_COUNT * num_association_bytes;
1663
+ let max_total_association_bytes = entry_count * max_association_bytes_per_entry;
1664
+ let max_bytes_left = total_non_association_bytes + max_total_association_bytes;
1665
+
1666
+ if src. bytes_left ( ) > max_bytes_left {
1667
+ return Err ( Error :: InvalidData (
1668
+ "ipma box exceeds maximum size for entry_count" ,
1669
+ ) ) ;
1670
+ }
1671
+
1672
+ let total_associations = total_association_bytes / num_association_bytes;
1673
+ let mut associations = TryVec :: with_capacity ( total_associations. try_into ( ) ?) ?;
1637
1674
1638
- let entry_count = be_u32 ( src) ?;
1639
1675
for _ in 0 ..entry_count {
1640
1676
let item_id = if version == 0 {
1641
1677
be_u16 ( src) ?. into ( )
@@ -1644,7 +1680,6 @@ fn read_ipma<T: Read>(
1644
1680
} ;
1645
1681
let association_count = src. read_u8 ( ) ?;
1646
1682
for _ in 0 ..association_count {
1647
- let num_association_bytes = if flags & 1 == 1 { 2 } else { 1 } ;
1648
1683
let association = src. take ( num_association_bytes) . read_into_try_vec ( ) ?;
1649
1684
let mut association = BitReader :: new ( association. as_slice ( ) ) ;
1650
1685
let essential = association. read_bool ( ) ?;
0 commit comments