diff --git a/rafs/src/metadata/direct_v6.rs b/rafs/src/metadata/direct_v6.rs index d8177d1e4d0..f7731aa1c9c 100644 --- a/rafs/src/metadata/direct_v6.rs +++ b/rafs/src/metadata/direct_v6.rs @@ -537,7 +537,16 @@ impl OndiskInodeWrapper { is_tarfs_mode: bool, is_tail: bool, ) -> Option { - let blob_index = chunk_addr.blob_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) => { @@ -554,7 +563,7 @@ impl OndiskInodeWrapper { } else { self.chunk_size() }; - let chunk = TarfsChunkInfoV6::from_chunk_addr(chunk_addr, size); + let chunk = TarfsChunkInfoV6::from_chunk_addr(chunk_addr, size).ok()?; let chunk = Arc::new(chunk) as Arc; Some(BlobIoDesc::new( blob, @@ -1309,7 +1318,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 @@ -1326,9 +1335,8 @@ impl RafsInodeExt for OndiskInodeWrapper { } else { self.chunk_size() }; - Ok(Arc::new(TarfsChunkInfoV6::from_chunk_addr( - chunk_addr, size, - ))) + let chunk_info = TarfsChunkInfoV6::from_chunk_addr(chunk_addr, size)?; + Ok(Arc::new(chunk_info)) } else { let mut chunk_map = self.mapping.info.chunk_map.lock().unwrap(); if chunk_map.is_none() { @@ -1337,7 +1345,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() ))), @@ -1468,11 +1476,11 @@ impl TarfsChunkInfoV6 { } } - fn from_chunk_addr(chunk_addr: &RafsV6InodeChunkAddr, size: u32) -> Self { - let blob_index = chunk_addr.blob_index(); + fn from_chunk_addr(chunk_addr: &RafsV6InodeChunkAddr, size: u32) -> Result { + 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; - TarfsChunkInfoV6::new(blob_index, chunk_index, offset, size) + Ok(TarfsChunkInfoV6::new(blob_index, chunk_index, offset, size)) } } diff --git a/rafs/src/metadata/layout/v6.rs b/rafs/src/metadata/layout/v6.rs index 523a0431100..cb7845ff1b4 100644 --- a/rafs/src/metadata/layout/v6.rs +++ b/rafs/src/metadata/layout/v6.rs @@ -1197,8 +1197,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. @@ -2228,7 +2233,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)); @@ -2357,4 +2362,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); + } }