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 {
|
impl UpgradeStorage for BufferUpgradeStorage {
|
||||||
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
|
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());
|
let partition_range = ModRange::new(0, self.partition.len());
|
||||||
if partition_range.contains_range(&ModRange::new(offset, length)) {
|
if partition_range.contains_range(&ModRange::new(offset, length)) {
|
||||||
Ok(&self.partition[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<()> {
|
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());
|
let partition_range = ModRange::new(0, self.partition.len());
|
||||||
if partition_range.contains_range(&ModRange::new(offset, data.len())) {
|
if partition_range.contains_range(&ModRange::new(offset, data.len())) {
|
||||||
self.partition[offset..][..data.len()].copy_from_slice(data);
|
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 {
|
impl UpgradeStorage for SyscallUpgradeStorage {
|
||||||
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
|
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
|
||||||
|
if length == 0 {
|
||||||
|
return Err(StorageError::OutOfBounds);
|
||||||
|
}
|
||||||
let address = self.partition.start() + offset;
|
let address = self.partition.start() + offset;
|
||||||
if self
|
if self
|
||||||
.partition
|
.partition
|
||||||
@@ -301,14 +304,15 @@ impl UpgradeStorage for SyscallUpgradeStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()> {
|
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()> {
|
||||||
|
if data.is_empty() {
|
||||||
|
return Err(StorageError::OutOfBounds);
|
||||||
|
}
|
||||||
let address = self.partition.start() + offset;
|
let address = self.partition.start() + offset;
|
||||||
if self
|
let write_range = ModRange::new(address, data.len());
|
||||||
.partition
|
if self.partition.contains_range(&write_range) {
|
||||||
.contains_range(&ModRange::new(address, data.len()))
|
|
||||||
{
|
|
||||||
// Erases all pages that have their first byte in the 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.
|
// 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)?;
|
erase_page(address, self.page_size)?;
|
||||||
}
|
}
|
||||||
write_slice(address, data)
|
write_slice(address, data)
|
||||||
|
|||||||
Reference in New Issue
Block a user