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

Issues discovered through fuzzing #166

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

blaugold
Copy link
Contributor

I've been experimenting with testing Fleece with fuzzed Fleece data.

In the process, I had to expand the validation of untrusted Fleece data. It seems to be quite complete now. Fuzzing for an extended amount of time does not produce new assert failures or crashes.

I found and fixed the following issues:

  • An assert is not handling comparing two nan floats.
  • ValueSlot::copyValue does not handle integers and binary data.
  • An undefined value in a Dict causes an incorrect count in deep mutable copies.
    The problem is that in this line _source->get(key) returns nullptr for a undefined value, so ValueSlot::setting is not able to distinguish between a new key and a key with an undefined value.
    I'm not sure if my fix is the right approach, though.

The fuzzing function I used is relatively simple. With a more advanced function (e.g. also handling shared keys) it might be possible to discover more issues.

#include <cstdlib>

#include "fleece/Fleece.hh"
#include "fleece/Mutable.hh"
#include "fleece/Expert.hh"

static void IterateValue(fleece::Value& value) {
    fleece::DeepIterator copyIter(value);
    for (; copyIter; ++copyIter) {}
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
    fleece::alloc_slice slice(Data, Size);
    fleece::Doc doc(slice);

    if (doc) {
        auto root = doc.root();
        IterateValue(root);

        switch (root.type()) {
            case kFLArray: {
                auto copy = root.asArray().mutableCopy(kFLDeepCopyImmutables);
                IterateValue(copy);
                break;
            }
            case kFLDict: {
                auto copy = root.asDict().mutableCopy(kFLDeepCopyImmutables);
                IterateValue(copy);
                break;
            }
            default:
                return 0;
        }
    }

    return 0;
}

Fuzzing with LLVM's libFuzzer is quite straightforward and could be automated in CI.

@blaugold blaugold force-pushed the fuzzing branch 3 times, most recently from c1540c8 to 7b05837 Compare October 1, 2022 11:29
@blaugold
Copy link
Contributor Author

blaugold commented Oct 1, 2022

Tow more issues:

  • Fix the count of a dict that inherits all of its entries from the parent.
  • Distinguish a nullslice from an empty slice. The two are not the same, but FLSlice_Equal and FLSlice_Compare treats them as if they are.

@blaugold
Copy link
Contributor Author

blaugold commented Nov 6, 2022

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.

None yet

1 participant