-
Notifications
You must be signed in to change notification settings - Fork 35
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
Unilateral unlinking of edge's TB causes infinite loop #52
Comments
libafl_gen_edge
generated TB generates an infinite looplibafl_gen_edge
generated TB, generates an infinite loop
I forgot an important detail between 9) and 10). I add it below:
|
libafl_gen_edge
generated TB, generates an infinite loop
Thanks a lot for the detailed walkthrough, it was very nice to follow!
I'm not sure about my remark since I can't test easily with an example, so maybe I missed something. I also suspect there is something fishy around |
that check is to avoid to instrument single exit blocks like direct jmp,
they are not branches
Il gio 14 mar 2024, 16:45 Romain Malmain ***@***.***> ha
scritto:
… Thanks a lot for the detailed walkthrough, it was very nice to follow!
There is a point in your explanation I am not sure to understand:
1. "We are now back in cpu_exec_loop, edge is now last_tb, the pc
returned by cpu_get_tb_cpu_state is the same as X, so tb_lookup will
return X." -> At this point last_tb should be X, not edge, no? (since
X and edge are linked together). Also, cpu_get_tb_cpu_state should
return the pc right after X, not the pc of X if I'm not wrong, since the
call to ops->tb_stop(db, cpu); will make the TB update the pc at the
end of its execution.
I'm not sure about my remark since I can't test easily with an example, so
maybe I missed something. I also suspect there is something fishy around if
(last_tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID).
—
Reply to this email directly, view it on GitHub
<#52 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AD3LJ6VYB5XXC7P3O22X2IDYYHA3FAVCNFSM6AAAAABEUHK7T6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOJXG43DGNRXGI>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Yes, I meant this is indeed where we would create the infinite loop if we are in the conditions he describes ( |
Yes, I supspect like a cache invalidation in between, that would explain
why he cannot reproduce on a small example program
Il gio 14 mar 2024, 17:06 Romain Malmain ***@***.***> ha
scritto:
… Yes, I meant this is indeed where we would create the infinite loop if we
are in the conditions he describes (last_tb == edge and pc == X). I'm
surprised there is an infinite loop there tough, if my scenario is the one
being executed then last_tb == X and pc == Y. In that case we should just
fall back to the original generation of edge and Y no?
—
Reply to this email directly, view it on GitHub
<#52 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AD3LJ6V3WE2HCD42ZKQ27QDYYHDHBAVCNFSM6AAAAABEUHK7T6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOJXHAYDMNZSG4>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
No? From my debugging, within
This is true for regular TBs. However, for edge TBs, the code responsible for updating
and the lines below are taken from edge's generated code:
As you can see, in the code above, the part that updates To be honest, I haven't went through the specifics of the ops generation part, so I can't say for sure why the PC is updated exclusively for regular TBs and not for edges'. However, I can somewhat understand why this occurs: what would be the next PC of an invalidated edge? Conceptually speaking, it doesn't seem reasonable to me for an edge to update the PC of the left-side TB (the TB I referred to as X in my example), as its sole purpose is to execute hooks and transition to Y.
@andreafioraldi could you explain what is it this cache you mentioned? I believe reproducing this issue on a small program (e.g., examples within the fuzzers directory) might be not possible because there might not be any QEMU user-mode example that replicates the scenario I'm facing (namely, edges between RWX regions being invalidated by the signal handler). Btw, I think that with some effort I can create a small program that reproduces the issue but I would do that only if really necessary, as it would require a considerable amount of time. |
Btw, I think we cannot just simply unlink |
Fixed in #53. |
Context: my target allocates RWX pages, which are populated with jit code and executed.
I'm experiencing infinite loops when using the
QemuCoverageEdgeHelper
. The infinite loop occurs because the edges generated bylibafl_gen_edge
have the same pc as the last TB executed and because edges' TB is unlinked from its successor in the chain when the QEMU's signal handler is triggered.I report below, step-by-step, a possible scenario that would trigger the infinite loop:
cpu_exec_loop
and about to execute a TB, named X from now onjne
to another TB, named YX -> edge -> Y
the important detail here is that the edge's TB has the same pc as X
tb_invalidate_phys_page_unwind
tb_jmp_unlink
is executed,tb_reset_jmp
is called on the edge's TB. Now edge's TB and Y are not linked anymore:X -> edge -x-> Y
cpu_exec_loop
, edge is nowlast_tb
, the pc returned bycpu_get_tb_cpu_state
is the same as X, sotb_lookup
will return X, X will be executed again, which will jump again to 9), resulting in an infinite loop between 9) and 10)I see two possible problems here:
I think a possible solution would be:
when the signal handler is triggered, and we are unlinking an
edge -> TB2
relationship, we should also unlink the other side of the chain:TB1 -> edge
.I'm open to other suggestions.
The text was updated successfully, but these errors were encountered: