indygreg / apple-platform-rs

Rust crates supporting Apple platform development
595 stars 49 forks source link

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

Open indygreg opened 10 months ago

indygreg commented 10 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 10 months ago

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