-
Notifications
You must be signed in to change notification settings - Fork 48
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
Add a compartment initalisation framework #275
Comments
I agree that something in this space would be nice. There are a lot of problems that are similar to the ones with shared-library global initialisers. To start with, this is what we have now:
If we have a generic mechanism, a few problems arise immediately:
I don't think we can solve this in the general case (happy to be wrong!), but I would welcome suggestions for how we can at least provide some general infrastructure for the common cases. Currently, the simplest pattern is:
The thread that runs the cleanup needs one trusted stack frame to handle the startup bits before it enters its main entry point. It can then define the initialisation order and what to do if any fail. If you want to handle infinite looping, a second thread can do a timed wait on the barrier and handle errors if the timeout is triggered. This requires a lot of bespoke code, so is not ideal. |
Musing a bit, forgive some half-baked thoughts. I think it could be relatively straightforward to offer severely limited constructors, which...
I think the limitations here probably mean we don't have to worry about dependencies among such constructors. That said, despite the limitations, these seem good enough to...
Does that seem like enough utility to merit the throw-weight of the requisite support code in the loader? |
I think it is useful. The loader code should mostly be preparing an array of cross-compartment callbacks. The right place for this to run is probably the fake thread that the scheduler has, which also has no trusted stack and is the one the loader runs on. |
It sounds like there's a contradiction between the limitation on not being able to make cross-compartment calls, and the point about walking though intra-compartment collections ? In the config broker initialisation each parser is making a cross-compartment call into the broker to register a call back - would that be supported here ? |
I think that's the hardest thing to support. I don't really want to support cross-compartment calls because that makes it hard to reason about the initial state. If each initialiser is self contained, then you guarantee non-interference between two that run in compartments with access to disjoint sets of devices / pre-shared objects. If they can do cross-compartment calls, that's much harder. Initialising global constructors and doing early device init are the two main use cases for me. The latter, in particular, where we could give a compartment with no entry points except the init code a richer set of permissions, would enable some useful things. For example, for the revoker, the revoker-init compartment could have access to the full device range and configure the start and end region for scanning, then the allocator could have access to only the range that lets it start revocation and read the epoch counter. |
Oh, I'd missed that point and was thinking about something more akin to linker sets to get collections of things from across a compartment's linkage to iterate at startup. It seems plausible that we could do cross-compartment linker sets, too, making the broker's registration of callbacks more declarative, but I'd want to expose such functionality to auditing as well. Will ponder further. |
I think we'd want each compartment to expose zero or one initialisation entry points. For the config broker, I'm not sure what the right way of doing that registration is. It feels like doing it at run time, rather than link time, is probably the wrong approach, but I'm willing to be convinced otherwise. |
@nwf It could be that my design is an outlier - I was trying to keep it so that the broker was a compartment that could be included unchanged and just extended by adding other compartments around it (it's kind of in our DNA as a company to turn everything into a configuration problem rather that dev). |
Sold. 1
An admirable goal indeed! I think we can keep it, declaratively and without the use of cross-compartment calls, atop the proposed limited framework above, with some restructuring and (quite a bit of) engineering. I think the steps are...
Then the broker's
(Similarly, the allocator compartment could have a nearly identical loop for assigning owner IDs to quotas.) Edit 2025/01/24: David reminds me that my initial design, of having type-segregated sealed object sets, is required, not just a nice to have. I've updated the above. I think, given the possibility of the above as an extension to the design sketched above, that we ponder exploring that more fully first and then pick this up in a 2nd round? Footnotes
|
Sometimes there is code in a compartment that you want to run once at startup - for example in the configuration broker example each parser needs to register a callback with the broker (to avoid hard coding the list of parers into to the broker).
Running a thread in each compartment to do this is wasteful and since threads aren't expected to exit means they are left hanging around. Doing it from a single thread means exposing a compartment-call that's not otherwise need.
Following the pattern of compartment_error_handler() with something like compartment_init() would work ?
The text was updated successfully, but these errors were encountered: