potentially correct infinite indirect read

This commit is contained in:
husky 2023-08-17 17:59:56 -07:00
parent ca82cdb4d4
commit 2e5a154895
No known key found for this signature in database
GPG key ID: 6B3D8CB511646891
2 changed files with 76 additions and 0 deletions

View file

@ -295,6 +295,80 @@ pub fn next_journal_position(sb: &Superblock, bd: &mut dyn BlockDevice) -> Optio
}
}
/// Reads an indirect datablock from a list of 3 indirect datablocks.
pub fn read_indirect_datablock(sb: &Superblock, bd: &mut dyn BlockDevice, dbas: [Index; 12], address: Index) -> Vec<u8> {
if address < 12 {
return read_datablock(dbas[address as usize], sb, bd);
} else {
let mut n = address - 12;
let mut blocks_left = n / (sb.block_size as u64 - 8);
let mut indexes_left = n % (sb.block_size as u64 - 8);
let mut current_block = dbas[9]; // first indirect block
let mut visited = vec![];
loop {
if visited.contains(&current_block) {
return vec![]; // we've looped around
}
visited.push(current_block);
let mut head = 0;
let buf = read_datablock(current_block, sb, bd);
let count = u64::from_be_bytes(buf[0..8].try_into().unwrap());
head += 8;
// if blocks_left == 0, we're in the right block (either that or we're in the right block to recurse downwards into)
if blocks_left == 0 {
for _ in 0..count.min(indexes_left) {
let isdata_depth = &buf[head..head + 8];
head += 8;
let ptr_data = &buf[head..head + 8];
let ptr = u64::from_be_bytes(ptr_data.try_into().unwrap());
let is_data = isdata_depth[1] != 0;
// if not data, we need to recurse
if !is_data {
current_block = ptr;
break; // skip the rest of the loop
} else {
// if indexes_left == 0, we found the correct index
if indexes_left == 0 {
return read_datablock(ptr, sb, bd);
} else {
indexes_left -= 1;
}
}
}
} else {
for _ in 0..count {
let isdata_depth = &buf[head..head + 8];
head += 8;
let ptr_data = &buf[head..head + 8];
let ptr = u64::from_be_bytes(ptr_data.try_into().unwrap());
let is_data = isdata_depth[1] != 0;
let mut depth = isdata_depth.to_vec();
depth[0] = 0;
let depth = u64::from_be_bytes(depth.try_into().unwrap());
// if blocks_left is less than the depth, we are at the correct block
if !is_data {
if blocks_left < depth {
// if not data, we need to recurse
blocks_left = 0;
current_block = ptr;
break; // skip the rest of the loop
} else {
blocks_left -= depth;
}
} else {
// if indexes_left == 0, we found the correct index
if indexes_left == 0 {
return read_datablock(ptr, sb, bd);
} else {
indexes_left -= 1;
}
}
}
}
}
}
}
/// Creates a journal entry for a single block write operation.
/// Should be safe to call at anytime, and shouldn't corrupt anything if the system crashes.
/// Returns None if the journal is full, or if the block device cannot be written to.

View file

@ -221,6 +221,8 @@ pub struct Inode {
/// // read block, if not data then check depth,
/// // if depth implies that this indirect block could contain the nth data block, then recurse
/// // otherwise, subtract the depth from n, and continue
/// ====
/// ideally, this should not take up too much storage space, while allowing for a large number of blocks to be addressed with minimal performance impact
pub direct_block_addresses: [Index; 12],
/// CRC32 checksum of this inode
pub checksum: u32,