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

Perform stronger typechecks of host-owned resources #7902

Merged
merged 4 commits into from
Feb 12, 2024

Conversation

alexcrichton
Copy link
Member

Right now the abstraction for host-owned resources in Wasmtime is quite simple, it's "just an index". This can be error prone because the host can suffer both from use-after-free and ABA-style problems. While there's not much that can be done about use-after-free the previous implementation would accidentally enable "AB" style problems where if a host-owned resource index was deallocated and then reallocated with another type the original handle would still work. While not a major bug this can be confusing and additionally violate's our guarantees as a component runtime to guests to ensure that resources always have valid reps going into components.

This commit adds a new layer of storage which keeps track of the ResourceType for all host-owned resources. This means that resources going into a host-owned table now record their type and coming out of a host-owned table a typecheck is always performed. Note that guests can continue to skip this logic as they already have per-type tables and so won't suffer the same issue.

This change is inspired by my taking a look at #7883. The crux of the issue was a typo where a resource was reused by accident which led to confusing behavior due to the reuse. This change instead makes it return an error more quickly and doesn't allow the component to see any invalid state.

Closes #7883

Right now the abstraction for host-owned resources in Wasmtime is quite
simple, it's "just an index". This can be error prone because the host
can suffer both from use-after-free and ABA-style problems. While
there's not much that can be done about use-after-free the previous
implementation would accidentally enable "AB" style problems where if a
host-owned resource index was deallocated and then reallocated with
another type the original handle would still work. While not a major bug
this can be confusing and additionally violate's our guarantees as a
component runtime to guests to ensure that resources always have valid
`rep`s going into components.

This commit adds a new layer of storage which keeps track of the
`ResourceType` for all host-owned resources. This means that resources
going into a host-owned table now record their type and coming out of a
host-owned table a typecheck is always performed. Note that guests can
continue to skip this logic as they already have per-type tables and so
won't suffer the same issue.

This change is inspired by my taking a look at bytecodealliance#7883. The crux of the
issue was a typo where a resource was reused by accident which led to
confusing behavior due to the reuse. This change instead makes it return
an error more quickly and doesn't allow the component to see any invalid
state.

Closes bytecodealliance#7883
@github-actions github-actions bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Feb 9, 2024
Copy link

github-actions bot commented Feb 9, 2024

Subscribe to Label Action

cc @peterhuene

This issue or pull request has been labeled: "wasmtime:api"

Thus the following users have been cc'd because of the following labels:

  • peterhuene: wasmtime:api

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

@fitzgen
Copy link
Member

fitzgen commented Feb 9, 2024

I haven't looked at the actual PR yet, just read your comment, but:

Is recording the type info enough to solve the ABA problem?

I don't think so: we could allocate a resource of type A, create an index handle to it, deallocate it, allocate a new resource that is also of type A in that place, and then use the old index handle to access the wrong resource.

I think adding a generation counter is the most straightforward way to definitely resolve the ABA problem here.

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

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

The code itself LGTM, and this is an improvement over the current status quo, so I don't mind landing this.

But I'd like to hear your thoughts on how we can integrate a generation to fully prevent ABA issues. I'm not 100% sure on the constraints we are working within here. For example, are we restricted to u32 indices and therefore we can't add a second u32 for generation? If so, perhaps we can repurpose 8 bits into a generation? Would 24 bits be enough for all active resources? Do we have a limit on how many active resources can exist at a time? Such a small generation likely wouldn't be enough to fully prevent ABA problems, but I think it would still be a further improvement.

crates/wasmtime/src/runtime/component/resources.rs Outdated Show resolved Hide resolved
crates/wasmtime/src/runtime/component/resources.rs Outdated Show resolved Hide resolved
@alexcrichton
Copy link
Member Author

A few days ago I was halfway through writing up a comment saying that I wasn't originally intending to solve the "full ABA problem" but was just targetting a smaller slice. Halfway through I asked myself "but why?" and scrapped that approach and took your suggestion of the generation counters and such.

I think this should be an even stronger guarantee now where host-owned resources should be nearly fully resistant to ABA issues (modulo overflow of counters)

Mind taking another look though @fitzgen since enough has changed?

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

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

Nice!

Comment on lines 338 to 340
fn index(&self) -> u32 {
self.0 as u32
}
Copy link
Member

Choose a reason for hiding this comment

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

Mind explicitly masking off the generation and doing u32::try_from(masked).unwrap()? I think that would make things a lot more clear and avoid hiding subtle issues with as casts as we change representations and stuff like that.

@alexcrichton alexcrichton added this pull request to the merge queue Feb 12, 2024
Merged via the queue into bytecodealliance:main with commit 4691f69 Feb 12, 2024
19 checks passed
@alexcrichton alexcrichton deleted the more-typechecks branch February 12, 2024 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasmtime:api Related to the API of the `wasmtime` crate itself
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Running method that takes resource as argument and returns resource multiple times returns same instance
2 participants