Closed Dr-Emann closed 1 year ago
@Dr-Emann
Unfortunately, this is finding some issues
If you think that there is a bug in CRoaring, the best first step would be to push the issue upstream with a reproducible test case. We can also add more fuzzing to CRoaring.
do you have any handle on how unsafe it might be to handle a bitmap which doesn't follow the rules like that
I am not sure what the question is. Can you specify which bitmap and which rules?
@lemire, I'm not sure if it would be considered a bug or not.
The issue is that a deserialized bitmap may not be "internally valid". In the specific case I found (C example code below), it appears the deserialized bitmap has a bitset container which says it has a different cardinality than the number of bits actually set in the bits.
I'm asking: How bad is that. What can we expect from operating on a bitmap which isn't "internally valid"? I'm worried about e.g. we could probably get a negative cardinality since cardinality is stored as an i32, and what that could do, etc. Will it just return possibly nonsense, or could it invoke full undefined behavior?
And finally, is just running roaring_bitmap_internal_validate
afterwards enough to ensure a deserialized bitmap is safe to perform all operations on? We could add that to our deserialize method, and add an unsafe option for performance if they're sure the data really contains a validly serialized bitmap.
How bad is that.
Possibly quite bad. As in... it could lead to hard crashes.
I don't have an example in mind, but I would not assume that it is safe.
it appears the deserialized bitmap has a bitset container which says it has a different cardinality than the number of bits actually set in the bits.
That's certainly possible because we serialize both independently.
@saulius, I'm recommending we add a call to validate the bitmap after deserializing, and add an unsafe method to allow deserializing without that validation for performance. Maybe yanking 2.0.0 once we release a fix?
Also, I'm not super sure how to fix the buildtime_bindgen builds. It seems related to #110, although it's a different error. It does bindgen just fine on my machine (an M1 mac) so it's a bit hard for me to debug.
@lemire it's also a bit unexpected that CRoaring (as a library) writes directly to stderr, running the fuzzing, I get a lot of output e.g. I failed to find one of the right cookies. Found 1073754170
.
I think I checked for all the assumptions I think CRoaring might make in roaring_bitmap_internal_validate
: that if it succeeds, the bitmap should behave sanely, but I'm of course worried I missed something.
it's also a bit unexpected that CRoaring (as a library) writes directly to stderr,
It shouldn't. I will write a PR.
@saulius, I'm planning to merge this in the next few days, especially because of the memory unsafely possibility in deserialization currently, unless you have any issues.
Thanks for fixing this @Dr-Emann.
Maybe yanking 2.0.0 once we release a fix?
Do you mean yank 1.0.0
of croaring-rs? I think this can be done.
Maybe yanking 2.0.0 once we release a fix?
Do you mean yank
1.0.0
of croaring-rs? I think this can be done.
D'oh! Yes, that's what I meant. Got confused with 1.0 of croaring-rs and the recent bump to 2.0 of CRoaring.
See CRoaring release 2.0.0 and CRoaring release 2.0.1. I don't believe there's any significant changes from our perspective, other than a new internal validation function.
Adds a binding for the new
roaring_bitmap_internal_validate
function for testing purposes.Add a fuzzer for deserialization, and include calls to
internal_validate
.Per below discussion, deserialization functions now call
internal_validate
before returning a bitmap, since an inconsistent bitmap can lead to adverse behavior possibly including UB. This also adds atry_deserialize_unchecked
unsafe function to allow fully unsafe deserialization when the caller knows the data a valid bitmap.This removes the buildtime_bindgen feature (the feature itself is still there, but it is now a no-op). I've verfied that all the current bindings are totally independant of the environment: croaring doesn't use any #ifdefs to change any types defined in the APIs. All types in the API are the same for all architectures (that's not to say the size of the types are the same, for instance, size_t is used, but that is translated to the single type usize).