-
Notifications
You must be signed in to change notification settings - Fork 410
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Adds support for fuzzing via AFL #100
Conversation
In particular, the two files 100 and 200 in the afltests directory cause crash as follows:
|
@pjsg thanks for that Philip! I'll have a thorough look at it tomorrow, at a quick glance it looks good. |
The only extra thing that I might do is to put together a short doc explaining how to do the fuzzing.... |
If you find the time to do that it'd be great. Otherwise it is pretty clear from the testcase. The test stuff does not have to be as lucid and documented as the actual spiffs code. |
It all looks good to me. If you feel finished I'll merge it. The only comment I had was about 'fizzing' which in retrospect I gather was a misspelling. Not having English as native language I'm always keen to learn new words. I googled it in hope to learn something new and useful. Something new I learnt... Useful, I hope not :) |
Actually, I realized that I should restructure the way that this test works -- to make it easy to include specific test cases.... I'll do this tonight. |
I think that this is done.... I checked in a couple of tests that cause problems: fuzzer_found_1 and fuzzer_found_2 I added some code to handle what happens when there is a platform reboot -- i.e. I dump the current state of the file system and then reload it into a new file system. |
I realized that all the failing cases were with multiple open files at the same time. I added a test case 'afl_single' which only uses a single open FD at a time. AFL still finds failures. One of these is test afl_fuzzer_single_1 |
Hmm it should still cope with multiple fds. I'll check it out. Thanks again!
Will merge tomorrow evening (~24 hrs) unless you shout.
Cheers!
|
The only downside to merging is that the default tests no longer pass..... |
Ah yes, you have a point. Well - I'll use it locally then, and fix the errors. When all is done, I'll merge this PR and directly after push the fixes. I am however a bit busy at work for the moment, so things must calm down first before I can dig into it. |
Conflicts: src/test/test_spiffs.c
I updated to fix a merge conflict. I also added some prettier logging in the crash cases. Typical output is:
My feeling is that removing a file while the file is open is probably the issue here.... I'm not enough of a spiffs expert to be able to say whether the remove should have been allowed or not. |
Conflicts: src/test/test_spiffs.c
The issue appears to have been fixed. This PR can now be merged and doesn't break the tests. |
@pellepl Since the tests now pass, can we just get this merged so that it doesn't rot...... |
@pjsg of course, sorry for the long delay and thanks for the efforts. Busy times! :) |
@psjg. Odd. Test 81 and 82 breaks on my local computer. Works on yours? 82 goes fatal so everything shuts down.... Ah. Error in test_spiffs.c. exit(0) on out of bounds write. That's probably why build is passing... |
I just pulled the branch and checked out master and this is what I get:
I hope that it isn't compiler dependant. I'm using Ah -- I just tried on a different system, and I get:
|
Argh! My bad entirely. I had an uncommitted change (I was trying to simulate random power-offs) which made these tests pass...... I checked out a clean copy on my original machine and it still fails... Sorry. |
When I look at the implementation, I'm not even sure that I know what ought to happen in this case. The issue appears to be that the sequence open/write/remove/close ends up corrupting the file system. There are two versions of _remove, once which takes a name and the other an open file handle. This clearly envisages calling it when there is an open file. In a POSIX file system, the remove would just orphan the existing file (which would continue to exist) until the last person closes it. At this point it would be deleted. On windows, AFAIR, you can't delete an open file (I'm not sure if you can rename it either). For SPIFFS, it isn't clear which model it is trying to adopt (and it might be a third model). I suspect that the simplest implementation is the windows model where you just return an error code on removes/renames if the file is open. Of course, this means that the _fremove will always return an error. If I change the fuzzing code to not try and remove (or rename) a file which is open, then the test 82 passes (as it skips the removes). Test 83 still fails:
I suspect that this is a similar issue -- the third open of the file has O_TRUNC set and I'll bet that that confuses something. Maybe there should be a restriction that each file can only be opened once at a time. |
If I implement those restrictions (in the test layer), then I can still provoke a crash with the use of a simulated power cycle (not in the middle of writing, but between calls into SPIFFS). This is true even if I call spiffs_check after mounting....
|
I've dug into this last case, and I think that this is a result of a bad interaction with GC happening at a bad time. The file system is almost full and it first writes the 63 bytes to data to page 17, and then it does some more GC and now has the 63 bytes in page 1c and tries to write that. This doesn't work. I tried turning off caching, but it doesn't make any difference (except that the error then happens as part of the write() call rather than the close() call). |
No problem, I tend to have a mess with my branches my self :)
Umm, that is a good question. I honestly cannot remember, I'll need to scrutinize the code regarding that. I do remember I (though) solved multiple modifications on same file, however caching might mess things up.
I'll have to check this in depth. With a stroke of luck, I might get some time actually doing it soon also. I do recall looking into one of them some time ago - might have been the one you refer to. That particular test had a really on-the-edge config with only four blocks. I am not even sure spiffs should support that. Perhaps it should reject such a mount instead. The fuzzing tests are a great addition, and I really want to keep them. However, perhaps we should temporarily |
I'd be happy making those two tests non-default tests.... I'll submit a PR to do that.... |
This adds a new test (afl_test) which is not run by default, but only if you include it with -f afl_test
This reads from stdin a list of operations (like open, close, read, write, flush, delete, rename etc) and then executes those operations against the SPIFFS api.
Some non-fatal errors have now been made fatal errors (write out of bounds, write which tries to set bits, etc).
AFL can then drive this test and discover interesting combinations of operations that cause failures. The command line:
takes test files from the afltests directory and then puts the results into the findings directory. It may take several hours to find a problem.