-
-
Notifications
You must be signed in to change notification settings - Fork 367
libafl_frida: Add tests for ASan for Unix platforms #1781
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
Conversation
…1) destroying Gum causes segmentation fault and thus a single test is supported by using a static Gum object. Ideally, this should be fixed and a new Gum instance would be created for each test. 2) 70 identical errors are reported by Asan instead of a a single one. Apart from that, the draft fixes a number of errors found in Asan
libafl_frida/harness.cpp
Outdated
#include <string> | ||
|
||
extern "C" int heap_uaf_read(const uint8_t *_data, size_t _size) { | ||
int *array = new int[100]; |
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.
are you purposely using c++ allocations instead of raw malloc
s?
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.
Nothing special; more tests should be added that will cover C. I just started from code present in some other example, and it used C++.
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.
Ok. So we should make sure to include versions of the tests which use the C api.
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, are you certain your tests aren't being optimized out?
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.
Added several malloc-based tests and -O0 to the compilation options to make sure the code is not optimized out. We still need a way to run all the tests. Until AsanRuntime cleans up when dropped this is not possible
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.
Ideally tests should be run by cargo test
.
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 you run cargo test this one will run. It is already like that
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.
FWIW we can also add external tests in a Makefile.toml
and run these with cargo make test
(and CI supports it too).
Of course it's nice like it's now, but not everything may be possible that way, so mentioning it as well
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 had a brief look at proper AsanRuntime uninitialization and it indeed should be done in a separate PR. I prefer to complete this one to prevent more merges as time passes. So, can we resolve it as it is now? @s1341 I'll need your help with how to shut things down properly. I initially thought of keeping the helper around and creating a new executor for each test. This does not compile due to some dependencies between the lifetime of the harness and of the helper (which I can't figure out yet).
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've figured this out, and now multiple tests are running. Please review
Left some comments about new dependencies - we try to keep these low. Feel free to ignore this until the PR is ready, then we can still clean it up :) |
Where are these comments? |
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.
Oops forgot to publish the comments
libafl_frida/src/lib.rs
Outdated
#[test] | ||
#[cfg(unix)] | ||
fn run_test_asan() { | ||
env_logger::init(); |
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.
libafl_bolts has a SimpleStdoutLogger
that you can use to get around this dependency 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.
The ability to specify the trace level at runtime is very helpful. Does SimpleStdoutLogger support this?
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.
Moved to dev-dependencies
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.
Not sure, but for a test you don't usually see the logs anyway? For development purposes it's a different story, but I'd still prefer to not add crates to the library that are not needed in the normal case
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.
FWIW I usually use something like this to enable trace in debug builds, but you could also make that read an env
manually
if cfg!(debug_assertions) {
log::set_max_level(log::LevelFilter::Trace);
} else {
log::set_max_level(log::LevelFilter::Info);
}
SimpleStdoutLogger.set_logger().unwrap()
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 indeed use this while developing the test, because it is quite complicated. I can remove this altogether or switch to SimpleStdoutLogger if it is important. However, I don't see it used anywhere as of now
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've written the code using SimpleStdoutLogger, but the prints don't appear even though writing to stdout stream works...
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.
That's somewhat concerning, you did set the LeveFilter accordingly? Do rust tests close stdout or something?
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 found the problem. In cargo test, the output of successfull tests is suppressed by default, both those sent to stdout and stderr. To see the output, run cargo test -- --nocapture
. Pushed the code
libafl_frida/build.rs
Outdated
// Build the test harness | ||
// clang++ -shared -fPIC -o harness.so harness.cpp | ||
#[cfg(unix)] | ||
std::process::Command::new("clang++") |
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.
This should potentially use the cc
crate to have (some) support for other environments
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 did not find a way to build a shared library with cc. If you have an idea - please let me know
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.
cc::build::new()
.flag("-shared")
.flag("-fPIC")
?
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.
Nope, this does not work. It produces a .a file and ignores the -shared. There is no linker running as well.
This is what I run:
cc::Build::new() .flag("-v") .flag("-shared") .flag("-fPIC") .flag("-O0") .file("test_harness.cpp") .compile("test_harness.so");
This is what it resulted in:
file /home/me/LibAFL/target/release/build/libafl_frida-3e26f9fa0e88b5c2/out/libtest_harness.so.a /home/me/LibAFL/target/release/build/libafl_frida-3e26f9fa0e88b5c2/out/libtest_harness.so.a: current ar archive
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.
Hmm, sad...
Alternatively maybe we can reuse the compiler detection from libafl_cc's build.rs here?
Line 293 in 3d126f2
clangcpp = bindir_path.join("clang++"); |
Assuming clang is in the path may or may not work, I fear.
Or worst case ignore the testcase if clang wasn't found?
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 could copy the code over, but am not sure it is worth the effort for the current initial state where a single platform is supported by Asan (and therefore for its test). The compiler detection in libafl_cc is quite complicated, and for UNIX eventually just checks if llvm-config is in the path and then runs it. I guess that if llvm-config is in the path, clang++ will be there as well. I can start with checking for clang presence and skip compilation if not found, then the test will be skipped if the harness is not found.
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.
Added checking for clang and failing the test if the harness not found
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 a bit unfortunate cargo test
can fail because of the PATH now, maybe we should make this optional somehow? Also, on MacOS the file extension would usually be dylib, right?
But anyway we can merge and then fix these things later
Sorry for nagging, this PR is very much appreciated btw :) |
…st_harness" This reverts commit 2d3494b.
If possible, I'd prefer to merge this without adding more features or placeholders for more platforms, as Asan doesn't support anything but Unix as of now. Postponing a merge of this just increases the size of the code to merge |
can you run fix the clippy and run ./script/fmt_all.sh |
I ran fmt and merged main. But clippy has nothing to do with my changes; it complains about dependencies in libafl_bolts and libafl. As I wrote above, I'm unsure how that main is in such a state. |
I ran fmt and merged main. But clippy has nothing to do with my changes; it complains about dependencies in libafl_bolts and libafl. As I wrote above, I'm unsure how comes that main is in such a state. |
because clippy updates bring new lints. |
can you fix it as suggested by clippy?
Also it's not formatted yet. you need to clang-format your test-harness.cpp |
I ran clippy many times, both nightly and stable, and I don't get this error. I also looked up the GitHub builds and don't see it. What command do you run to get it? |
i didn't run it but the log says so |
Oh, crap. I ran scripts/clippy locally with the latest toolchain and hope this time it is ok |
Aweoms, it's green! |
All of the commented-out stuff is no longer required? Or will you bring it back? |
I left it because it seemed that it might be useful for macos/ios when someone gets ASan working there. |
How do you mean get asan working there? It was working IIRC? cc @fabianfreyer |
cargo test already is a part of the CI steps |
Maybe it's my misunderstanding, I indeed see some indications of this support, but have no way of testing |
So, will this be merged? |
let shadow_mapping_start = map_to_shadow!(self, start); | ||
|
||
let shadow_start = self.round_down_to_page(shadow_mapping_start); | ||
// I'm not sure this works as planned. The same address appearing as start and end is mapped 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.
it's not about the code you did but do you know why create a new mappings here in this function?
after we find the suitable bit in init() then the shadow region is mapped and then we are good and ready to start fuzzing right?
I don't get the purpose of this function.
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 ok i understand now it's like a primitive malloc
I'm still uneasy about the removed parts for MacOS.. |
It definitely used to work. Can we make sure it still works? @tokatoka did you look at the comments? |
Any functional reasons you removed the code or just refactoring? |
Yes - the code was crashing on linux. It tries to extend the stack beyond the originally allocated region. But in all cases I tested there was another allocated region adjacent to it so it was not possible just to stretch the stack over. Maybe on Mac it makes some sense, but I haven't work on Mac for some years and don't have one at hand to test. There were no comments to explain why this was necessary in the first place and it worked correctly with the original stack so I commented it out hoping that whoever wrote this will react. |
Ok then, I guess we'll keep it like this and have to hope someone fixes MacOS again (don't have time myself) |
The PR contains a basic structure for running multiple tests and a few harness functions with different errors to be caught by ASan.
Apart from that, the draft fixes several errors found in Asan itself. Also, I disabled the stack increasing as is caused a crash on my Linux (the adjacent memory was in use). The code contains a workaround for a bug in frida-rust, that is fixed now, but the fix has not been released yet.
This is a WIP, as:
Your comments are welcome.