-
-
Notifications
You must be signed in to change notification settings - Fork 793
RFC: Revised IPC Design #4680
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
base: master
Are you sure you want to change the base?
RFC: Revised IPC Design #4680
Conversation
jrvanwhy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suppose you are writing a Tock application that needs to store encryption keys in a secure location. You know that the IPC service for storing keys is named "keystore" and that the real implementation (the one you trust) has application ID 0123456789. Your app generates an encryption key, and wants to send it to that application.
How does it know it is sending the encryption key to app ID 0123456789 and not an imposter that also uses the "keystore" name? Is preventing that impersonation the IPC Name Registry capsule's responsibility?
| Upon discovery, it provides opaque process IDs which can be used to refer to | ||
| processes in other IPC mechanisms. | ||
|
|
||
| If validation of services or clients is desired, this capsule could perform |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "validation" mean here? Client authentication and/or authorization, or something else (like verifying the client process implements particular APIs)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It means authentication / authorization. I should clarify that in the text.
| **Commands**: | ||
| * Existence | ||
| * Register as service with allowed string name | ||
| * Discover service with allowed string name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are races between service registration and service discovery handled (i.e. what happens if a process tries to discover service X when the process that provides service X is still starting up and hasn't registered yet)? Is that an implementation detail that is outside the scope of this document?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should document that in this document. Since servers can choose to register themselves, it is possible to search the registry and not discover a server yet. That would result in "no match". The application should try again at a later time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"a later time" is kinda vague. Maybe we should have a "new service registered" upcall that prompts processes to re-try service discovery?
| Servers do not need to be aware of clients in advance, as they will receive a | ||
| process ID with each request. Clients do need to have previously discovered a | ||
| process ID for the server, possibly via the IPC Name Registry or possibly via a | ||
| separate mechanism (for example, they could be hard-coded). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So presumably something in the kernel has to store the list of discovered process IDs for each process, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. The kernel doesn't need to track discovered Process IDs. Instead, processes can hang on to them in process memory.
For clients, they can query the "Registry" to match some name to a Process ID, and then store that ID locally for use. For servers, they get a Process ID attached to incoming messages, and can store that if they want to use it later.
The kernel would have to hang on to discovered Process IDs if we wanted to do real client authentication. See the "Process Descriptor Tables" section:
| ### Process Descriptor Tables |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this means "clients are supposed to discover the process ID first before passing messages to it", not "the kernel needs to reject messages if the client did not discover the process ID first".
In the proposed initial implementation plan, there is no mechanism to ensure that the "keystore" service is not an imposter. However, application credentials is already is a thing in Tock. So you could ensure that only credentialed applications are running, and therefore that no imposter can exist. If we did authentication in the Registry, we could verify at registration-time that the "keystore" process is authentic and authorized to use that identifier. The IPC Name Registry would be responsible for this. How exactly it would do it is a little unclear. Probably something to do with TBF headers and credentials. Our thinking is that doing this authentication at registration-time should be possible (i.e., the design should allow it to be added in the future if someone wants to), but also that it isn't very important because platforms that really care would also use credentialed applications and verify them. |
I think you're asserting that all Tock deployments that care about preventing impersonation would have a form of secure boot (only allowing certain apps to run and denying apps the kernel has never heard of). At the time application IDs were designed, we had a use case for which that assertion was false (that is, we wanted to be able to run unknown applications and provide security to those applications). I'm not sure those uses cases exist for Tock anymore, and they're certainly difficult to support (in particular w.r.t. anti-starvation guarantees), but if we're going to rule them out we should do so thoughtfully rather than accidentally. I do agree that it could be retrofit, though. I think you could allow processes to self-service their security by providing one or both of the following commands:
(Because application IDs are variable-length, having both commands would be helpful). Retrofitting anti-impersonation would make IPC insecure-by-default, however. |
I forgot that you cannot have multiple running processes with the same application ID, so the first command could just be "get the process ID for a particular application ID". |
|
Let me try to step back and give a high-level view of what we're trying to achieve with IPC authentication, and the available options for doing so. Why does IPC need to use application IDs?First, why do we need authentication? The threat model's Isolation Provided to Processes section says:
So if a process tries to send data using the IPC system, the IPC capsule is not allowed to send that data just anywhere. The process must have a way to control where that data goes. So how does a process specify what that data can be shared? The What is an "Application"? section has the answer:
So when a process gives the IPC capsule a message to send, it should have control over the application ID of the process(es) that receives that message. Client authentication versus server authenticationConceptually, the threat model's statement applies to both client->server and server->client messages. But to make it more concrete, lets look at examples where each type of authentication matters. Client->server authentication exampleSuppose that application C is a cryptography server, which can perform encryption for other Tock apps on the system. App A has some data it wants to encrypt, that it does not want to share with the world. App A wants to send that data to application C, and know that it is not sending that data to any other application. Server->client authentication exampleSuppose application F implements a filesystem. Application A has already stored data in that filesystem, and has set the data's permissions such that no other app can read that data. App B contacts the filesystem and asks for app A's data. The filesystem application F needs to be able to determine that app B is not app A and deny that request. Application ID historyUnfortunately, with this PR we find ourselves reinventing parts of the app ID infrastructure. Lets look at the history of application ID design in Tock to inform the current design. First application ID proposalThe first design proposal for application IDs was on 2025-06-05 on the tock-dev list. This proposal introduced application identifiers as a variable-length byte string, which would be used for authentication and authorization by various Tock features (syscall filtering, ipc, secure boot, cryptography, storage, etc). It did not include any form of short ID (note that I'm not capitalizing short ID, because this is NOT the same meaning of short ID as the AppID TRD). Introduction of short IDsApplication ID proposal v2 was the first proposal to introduce short IDs. In v2, short IDs are subsystem-specific identifiers -- that is, the storage system and syscall filter would have distinct short ID spaces. The reason for this discrepancy was incompatible persistence between the systems:
I did not design short IDs for IPC in that proposal (this is clarified later in the thread). Application ID TRD: shared Short IDs.The application ID TRD mashed the two distinct short ID systems from proposal v2 into a single Short ID shared between subsystems. With this design:
Options for IPCIPC has several options for security identifying applications. Use the full application IDApplication IDs are unique among running processes, so the IPC system could exclusively use full application IDs (this is the design from proposal v2). This has a couple drawbacks. First, application IDs are large and variable-size, which makes it difficult to allocate memory to store them. The other drawback is that having less-persistent IDs is actually a benefit for IPC, as is already highlighted in this PR:
Use the Short IDThis solves the "large and variable-size" problem, but keeps the persistence drawback. It also introduces a new drawback: processes with a locally-unique Short ID would be unable to use IPC at all, though this is not really a new drawback because it was an intentional compromise in the application ID TRD (there's no succinct description here, it's a PR discussion so large I cannot get GitHub to load all of it). Use process IDs as a custom short ID.This uses process IDs as a short ID (note lowercase -- this is the v2 proposal's concept of short ID) for IPC. The IPC system (presumably the name registry capsule) would need to provide an API that allows processes to discover the relationship between process IDs and application IDs. Then the rest of the IPC system can use only process IDs. This is what I suggested a few hours ago. One minor drawback here: if you expose a "get process ID for application ID" command, then that command leaks information about whether a given application is running on the system. That's probably fine to leak, but there are a few ways to avoid it if needed (could be more specific about when a process ID is returned, or only offer a "get application ID for process ID" command). Something else?Maybe if the main use for IPC is networking then maybe it could use UDP/TCP/etc port numbers as short IDs. IDK, I'm just spitballing to make the point that we have other options here. Network WG notes responseNow that we've paged in the application ID discussion history, I'll go through and respond to the discussion from the 2025-12-08 network WG meeting.
The entity (individual/organization/etc) that signs a cryptographically-signed app is not necessarily the same organization that controls what apps run on a Tock system. Consider a Tock app store where developers can push signed application binaries. A developer should be able to set up their own PKI (Public Key Infrastructure), sign their own app (let's call it A), and know that no-one else can impersonate their app (assuming the Tock system is correctly implemented). That should be true even if that app is deployed alongside a malicious app (let's call it M). Application IDs would prevent app M from impersonating app A. However, app M could contain the same service name in its header as app A. So headers alone are not trustworthy enough.
IPC shouldn't implement its own cryptographic credential checking, but it does need to hook into the existing application ID infrastructure to satisfy use cases with mutually-distrustful apps. I don't think that needs to be mandatory for all IPC users, though -- we can make "verify this process has the expected application ID" a separate step that security-conscious applications must perform. I don't like that it is insecure by default, but it might be the best tradeoff for Tock overall.
You should be able to trust that a Short ID is valid, it's just that if it's locally unique you can't do much with it (e.g. a client that sends a message to a server cannot receive a response, because the server has no way to send the message back). A Short ID <-> application ID mapping capsule should already exist as an application ID mechanism (it doesn't, but it should). So if you're doing a multi-step lookup, IPC would only need to know the process ID <-> Short ID lookup step. But because not every process has a Short ID, I think it makes sense for IPC to have a single process ID <-> application ID registry and skip Short IDs entirely. That would make IPC simpler and more capable. |
Pull Request Overview
This pull request documents a revised IPC system for Tock. Rendered here
The document mostly speaks for itself, but the summary is that it proposes replacing the existing IPC design with a new ecosystem of IPC capsules. It proposes some initial designs for these capsules and documents the thinking behind them. This is a joint work of the Network working group informed by discussions over the last few months.
This is still a draft PR. You might notice several TBDs. Primarily, we've left a shared memory mechanism unspecified for now. We do have some designs for this, but we wanted to request community comments and work on implementations of the existing mechanisms before moving on to the more complicated shared memory work.
This is in the RFC folder for now, but we could move it later if there is an alternative location people prefer, maybe a TRD.
Testing Strategy
Documentation
TODO or Help Wanted
This pull request still needs: comments and thoughts from the community. Let us know if you spot any potential problems or if you have an application with tradeoffs we haven't considered.
Documentation Updated
/docs, or no updates are required.Formatting
make prepush.