diff --git a/rafs/src/metadata/direct_v6.rs b/rafs/src/metadata/direct_v6.rs index 8509e52a4b7..c0be3858e0e 100644 --- a/rafs/src/metadata/direct_v6.rs +++ b/rafs/src/metadata/direct_v6.rs @@ -537,8 +537,17 @@ impl OndiskInodeWrapper { is_tarfs_mode: bool, is_tail: bool, ) -> Option { - let blob_index = chunk_addr.blob_index(); let chunk_index = chunk_addr.blob_ci_index(); + let blob_index = match chunk_addr.blob_index() { + Err(e) => { + warn!( + "failed to get blob index for chunk address {:?}, {}", + chunk_addr, e + ); + return None; + } + Ok(v) => v, + }; match state.blob_table.get(blob_index) { Err(e) => { @@ -1310,7 +1319,7 @@ impl RafsInodeExt for OndiskInodeWrapper { let has_device = self.mapping.device.lock().unwrap().has_device(); if state.meta.has_inlined_chunk_digest() && has_device { - let blob_index = chunk_addr.blob_index(); + let blob_index = chunk_addr.blob_index()?; let chunk_index = chunk_addr.blob_ci_index(); let device = self.mapping.device.lock().unwrap(); device @@ -1322,7 +1331,7 @@ impl RafsInodeExt for OndiskInodeWrapper { )) }) } else if state.is_tarfs() { - let blob_index = chunk_addr.blob_index(); + let blob_index = chunk_addr.blob_index()?; let chunk_index = chunk_addr.blob_ci_index(); let offset = (chunk_addr.block_addr() as u64) << EROFS_BLOCK_BITS_9; let size = if idx == self.get_chunk_count() - 1 { @@ -1340,7 +1349,7 @@ impl RafsInodeExt for OndiskInodeWrapper { match chunk_map.as_ref().unwrap().get(chunk_addr) { None => Err(enoent!(format!( "failed to get chunk info for chunk {}/{}/{}", - chunk_addr.blob_index(), + chunk_addr.blob_index().unwrap_or_default(), chunk_addr.blob_ci_index(), chunk_addr.block_addr() ))), diff --git a/rafs/src/metadata/layout/v6.rs b/rafs/src/metadata/layout/v6.rs index e74aa6bdb69..6008a805419 100644 --- a/rafs/src/metadata/layout/v6.rs +++ b/rafs/src/metadata/layout/v6.rs @@ -1196,8 +1196,13 @@ impl RafsV6InodeChunkAddr { /// The index in BlobInfo grows from 0, so when using this method to index the corresponding blob, /// the index always needs to be minus 1 /// Get the blob index of the chunk. - pub fn blob_index(&self) -> u32 { - (u16::from_le(self.c_blob_addr_hi) & 0x00ff) as u32 - 1 + pub fn blob_index(&self) -> Result { + let idx = (u16::from_le(self.c_blob_addr_hi) & 0x00ff) as u32; + if idx == 0 { + Err(einval!("invalid zero blob index from RafsV6InodeChunkAddr")) + } else { + Ok(idx - 1) + } } /// Set the blob index of the chunk. @@ -2227,7 +2232,7 @@ mod tests { writer.flush().unwrap(); let mut chunk2 = RafsV6InodeChunkAddr::new(); chunk2.load(&mut reader).unwrap(); - assert_eq!(chunk2.blob_index(), 3); + assert_eq!(chunk2.blob_index().unwrap(), 3); assert_eq!(chunk2.blob_ci_index(), 0x123456); assert_eq!(chunk2.block_addr(), 0xa5a53412); assert!(chunk2.validate(4)); @@ -2356,4 +2361,20 @@ mod tests { assert!(entry2 == target1); } } + + #[test] + fn test_invalid_blob_idx_from_chunk_addr() { + let mut addr = RafsV6InodeChunkAddr::new(); + assert!(addr.blob_index().is_err()); + addr.set_blob_index(8); + assert_eq!(addr.blob_index().unwrap(), 8); + + assert_eq!(addr.blob_ci_index(), 0); + addr.set_blob_ci_index(131); + assert_eq!(addr.blob_ci_index(), 131); + + assert_eq!(addr.block_addr(), 0); + addr.set_block_addr(179); + assert_eq!(addr.block_addr(), 179); + } }