Skip to content

Conversation

@SoniEx2
Copy link
Collaborator

@SoniEx2 SoniEx2 commented Sep 13, 2024

The interpreter could overflow the stack without trapping properly in call_indirect situations. While it would set the out_trap to the trap reason, it would return RunResult::Ok and the interpreter code would only check RunResult::Ok to decide whether or not to keep running. In other words, while the stack overflow meant the interpreter wouldn't push a frame onto the call stack, the interpreter loop would continue advancing instructions, resulting in instructions after the runaway call_indirect running.

If the offending call_indirect didn't have return values, it would be as if the call returned normally. If it did have return values, nothing would be pushed onto the value stack, yet the return types would be pushed onto the type stack. With careful manipulation of the following instructions, this could be used to cause all sorts of memory corruption.

As it turns out, the function exit code, as well as a handful of other instructions, do check the state of the value and type stacks and can safely reproduce the bug without the memory corruption, so that's what we made the test do.

The obvious fix was to make call_indirect propagate RunResult::Trap properly. Additionally, we made it so assert_exhaustion checks both the RunResult and the out_trap, and asserts if they don't match. This should help catch similar bugs in the future.

Closes #2462
Fixes #2398

@SoniEx2 SoniEx2 force-pushed the fix-memory-corruption branch from 0ad7539 to 16f41de Compare September 13, 2024 23:39
@SoniEx2 SoniEx2 marked this pull request as ready for review September 13, 2024 23:40
@SoniEx2
Copy link
Collaborator Author

SoniEx2 commented Sep 14, 2024

@keithw @sbc100

@SoniEx2
Copy link
Collaborator Author

SoniEx2 commented Sep 14, 2024

(we were trying to figure out a way to trigger the bug consistently, without triggering the memory corruption. it was hard, but we're glad we figured something out.)

@sbc100
Copy link
Member

sbc100 commented Sep 18, 2024

Could you add some details to the PR description saying what the issue is exactly and how this change fixes it?

(elem
$runaway-with-return
)
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this table declaration can fit all on one line maybe?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, can this be reproduced even without a table? I.e. just with a direct call?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as far as we could tell, no - the codepath for call is different from the codepath for call_indirect...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we chose to write the table declaration like this for consistency with the code style of upstream tests

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as far as we could tell, no - the codepath for call is different from the codepath for call_indirect...

The reason I ask is that the changes on the interpreter side all like they are part of DoCall.. which doesn't look specific to indirect calls. But I've not looked at the interpreter code in a long time so I maybe be misunderstanding.

Copy link
Collaborator Author

@SoniEx2 SoniEx2 Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, for some reason O::Call has its own copy of part of DoCall... (and doesn't have the bug)

could it use DoCall? maybe. but it currently doesn't.

@SoniEx2
Copy link
Collaborator Author

SoniEx2 commented Sep 18, 2024

Could you add some details to the PR description saying what the issue is exactly and how this change fixes it?

done

Copy link
Member

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think I understand the issue better now. LGTM.

@sbc100
Copy link
Member

sbc100 commented Sep 18, 2024

Can you update the PR title with [wasm-interp] and include call_indirect in the title?

@SoniEx2 SoniEx2 changed the title Fix recursion memory corruption [wasm-interp] Fix memory corruption with call_indirect Sep 18, 2024
@SoniEx2 SoniEx2 changed the title [wasm-interp] Fix memory corruption with call_indirect [wasm-interp] Fix memory corruption with recursive call_indirect Sep 18, 2024
@SoniEx2
Copy link
Collaborator Author

SoniEx2 commented Sep 18, 2024

done(?)

@sbc100 sbc100 merged commit 874caa4 into WebAssembly:main Sep 18, 2024
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.

Invalid Memory Read in FreeList<wabt::interp::Object*>::IsUsed()

2 participants