Giter Club home page Giter Club logo

dtb's People

Contributors

ababo avatar berkus avatar heroickatora avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

dtb's Issues

Unsound implementation of `transmute_buf` and `value_u32_list`

The source of unsoundness

The first unsoundness lies in transmute_buf.

dtb/src/struct_item.rs

Lines 88 to 93 in caf8d1e

unsafe fn transmute_buf<T>(buf: &mut [u8]) -> Result<&mut [T]> {
let buf = align_buf::<T>(buf)?;
Ok(from_raw_parts_mut(
buf.as_ptr() as *mut T,
buf.len() / size_of::<T>(),
))

At line 91, buf.as_ptr() would create an immutable raw pointer; however, it is then casted to a mutable raw pointer and created a slice from it. Changing the readonly permission in type conversion could lead to undefined behavior. Even though the function is not public and declared as unsafe, it was still called by other functions and could have some impact.

The second unsoundness lies in value_u32_list.

dtb/src/struct_item.rs

Lines 115 to 135 in caf8d1e

pub fn value_u32_list<'b>(&self, buf: &'b mut [u8]) -> Result<&'b [u32]> {
let value = self.value()?;
if value.len() % 4 != 0 {
return Err(Error::BadU32List);
}
let len = value.len() / 4;
let buf = unsafe { StructItem::transmute_buf(buf)? };
if buf.len() < len {
return Err(Error::BufferTooSmall);
}
for (i, val) in buf.iter_mut().enumerate().take(len) {
*val = u32::from_be(unsafe {
*(value.as_ptr().add(4 * i as usize) as *const u32)
});
}
Ok(&buf[..len])
}

At line 130, value.as_ptr() was casted to u32 raw pointer and created a misaligned pointer. The misaligned pointer was deref in the same line, leading to undefined behavior.

To reproduce the bug

To reproduce the bug in transmute_buf:

fn main() {
    let mut arr: [u32; 3] = [0; 3];
    let mut buf = unsafe {
        core::slice::from_raw_parts_mut::<u8>(
            arr.as_mut_ptr() as *mut u8,
            core::mem::size_of_val(&arr),
        )
    };

    println!("{:?}", prop.value_u32_list(&mut buf).unwrap())
}

run with miri,

error: Undefined Behavior: trying to retag from <2588> for Unique permission at alloc1308[0x0], but that tag only grants SharedReadOnly permission for this location
   --> /$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/raw.rs:145:9
    |
145 |         &mut *ptr::slice_from_raw_parts_mut(data, len)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
    |         trying to retag from <2588> for Unique permission at alloc1308[0x0], but that tag only grants SharedReadOnly permission for this location
    |         this error occurs as part of retag at alloc1308[0x0..0xc]
    |

To reproduce the bug in value_u32_list, we just need to run cargo test:

running 38 tests
test reader::tests::test_bad_magic ... ok
thread 'struct_item::tests::test_value_u32_list' panicked at 'misaligned pointer dereference: address must be a multiple of 0x4 but is 0x563ee31717fb', src/struct_item.rs:130:17

Hope this could help you debug and fix the bugs:)

Potential creation of invalid reference

The reader my construct a reference of &Header even when the underlying blob is too small. This may lead to UB and the compiler would also not miscompile if it were to remove the check for header length that comes afterwards, even though it does not seem to exploit that fact at the moment.

unsafe { &*(blob.as_ptr() as *const Header) as &Header };

Search for path of property-value pair

Nice work!

Do you have any thoughts on adding some search functionality like this?

let reader = Reader::read_from_address(pdtb as usize).unwrap();
let (node, _) = reader.struct_items().path_struct_items("/interrupt-parent").next().unwrap();
let phandle = node.value().unwrap();

let intc_path = reader.struct_items().find_path_to("phandle", phandle).unwrap();

let (intc, _) = reader.struct_items().path_struct_items(intc_path).next().unwrap();

Invalid header data may lead to unsafe memory reads

The current implementation trusts, to some extent, the offsets provided by the
file header to access its buffers. In particular, the order of checks for ensuring
that offsets and sizes are well defined on the whole blob is not enough to
avoid wrong all invalid indices.

For example reserved_mem_offset is used to read from the buffer first but
the order in Reader::read only checks the total_size last. Furthermore,
several conversion with as usize and additions may lead to overflows that
could confuse the conversion.

The impact for the struct and strings offsets is a simple panic, as they are
used as slice indices only which are fully checked against the buffer length.
However, reserved_mem_offset is used to unsafely construct a &[u8]
before any of the other checks have been performed. This allows an attacker
to create files with an invalid out-of-bounds reserved_mem_offset that is
improperly check in that portion of code.

It is then used to manipulate a pointer to the input buffer:

let ptr = blob.as_ptr().add(header.reserved_mem_offset as usize)

An invalid offset may thus lead to this pointer pointing out-of-bounds and
overflow in the length calculation will then iterate over a large portion of
invalid memory.

Insufficient input validation reading `StructItems`

These lines read offsets from the input binary and trust them to only specify offsets in-bounds. This leads to panic! while reading from the StructItems iterator.

dtb/src/reader.rs

Lines 89 to 95 in e0ce89f

let value_size = u32::from_be(desc_be.value_size) as usize;
self.assert_enough_struct(offset, value_size)?;
let value = &self.struct_block[offset..offset + value_size];
offset += value_size;
let name_offset = u32::from_be(desc_be.name_offset) as usize;
for (i, chr) in (&self.strings_block[name_offset..]).iter().enumerate()

Reproduction case is attached (cargo run --example dump), I'll likely provide a fix PR this week.
issue-6.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.