Giter Club home page Giter Club logo

Comments (4)

ColinFinck avatar ColinFinck commented on July 28, 2024 1

@Arthur-PI Code looks good. Note that the /// comment for an error variant is parsed by #[derive(Display) from displaydoc::Display, which is why it contains formatting strings for all fields. Please take care of them as well, so that the context information in the error variant is actually printed.

As we're working asynchronously and I'll be the only one reviewing your PR(s), I think that a single PR with one fix per commit is the best here. Thanks for referencing the test file in each commit - that makes it very easy for me to follow what you've found :)

from ntfs.

ColinFinck avatar ColinFinck commented on July 28, 2024

Hey @Arthur-PI! Thank you for your fuzzing efforts and for opening this bug report. This is a very good catch!

When writing the ntfs crate, my style was to use the [start..end] range slice only when start and end have already undergone extensive validation and are safe to use. An example for this style is

let string = NtfsString(&self.file.record_data()[start..end]);
in the same file.
This is safe, because start and end have already been checked in validate_name_sizes before:

ntfs/src/attribute.rs

Lines 387 to 407 in 9348d72

fn validate_name_sizes(&self) -> Result<()> {
let start = self.name_offset();
if start as u32 >= self.attribute_length() {
return Err(NtfsError::InvalidAttributeNameOffset {
position: self.position(),
expected: start,
actual: self.attribute_length(),
});
}
let end = start as usize + self.name_length();
if end > self.attribute_length() as usize {
return Err(NtfsError::InvalidAttributeNameLength {
position: self.position(),
expected: end,
actual: self.attribute_length(),
});
}
Ok(())
}

If validation fails, this function also returns a precise error that pinpoints to the exact error type and location in the filesystem.

Offset and length are not necessarily checked and reported individually. Looking at the code again, I also found places where start and end are put into a slice.get(start..end) call, and a single error is returned if get doesn't yield a result:

ntfs/src/index_entry.rs

Lines 143 to 148 in 9348d72

let slice = self.slice.get(start..end);
let slice = iter_try!(slice.ok_or(NtfsError::InvalidIndexEntryDataRange {
position: self.position,
range: start..end,
size: self.slice.len() as u16
}));

So as you see, there are currently multiple ways to deal with these cases, with room for improvement/unification.

As you ask for my preferred version to deal with such cases:

  • Check if there is a suitable error variant. Don't hesitate to add one. Exact error messages are way better than a single message reused for multiple cases.
    In this case, NtfsError::MissingIndexAllocation is a specific error when an $INDEX_ALLOCATION attribute was expected but not found. It's unrelated to the reported problem.

  • Changing [start..end] to .get(start..end) is also how I would fix this particular problem.
    One could also check start and end individually, like it's done in validate_resident_value_sizes, but I'd say it's too easy to miss a check here.

  • Add an error variant InvalidNonResidentValueDataRange, with fields position, range, and size, and return that as the specific error for this case.
    Use self.position() for the position field, start..end for the range field, and self.file.ntfs().file_record_size() for the size field. This gives all important context to understand and pinpoint the error.
    Doing it like this is also 100% consistent with what's done for slice.get(start..end) in index_entry.rs.

  • Use .get(start..end).ok_or(.....)? instead of an if-else block.
    This doesn't add an indendation level for the happy case, and therefore scales better if we later need to introduce another check with early return in case of an error.

Again, thanks a lot for your help with this!

from ntfs.

Pastequee avatar Pastequee commented on July 28, 2024

Thanks you for this very complete response, those explanations are really helpful 👍🏼.
So I've taking into account what you've said and I made the fix accordingly, here is the new version.

pub(crate) fn non_resident_value_data_and_position(&self) -> Result<(&'f [u8], NtfsPosition)> {
    debug_assert!(!self.is_resident());
    let start = self.offset + self.non_resident_value_data_runs_offset() as usize;
    let end = self.offset + self.attribute_length() as usize;
    let position = self.file.position() + start;
    let data = &self.file.record_data().get(start..end).ok_or(
        NtfsError::InvalidNonResidentValueDataRange {
            position,
            range: start..end,
            size: self.file.record_data().len(),
        },
    )?;
    Ok((data, position))
}

With this new error:

/// The range of non resident value data when slicing is invalid
InvalidNonResidentValueDataRange {
    position: NtfsPosition,
    range: Range<usize>,
    size: usize,
}

Now I have fix for 8 bugs similar to this one, do you prefer one PR for each fix or one big PR with one fix per commit. As you wish. I'll also provide you all the test files that create those crashes (I'll assign a test case by commit) if you want do dig a little bit in why this happens and if the problem is deeper in the parsing process.

Thank you for your work and help.

from ntfs.

ColinFinck avatar ColinFinck commented on July 28, 2024

Fixed in #23

from ntfs.

Related Issues (19)

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.