Storage panic from oss-fuzz (#385)
* fixes the fuzzer flaw and adds tests for it * out of bounds instead of empty okay
This commit is contained in:
@@ -39,6 +39,9 @@ impl BufferUpgradeStorage {
|
||||
|
||||
impl UpgradeStorage for BufferUpgradeStorage {
|
||||
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
|
||||
if length == 0 {
|
||||
return Err(StorageError::OutOfBounds);
|
||||
}
|
||||
let partition_range = ModRange::new(0, self.partition.len());
|
||||
if partition_range.contains_range(&ModRange::new(offset, length)) {
|
||||
Ok(&self.partition[offset..][..length])
|
||||
@@ -48,6 +51,9 @@ impl UpgradeStorage for BufferUpgradeStorage {
|
||||
}
|
||||
|
||||
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()> {
|
||||
if data.is_empty() {
|
||||
return Err(StorageError::OutOfBounds);
|
||||
}
|
||||
let partition_range = ModRange::new(0, self.partition.len());
|
||||
if partition_range.contains_range(&ModRange::new(offset, data.len())) {
|
||||
self.partition[offset..][..data.len()].copy_from_slice(data);
|
||||
@@ -79,3 +85,64 @@ impl UpgradeStorage for BufferUpgradeStorage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_write_partition() {
|
||||
let mut storage = BufferUpgradeStorage::new().unwrap();
|
||||
assert_eq!(storage.read_partition(0, 2).unwrap(), &[0xFF, 0xFF]);
|
||||
assert!(storage.write_partition(1, &[0x88, 0x88]).is_ok());
|
||||
assert_eq!(storage.read_partition(0, 2).unwrap(), &[0xFF, 0x88]);
|
||||
assert_eq!(
|
||||
storage.write_partition(PARTITION_LENGTH - 1, &[0x88, 0x88]),
|
||||
Err(StorageError::OutOfBounds)
|
||||
);
|
||||
assert_eq!(
|
||||
storage.read_partition(PARTITION_LENGTH - 2, 2).unwrap(),
|
||||
&[0xFF, 0xFF]
|
||||
);
|
||||
assert_eq!(
|
||||
storage.read_partition(PARTITION_LENGTH - 1, 2),
|
||||
Err(StorageError::OutOfBounds)
|
||||
);
|
||||
assert_eq!(
|
||||
storage.write_partition(4, &[]),
|
||||
Err(StorageError::OutOfBounds)
|
||||
);
|
||||
assert_eq!(
|
||||
storage.write_partition(PARTITION_LENGTH + 4, &[]),
|
||||
Err(StorageError::OutOfBounds)
|
||||
);
|
||||
assert_eq!(storage.read_partition(4, 0), Err(StorageError::OutOfBounds));
|
||||
assert_eq!(
|
||||
storage.read_partition(PARTITION_LENGTH + 4, 0),
|
||||
Err(StorageError::OutOfBounds)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partition_slice() {
|
||||
let storage = BufferUpgradeStorage::new().unwrap();
|
||||
assert_eq!(storage.partition_address(), 0x60000);
|
||||
assert_eq!(storage.partition_length(), PARTITION_LENGTH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_write_metadata() {
|
||||
let mut storage = BufferUpgradeStorage::new().unwrap();
|
||||
assert_eq!(storage.read_metadata().unwrap(), &[0xFF; METADATA_LENGTH]);
|
||||
assert!(storage.write_metadata(&[0x88, 0x88]).is_ok());
|
||||
assert_eq!(
|
||||
storage.write_metadata(&[0x88; METADATA_LENGTH + 1]),
|
||||
Err(StorageError::OutOfBounds)
|
||||
);
|
||||
let new_metadata = storage.read_metadata().unwrap();
|
||||
assert_eq!(&new_metadata[0..2], &[0x88, 0x88]);
|
||||
assert_eq!(&new_metadata[2..], &[0xFF; METADATA_LENGTH - 2]);
|
||||
assert!(storage.write_metadata(&[]).is_ok());
|
||||
assert_eq!(storage.read_metadata().unwrap(), &[0xFF; METADATA_LENGTH]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +289,9 @@ impl SyscallUpgradeStorage {
|
||||
|
||||
impl UpgradeStorage for SyscallUpgradeStorage {
|
||||
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
|
||||
if length == 0 {
|
||||
return Err(StorageError::OutOfBounds);
|
||||
}
|
||||
let address = self.partition.start() + offset;
|
||||
if self
|
||||
.partition
|
||||
@@ -301,14 +304,15 @@ impl UpgradeStorage for SyscallUpgradeStorage {
|
||||
}
|
||||
|
||||
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()> {
|
||||
if data.is_empty() {
|
||||
return Err(StorageError::OutOfBounds);
|
||||
}
|
||||
let address = self.partition.start() + offset;
|
||||
if self
|
||||
.partition
|
||||
.contains_range(&ModRange::new(address, data.len()))
|
||||
{
|
||||
let write_range = ModRange::new(address, data.len());
|
||||
if self.partition.contains_range(&write_range) {
|
||||
// Erases all pages that have their first byte in the write range.
|
||||
// Since we expect calls in order, we don't want to erase half-written pages.
|
||||
for address in ModRange::new(address, data.len()).aligned_iter(self.page_size) {
|
||||
for address in write_range.aligned_iter(self.page_size) {
|
||||
erase_page(address, self.page_size)?;
|
||||
}
|
||||
write_slice(address, data)
|
||||
|
||||
Reference in New Issue
Block a user