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

Restrict promise redirect #5124

Merged
merged 7 commits into from
Apr 25, 2022
Merged

Conversation

mhofman
Copy link
Member

@mhofman mhofman commented Apr 16, 2022

closes: #5023
refs: #4318

Best reviewed commit-by-commit

Description

This changes the kernel and comms promise handling logic to enforce 2 basically existing invariants:

  • A promise cannot be resolved to another promise. That would be a redirect, which isn't currently implemented
  • A non-pipelining decider vat should not be able to use an imported promise as result of a send

The goal is to limit the situations where messages sent to a promise need to change queues. The only case should now be when a message is sent to a result promise decided by a pipelining vat. Such a message can change either

  • from the promise queue to the vat's queue because the send for which the promise is the result has been queued to the vat, or
  • from the vat's queue to either the resolved target's vat, or back to the promise queue (if the send for which the promise is the result was just forwarded back).

Security Considerations

There shouldn't be any. All now explicitly disallowed behaviors were not currently happening in legitimate flows.

Documentation Considerations

TODO

Testing Considerations

Both positive and negative tests added for promise resolve as well as re-using of imported result promises.

@mhofman mhofman requested a review from warner April 16, 2022 03:33
@mhofman
Copy link
Member Author

mhofman commented Apr 16, 2022

@warner I have a little bit of doc to write, and one test to add that I just thought about, but I would already appreciate a preliminary review.

@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch 2 times, most recently from bee5415 to 9f10b53 Compare April 16, 2022 07:16
@mhofman mhofman marked this pull request as ready for review April 19, 2022 00:39
@mhofman
Copy link
Member Author

mhofman commented Apr 19, 2022

This is actually ready for review. I still need to see if any doc needs updating. I also looked into a more thorough pipeline test over the weekend, but realized that because of the current kernel runqueue, it wouldn't test anything useful, but I'll it for the next step.

@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch 2 times, most recently from d9b939c to 9edd684 Compare April 19, 2022 21:27
// as the result of a send call, it's in effect doing a redirect, which
// is currently only supported for pipelining vats.
result = mapVatSlotToKernelSlot(resultSlot, {
requireVatAllocated: !enablePipelining,
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 also allows the case where the vat is re-using a vpid that it previously exported, and I'm not sure you want that (but I might be wrong, I need to think about it more carefully). The allocatedByVat flag is not a direct indicator of the history of the promise, although possible cases are probably limited (and limited even further by this new assertion).

We might be able to use allocatedByVat to achieve the goal, but maybe the new option should be more like "this must be a brand new promise"? (Note that I just filed #5189 and in that case we might see the vpid in args before we see it as result, which could cause a false negative for a "must be new" check.. we might salvage that by processing result before we translate args).

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, thinking about it more, I think the check should be requireNew.

When one of us fixes #5189, the new tests (where userspace includes the result promise in the args of the same message) will fail this requireNew check, and we'll fix it (both here and in liveslots) by translating the result before translating the arguments.

const args = [];
const p = E(target).foo(args);
args.push(p);

Copy link
Member Author

Choose a reason for hiding this comment

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

Happy to revert to the initial "fresh" / requireNew approach. After realizing that pipelining vats needed the flexibility, I no longer saw a reason to prevent regular vats from pre-allocating a promise (it is currently marked as supported in the docs).

The allocatedByVat flag is not a direct indicator of the history of the promise

Just to make sure I understand this flag correctly, is there any way for allocatedByVat to be true if the promise was in fact imported and not exported? That's the looser restriction I had settled on after moving away from "fresh", which seemed to satisfy all documented usages (and tests).

Copy link
Member

Choose a reason for hiding this comment

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

You're correct, if kernel is the one introducing the promise into the vat, then allocatedByVat will always be false. It's just that I avoid using "import" and "export" for Promises, since that's not nearly as meaningful as which side is the decider. For objects, import-vs-export is a big deal, but not so much for Promises.

// as the result of a send call, it's in effect doing a redirect, which
// is currently only supported for pipelining vats.
result = mapVatSlotToKernelSlot(resultSlot, {
requireVatAllocated: !enablePipelining,
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, thinking about it more, I think the check should be requireNew.

When one of us fixes #5189, the new tests (where userspace includes the result promise in the args of the same message) will fail this requireNew check, and we'll fix it (both here and in liveslots) by translating the result before translating the arguments.

const args = [];
const p = E(target).foo(args);
args.push(p);

@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch from 9edd684 to 3d5f7ce Compare April 22, 2022 23:12
@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch from 3d5f7ce to 334f4a5 Compare April 23, 2022 00:03
@mhofman mhofman requested a review from warner April 23, 2022 00:03
@mhofman
Copy link
Member Author

mhofman commented Apr 23, 2022

@warner PTAL

I changed requireVatAllocated into requireNew and updated tests accordingly, as well as added a test which represents what #5189 would end up as in syscalls: 50ec896

I will extract 5c98f5b and 4bd30d9, as it's the trigger for the GC weirdness I experience described in #5202, into a separate PR

@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch from 334f4a5 to 50ec896 Compare April 23, 2022 00:12
@mhofman mhofman mentioned this pull request Apr 23, 2022
Copy link
Member

@warner warner left a comment

Choose a reason for hiding this comment

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

One comment nit, rest looks good, land after fixing.

@mhofman
Copy link
Member Author

mhofman commented Apr 25, 2022

Will squash now, then rebase once #5204 has landed.

Edit: eeb79ec..e5f505b

@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch from eeb79ec to e5f505b Compare April 25, 2022 18:08
mhofman added 7 commits April 25, 2022 18:27
Do not create translators twice
A resolution to a promise is in fact a redirect to that promise.
It should not result to a fulfillment.
Add tests for both kernel and comms that this causes a failure.
Update rejection tests to use a non-wrapped promise as rejection
using a promise reason is technically valid (although strange).
Non-pipelining vats are not allowed to use an imported promise,
which they are the decider of, as the result of send.
@mhofman mhofman added the automerge:rebase Automatically rebase updates, then merge label Apr 25, 2022
@Tartuffo Tartuffo force-pushed the mhofman/5023-restrict-promise-redirect branch from e5f505b to 0c7445e Compare April 25, 2022 18:28
@mhofman mhofman force-pushed the mhofman/5023-restrict-promise-redirect branch from 0c7445e to 1b7cead Compare April 25, 2022 18:30
@mergify mergify bot merged commit 388abd2 into master Apr 25, 2022
@mergify mergify bot deleted the mhofman/5023-restrict-promise-redirect branch April 25, 2022 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Constraint decider changes to simplify promise enqueuing logic
2 participants