-
-
Notifications
You must be signed in to change notification settings - Fork 324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cheap reader for bytes slice #2261
Conversation
* Added a checked version of the read to slice.
libafl/src/inputs/mod.rs
Outdated
/// Target bytes wrapper keeping track of the current read position. | ||
/// Convenient wrapper when bytes must be split it in multiple subinputs. | ||
#[derive(Debug)] | ||
pub struct BytesReader<'a, I> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like std library functions for this use case exist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look at cursor, maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, my first idea was actually to use Cursor
, but it does not really offer an interface to extract a slice without any copy while moving the cursor forward, hence this implem. It has some good side effects, like the fine control on what to do when reaching the end of the reader and reuse OwnedSlice
, which keeps things consistent with libafl api.
I'd say a SubInput shouldn't really be sent to the target (?) for example |
I agree on this, the reader was designed to be created and used by the target internally. |
libafl/src/inputs/mod.rs
Outdated
/// - `Ok(Slice)` if the returned slice has `limit` bytes. | ||
/// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` bytes and is not empty. | ||
/// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. | ||
pub fn read_to_slice( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next_sub_input_mut()
or something like that?
libafl/src/inputs/mod.rs
Outdated
} | ||
} | ||
|
||
impl<'a, I> BytesReader<'a, I> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InputSplitter
or something? It's not really bytes specific, is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now it is bytes-specific (even if it could be generic). It's because it creates a BytesSubInput internally, which requires the HasTargetBytes
bound to get the OwnedSlice
instance.
We can make it generic but not sure it would be so useful in practice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still it's not really Reading Bytes, is it? It's spitting byte Inputs, then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd say it's more like reading by chunk, close to what Read
proposes: https://doc.rust-lang.org/std/io/trait.Read.html
this is why i called it like this initially. The difference is that this object is 0-copy (Read
forces to copy in a buffer afaik), so normally this is more efficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, we could implement Seek
: https://doc.rust-lang.org/std/io/trait.Seek.html
didn't do it since i don't really have the use, but it could be useful in some cases.
libafl/src/inputs/mod.rs
Outdated
|
||
impl<'a, I> BytesReader<'a, I> | ||
where | ||
I: HasTargetBytes + HasLen, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need TargetBytes here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get the OwnedSlice
from the input directly.
Another possibility is to take an OwnedSlice<T>
as input to make this generic. Is it worth doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this operate on HasMutatorBytes
though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I wonder if HasTargetBytes
shouldn't actually return a "normal" slice, instead of an OwnedSlice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's more restricting than necessary; HasTargetBytes is enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They happen to be the same for BytesInput but they are different for more abstract input types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
("the thing we send to the target" vs "the thing we mutate")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Want to change it / any reason not to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, didn't have time to check this week.
i was intending to use this in libafl_qemu, where we receive TargetBytes and wrap it whis this object to simplify the process of putting inputs in registers for example. doesn't it sound like TargetBytes-related? or maybe we need this as well for MutatorBytes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah.. The use case it not really mutator related then, right?
Might be somewhat independent (but maybe we can reuse some shared types then?)
What's the status here? |
libafl/src/inputs/bytes.rs
Outdated
@@ -96,13 +96,6 @@ impl HasMutatorBytes for BytesInput { | |||
} | |||
} | |||
|
|||
impl HasTargetBytes for BytesInput { | |||
#[inline] | |||
fn target_bytes(&self) -> OwnedSlice<u8> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be a blanket impl, keep this one (IMHO)
@rmalmain ping |
@domenukk pong. i created an intermediate trait that must be implemented by |
This doesn't really make sense imho, the use case for mutator bytes and target bytes is quite different. |
I mean we could have a |
i think it's good now, anything else @domenukk ? |
libafl/src/inputs/bytessub.rs
Outdated
/// | ||
/// An immutable version is available: [`BytesSlice`]. | ||
#[derive(Debug)] | ||
pub struct BytesSliceMut<'a> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BytesMutSlice
probably, to be consistent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, maybe we should change OwnedMutSlice to OwnedSliceMut? I think the name comes from MutPtr from the stdlib but in that case it could make sense to rename, anyway?
For now we should keep it consistent, though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aah we also have AsSliceMut
so the OwnedMutSlice is actually the one we should change, let's do it for 0.14.
Some smaller questions remain, but all in all looks good now! |
i was actually thinking of moving it to bolts, things like BytesSlice look pretty generic already |
btw i think you forgot a file, no? |
the idea is to safely read over an input by chunks in a lightweight way (see the test for a simple example), by reusing
BytesSubInput
(that has been renamed toBytesSubInputMut
since it contains a mutable reference).it's still in draft state, i think there is room for improvement.
i tried to auto implement
HasTargetBytes
for all implementors ofHasMutatorBytes
but not sure if it is the right thing to do: could it make sense to have mutator bytes that are different from target bytes?also,
end_index
now makes sure it does not go beyond the end of the subslice with a min, better this or should we return an error instead? (we could do something similar forstart_index
)