-
-
Notifications
You must be signed in to change notification settings - Fork 390
[WIP?] QemuSugar Snapshot support (+ OptionalModule) #3341
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
base: main
Are you sure you want to change the base?
Conversation
Forgot to note. It looks like it works when trying from the python bindings on the python_qemu fuzzer's target. The perfs are slightly decreased but I believe this is because the target is so small that the snapshot reset is heavy compared to just reseting a few registers and running again. Also taking any feedback on how I should test it further. |
imo this should be named as IfModule, |
@domenukk what do you think? |
Yes would be good if possible / easy to do |
wait.. I have to understand what this optional is for, is it because you want to make it configurable at runtime to use the snapshot module in libafl_sugar? |
if that's your goal, how about doing it like
yes, you a lot of duplicate code in this way, but to me it's more reasonable to handle all this in the user's code (libafl_sugar's code) |
You're right that's the goal. |
Regarding the name, I chose
I can do it but it'll require a few changes. Like dropping the Anyway, if you feel it adds too much complexity to the qemu code I'm happy to drop this. |
use crate::modules::{EmulatorModule, EmulatorModuleTuple}; | ||
|
||
#[derive(Debug)] | ||
pub struct OptionalModule<MD> { |
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.
If we don't use a closure, this should probably be an Enum
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 agree with that.
the way it's written, it looks like the module could be enabled after it has been initialized, which would definitely not work in most cases.
with an enum like
pub enum OptionalModule<MD> {
Disabled,
Enabled(MD),
}
it would make the intention clear.
A closure that checks a single flag should optimize reasonably well, don't you think? Probably emits the same code in the end |
@@ -842,8 +845,15 @@ pub fn trace_write_snapshot<ET, I, S, const SIZE: usize>( | |||
I: Unpin, | |||
S: Unpin, | |||
{ | |||
let h = emulator_modules.get_mut::<SnapshotModule>().unwrap(); | |||
h.access(addr, SIZE); | |||
if let Some(h) = emulator_modules.get_mut::<SnapshotModule>() { |
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 don't think we should remove the unwrap here.
if for some reason we end up there and there is no snapshot module, it's actually a bug.
the comment applies to all the other similar changes.
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.
If the SnapshotModule is wrapped in an OptionalModule
this call will fail, so this is done so we have a chance to retrieve the module from inside the OptionalModule
.
So the unwrap is kept in the else
branch.
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.
yeah i see, i'm not sure the current solution is good.
it forces to do code duplication.
maybe we can replace get_mut
with a new method, calling to a method implemented by the trait EmulatorModule
, which can return an Option<&mut Self>
? it's a bit heavy but at least we can keep the same semantic and avoid duplicating code in callbacks
@@ -81,6 +81,9 @@ pub struct ForkserverBytesCoverageSugar<'a> { | |||
/// Fuzz `iterations` number of times, instead of indefinitely; implies use of `fuzz_loop_for` | |||
#[builder(default = None)] | |||
iterations: Option<u64>, | |||
/// Disable redirection of stdout to /dev/null on unix build targets |
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 not just use a bool here?
use crate::modules::{EmulatorModule, EmulatorModuleTuple}; | ||
|
||
#[derive(Debug)] | ||
pub struct OptionalModule<MD> { |
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 agree with that.
the way it's written, it looks like the module could be enabled after it has been initialized, which would definitely not work in most cases.
with an enum like
pub enum OptionalModule<MD> {
Disabled,
Enabled(MD),
}
it would make the intention clear.
@@ -88,6 +91,8 @@ where | |||
/// Disable redirection of stdout to /dev/null on unix build targets | |||
#[builder(default = None)] |
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 guess this is why you used Option<bool>
.
we can just use bool
here as well instead, same for next field
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.
Most of it uses Option<bool>
so I mimicked it. Maybe it is done this way because of the python bindings, allowing to have optional parameters. I'm not sure this is the explanation 🤷
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.
we should be able to default to false
or smth like that.
i don't think it would break anything, we can try
it's fine the way @jma-qb did it, it's adding a file without touching the internal logic.
in term of performance, the extra check would only be noticeable in |
but for example in |
https://github.com/AFLplusplus/LibAFL/blob/poc/crates/libafl_sugar/src/qemu.rs I have a solution using macros 😜 |
which hashmap lookup? if you use snapshot in the same way as before, it will replace |
yeah i saw, i don't want to maintain this kind of macro, they tend to become unreadable. |
@tokatoka @rmalmain
Description
Trying to add an optional support for snapshot in Qemu Sugar. @domenukk suggested a
IfModule
like theIfStage
to avoid duplicating a lot of code and pleasing Rust's type system.I went with a simpler version taking a bool rather than a closure as we probably don't want to dynamically change the list of loaded modules.
I had to fix the
SnapshotModule
because it couldn't retrieve the module wrapped in theOptionalModule
but:I'm open to any suggestion to improve this and how/where I should document it.
Checklist
./scripts/precommit.sh
and addressed all commentsI ran the precommit script but couldn't address all comments.
In this example clippy wants me to merge the two
if
because it can't see the arm specific code.Also when targeting arm so it doesn't complain about this I got a lot of errors