Skip to content
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

posix: add fuzz testing using MAVLink messages #12896

Merged
merged 3 commits into from
Jan 7, 2022
Merged

Conversation

julianoes
Copy link
Contributor

@julianoes julianoes commented Sep 4, 2019

This adds the env option PX4_FUZZ which runs the LLVM libFuzzer which throws random bytes at mavlink_receiver using MAVLink messages over UDP.

The MAVLink messages that are being sent are valid, so the CRC is calculated but the payload and msgid, etc. are generally garbage, unless the fuzzing gets a msgid right by chance.

As I understand it, libFuzzer watches the test coverage and will try to execute as much of the code as possible.

To run this, do:

PX4_FUZZ=1 make px4_sitl_default-clang && (cd build/px4_sitl_default-clang/tmp/rootfs && mkdir CORPUS -p && ../../bin/px4 -detect_leaks=1 CORPUS/)

To stop it (if it never crashes): killall px4, or Ctrl+C.

So far I've been running this multiple days on a desktop computer but have not found anything.

@julianoes julianoes requested review from dagar and bkueng September 4, 2019 14:42
@dagar
Copy link
Member

dagar commented Sep 4, 2019

I wonder if we could be a bit more targeted to the subset of message ids we actually implement in mavlink_receiver. Seeing this with code coverage would also be interesting.

@julianoes
Copy link
Contributor Author

julianoes commented Sep 4, 2019

Seeing this with code coverage would also be interesting.

Anecdotal I can say that while running the tests it prints functions that it executed and I saw many of the mavlink_receiver functions pop up, so I assume all were used at some point.

However, you can collect coverage info and visualize it. I'll do that and share it.

@julianoes
Copy link
Contributor Author

@BazookaJoe1900 just found that I had forgotten that you require the patch below in the c_library_v2/pymavlink submodule, otherwise the address sanitizier will be triggered:
https://github.com/ArduPilot/pymavlink/pull/343/files

@dagar
Copy link
Member

dagar commented Sep 5, 2019

Apparently this doesn't actually matter, but can you add the build type here?
https://github.com/PX4/Firmware/blob/c8d13bacf2fb561cb3bdf12a4846ee52c06bbccf/CMakeLists.txt#L253

@hamishwillee
Copy link
Contributor

@julianoes Is this anything that needs to be added to test docs? http://dev.px4.io/master/en/test_and_ci/

@julianoes
Copy link
Contributor Author

@hamishwillee yes I want to add something. And maybe have it fuzz 5 minutes on a known corpus (input data) in CI.

@julianoes
Copy link
Contributor Author

julianoes commented Sep 5, 2019

Apparently this doesn't actually matter, but can you add the build type here?

ok I'll add it there too.

Seeing this with code coverage would also be interesting.

I looked at coverage for the corpus (input data) acquired over about 8 hours and it looks like all handle_message in MavlinkReceiver are covered. However, also all handle_message functions in Simulator are covered and I'm wondering why because no simulator like jMAVSim or Gazebo is running that would send that input.

Attached is a coverage file. It's in colors, so to see it you have to do something like cat coverage_handle_message.txt.

coverage_handle_message.txt

@dagar
Copy link
Member

dagar commented Sep 22, 2019

Would it make sense to add even the simplest minimal use of this to Jenkins to prevent from breaking the configuration and other setup helpers?

@julianoes
Copy link
Contributor Author

@dagar yes, I'll do that.

@stale
Copy link

stale bot commented Dec 22, 2019

This issue has been automatically marked as stale because it has not had recent activity. Thank you for your contributions.

@stale stale bot added the stale label Dec 22, 2019
@julianoes julianoes marked this pull request as draft June 2, 2020 11:29
@stale stale bot removed the stale label Jun 2, 2020
@stale
Copy link

stale bot commented Aug 31, 2020

This issue has been automatically marked as stale because it has not had recent activity. Thank you for your contributions.

@stale stale bot added the stale label Aug 31, 2020
@hamishwillee
Copy link
Contributor

@julianoes Should we let this die?

@stale stale bot removed the stale label Aug 31, 2020
@julianoes
Copy link
Contributor Author

@bkueng @dagar I'm making another effort to get this in.

@julianoes
Copy link
Contributor Author

@dagar do you have a good idea how we could integrate this into CI? Basically, we should run it for a certain amount of time and record the output if it does fail. If it is still running after some time we would just stop it with killall -SIGKILL px4.

Alternatively, we could try to get into the google/oss-fuzz project where they seem to provide free fuzzing for open source projects.

@julianoes julianoes marked this pull request as ready for review December 7, 2020 02:29
@dagar
Copy link
Member

dagar commented Dec 7, 2020

@dagar do you have a good idea how we could integrate this into CI? Basically, we should run it for a certain amount of time and record the output if it does fail. If it is still running after some time we would just stop it with killall -SIGKILL px4.

Any idea what kind of time is involved (imagine slower 2 core machine)?

Alternatively, we could try to get into the google/oss-fuzz project where they seem to provide free fuzzing for open source projects.

Cool, I had this on my list of things to look into. It's not clear to me if it's worth the effort to integrate vs doing it ourselves.

@julianoes
Copy link
Contributor Author

Any idea what kind of time is involved (imagine slower 2 core machine)?

Not sure. More is better but maybe doing 5 mins on each merge to master is pretty good. From what I understand if you cache the CORPUS (some inputs) it will re-use these.

@LorenzMeier
Copy link
Member

@julianoes Given how long this PR is open I will close it soon as stale. I know we want to get this in, so let's focus on merging it in a state that is an incremental improvement, rather than keeping it open longer. Could you please make sure this is mergable and documented and then add commits on top where needed later?

@julianoes julianoes marked this pull request as draft May 28, 2021 11:40
@julianoes julianoes force-pushed the pr-fuzz-testing branch 9 times, most recently from 0db7927 to dcd76eb Compare December 21, 2021 09:18
@julianoes
Copy link
Contributor Author

Memory sanitizer found something:

 INFO: A corpus is not provided, starting from an empty corpus
#2	INITED cov: 23 ft: 24 corp: 1/1b exec/s: 0 rss: 77Mb
#3	NEW    cov: 23 ft: 36 corp: 2/2b lim: 4096 exec/s: 0 rss: 77Mb L: 1/1 MS: 1 ChangeBit-
#6	NEW    cov: 25 ft: 51 corp: 3/124b lim: 4096 exec/s: 0 rss: 78Mb L: 122/122 MS: 3 InsertByte-CopyPart-InsertRepeatedBytes-
#10	NEW    cov: 25 ft: 53 corp: 4/129b lim: 4096 exec/s: 0 rss: 78Mb L: 5/122 MS: 4 CopyPart-ChangeBit-CMP-ChangeBit- DE: "m\000\000\000"-
#12	NEW    cov: 26 ft: 54 corp: 5/245b lim: 4096 exec/s: 0 rss: 78Mb L: 116/122 MS: 2 PersAutoDict-InsertRepeatedBytes- DE: "m\000\000\000"-
#14	NEW    cov: 26 ft: 56 corp: 6/280b lim: 4096 exec/s: 0 rss: 78Mb L: 35/122 MS: 2 CrossOver-InsertRepeatedBytes-
#18	REDUCE cov: 26 ft: 56 corp: 6/239b lim: 4096 exec/s: 0 rss: 78Mb L: 75/122 MS: 4 ChangeBinInt-InsertByte-ChangeBit-EraseBytes-
INFO  [logger] logger started (mode=all)
	NEW_FUNC[1/142]: 0x64dc30 in uORB::SubscriptionMultiArray<battery_status_s, (unsigned char)4>::SubscriptionMultiArray(ORB_ID) /src/PX4-Autopilot/platforms/common/uORB/SubscriptionMultiArray.hpp:68
	NEW_FUNC[2/142]: 0x64e080 in uORB::SubscriptionMultiArray<distance_sensor_s, (unsigned char)10>::SubscriptionMultiArray(ORB_ID) /src/PX4-Autopilot/platforms/common/uORB/SubscriptionMultiArray.hpp:68
#23	REDUCE cov: 378 ft: 204 corp: 7/335b lim: 4096 exec/s: 0 rss: 80Mb L: 96/122 MS: 5 InsertByte-CopyPart-CrossOver-InsertByte-PersAutoDict- DE: "m\000\000\000"-
#31	REDUCE cov: 378 ft: 204 corp: 7/305b lim: 4096 exec/s: 0 rss: 80Mb L: 45/122 MS: 3 CopyPart-PersAutoDict-EraseBytes- DE: "m\000\000\000"-
INFO  [mavlink] partner IP: 127.0.0.1
	NEW_FUNC[1/4]:     #0 0x66d718 in Commander::run() /src/PX4-Autopilot/src/modules/commander/Commander.cpp:2592:7
    #1 0x67eeba in ModuleBase<Commander>::run_trampoline(int, char**) /src/PX4-Autopilot/platforms/common/include/px4_platform_common/module.h:180:12
    #2 0xd905b2 in entry_adapter(void*) /src/PX4-Autopilot/platforms/posix/src/px4/common/tasks.cpp:98:2
    #3 0x7f40a103a608 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x9608)
    #4 0x7f40a0f40292 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x122292)

DEDUP_TOKEN: Commander::run()--ModuleBase<Commander>::run_trampoline(int, char**)--entry_adapter(void*)
  Uninitialized value was created by a heap allocation
0x598d70 in uORB::SubscriptionInterval::updated() /src/PX4-Autopilot/platforms/common/uORB/SubscriptionInterval.hpp:97
	NEW_FUNC[2/4]:     #0 0x563339 in operator new(unsigned long) /src/llvm-project/compiler-rt/lib/msan/msan_new_delete.cpp:45:35
    #1 0x67ecc5 in Commander::instantiate(int, char**) /src/PX4-Autopilot/src/modules/commander/Commander.cpp:3385:24
    #2 0x67ecc5 in ModuleBase<Commander>::run_trampoline(int, char**) /src/PX4-Autopilot/platforms/common/include/px4_platform_common/module.h:176:15
    #3 0xd905b2 in entry_adapter(void*) /src/PX4-Autopilot/platforms/posix/src/px4/common/tasks.cpp:98:2
    #4 0x7f40a103a608 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x9608)

DEDUP_TOKEN: operator new(unsigned long)--Commander::instantiate(int, char**)--ModuleBase<Commander>::run_trampoline(int, char**)
SUMMARY: MemorySanitizer: use-of-uninitialized-value /src/PX4-Autopilot/src/modules/commander/Commander.cpp:2592:7 in Commander::run()

@julianoes
Copy link
Contributor Author

@dagar it now fuzzes 3x 10 minutes, for every PR, using 3 different sanitizers. It fuzzes from scratch every time, and does not use a corpus cache. We could alternatively run it daily on master and keep a fuzzing CORPUS in cache.
What would you prefer?

Also see: https://google.github.io/clusterfuzzlite/overview/


if(NOT CMAKE_BUILD_TYPE STREQUAL FuzzTesting)
list(APPEND cxx_flags
-fno-rtti
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could maybe even be a NuttX specific flag.

Copy link
Contributor Author

@julianoes julianoes Dec 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea, you tell me. Ah, I guess, we just wanted to match what we have with NuttX.

return 0;
}

void initialize_fake_px4_once()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to throw this into an entirely separate file and have clear entry points (regular main vs fuzzing)?

The regular SITL start is already kind of convoluted and has other issues we need to address (clean shutdown, etc).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would, yes 😄. I'll give it a try.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, have a look :)

@julianoes julianoes marked this pull request as ready for review January 3, 2022 08:24
This adds the env option PX4_FUZZ which runs the LLVM libFuzzer which
throws random bytes at mavlink_receiver using MAVLink messages over UDP.

The MAVLink messages that are being sent are valid, so the CRC is
calculated but the payload and msgid, etc. are generally garbage, unless
the fuzzing gets a msgid right by chance.

As I understand it, libFuzzer watches the test coverage and will try to
execute as much of the code as possible.
So instead of fuzzing each and every PR for 10minutes, we just fuzz
30mins every 24 hours, at 6am UTC which should be a time when US and
Europe might be least active.
@julianoes
Copy link
Contributor Author

@dagar I suggest we merge this and then check if the cron job every 24h does the fuzzing.

@dagar dagar merged commit be0a5b4 into master Jan 7, 2022
@dagar dagar deleted the pr-fuzz-testing branch January 7, 2022 15:17
@DronecodeBot
Copy link

This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there:

https://discuss.px4.io/t/fuzz-testing-for-px4/35623/2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants