indygreg / apple-platform-rs

Rust crates supporting Apple platform development
565 stars 38 forks source link

DMG reader doesn't emit proper byte count for Ignore and Zero chunks #129

Open indygreg opened 8 months ago

indygreg commented 8 months ago

Currently, the DMG reader treats all Comment, Ignore, and Zero block chunks as an array of 0s of length compressed_bytes.

When reading DMGs produced by Apple's tooling, I was seeing corrupted partition data that coincided with the reading of Ignore and Zero block chunks. The following patch seems to fix things:

diff --git a/apple-dmg/src/lib.rs b/apple-dmg/src/lib.rs
index 6bd5678c..e0e40085 100644
--- a/apple-dmg/src/lib.rs
+++ b/apple-dmg/src/lib.rs
@@ -82,7 +82,10 @@ impl<R: Read + Seek> DmgReader<R> {
         self.r.seek(SeekFrom::Start(chunk.compressed_offset))?;
         let compressed_chunk = (&mut self.r).take(chunk.compressed_length);
         match chunk.ty().expect("unknown chunk type") {
-            ChunkType::Ignore | ChunkType::Zero | ChunkType::Comment => {
+            ChunkType::Zero | ChunkType::Ignore => {
+                Ok(Box::new(std::io::repeat(0).take(chunk.sector_count * 512)) as Box<dyn Read>)
+            }
+            ChunkType::Comment => {
                 Ok(Box::new(std::io::repeat(0).take(chunk.compressed_length)) as Box<dyn Read>)
             }
             ChunkType::Raw => Ok(Box::new(compressed_chunk)),

However, applying this patch causes tests to fail. Specifically the only_read_dmg test. This test attempts to create a copy of the vendored example.dmg file and verify it roundtrips properly. The test fails because the checksums differ:

for i in 0..dmg.plist().partitions().len() {
            let table = dmg.partition_table(i)?;
            let data = dmg.partition_data(i)?;
            let expected = u32::from(table.checksum);
            let calculated = crc32fast::hash(&data);
            assert_eq!(expected, calculated);
        }

And the checksums differ because the code change causes the emitted partition data to change, which changes the checksum.

@dvc94ch can you provide insight on how example.dmg was created? Was it created via Apple's tooling or this repo's Rust code? If it was produced with our Rust code, I think the checksums may be wrong. But without knowing what is supposed to be in the partition data, I can't (easily) pinpoint bugs in the DMG code.

dvc94ch commented 8 months ago

Think it was created with apple tooling, but it's been too long...