fix heap-use-after-free bug of http_request #1975
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
How to reproduce
build h2o with ASAN, and run with the following configuration
and do
h2load -n 100000 -c 100 http://127.0.0.1:8080, then you may see heap-use-after-free bugHow the problem occur
reqloses its referencemrb_obj_allocis called (e.g. mrb_str_new)reqgets releaseddispose_contextfunction is called, the httpclient and the context is freedIn current design, 5. happens because
h2o_mruby_http_request_ctx_t's lifetime relies on mruby objects (I think it's reasonable itself)How to fix
I added the following two amendments:
reqobject into gc arena (i.e.mrb_gc_protect(ctx->refs.request)) in httpclient callback functionmrb_object_dead_pfunction, and if it's not, abort immediatelywhy only a) is not enough?
When httpclient callback is fired: if the incremental gc state (
mrb->gc.state) isMRB_GC_STATE_SWEEP,mrb_gc_protectandmrb_gc_registerdon't protect objects from gc at all, because the gc arena and the global variable table are marked only in root scan phase and the end of marking phase. But here we can perfectly know whether the objects are alive or not because sweep phase means that all incremental marking is finished in this gc cycle. If they are dead, we don't have to do anything and even be able to actively dispose the context and httpclient immediately.why only b) is not enough?
When httpclient callback is fired: if the incremental gc state is
MRB_GC_STATE_MARK, the objects can be recognized asdeadin later incremental marking. So we have to keep that objects by putting them into the arena.