Support badged SMC caps to restrict SMC function IDs - #589
Conversation
4fb3591 to
c7191ec
Compare
c7191ec to
3ea486d
Compare
|
The current way of doing SMC is by setting an attribute The proposed way is using the recently added cap export mechanism and letting users call I agree that this is a better API, as it is more generic and avoids the Microkit wrapper function. However, the I would not disallow |
If I understand correctly your proposal is something like this? <system>
<protection_domain name="arm_smc" priority="1">
<program_image path="arm_smc.elf" />
<cspace>
<cap_initial type="smc" badge="0x84000000" slot="1"/>
</cspace>
</protection_domain>
</system>This would be interesting and a step toward adding a dynamic escape hatch to Microkit, |
This is useful as we are going to add SMC caps and they don't reference PD name/ID, so we need to distinguish them. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
Needed for new SMC badge changes. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
Useful for debugging. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
The "smc=true" attribute on a PD would provide an unbadged SMC capability that allows a component to invoke any function exposed by the ARM Secure Monitor. Use our extra capabilities / cap mappings feature to support this. This leaves the "smc=true" still enabled and useable. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
Use instead <cap_sc> feature instead for allow-listed function IDs. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
3ea486d to
bcb88d1
Compare
|
FYI, reason why I pinged you both is because this is somewhat closer to #362 than perhaps it should be, utilising the cspace element which was merged previously without wider discussion. I don't know if it's worth a proper RFC about whether we should make Microkit abstract away multiple function IDs as part of its API. |
One step further, type can also be something else, like "tcb", "sc", but then it needs a source attribute to find the correct one, like
Of course, (And it's perfectly fine to have aliases like
It's not just an escape hatch, it's a more generic way to copy caps. The advantage is that cap type specific code is contained to the cap lookup part and that the rest of the code can be generic. That means you can add new cap types without changing the XML format. The |
I'm in strong favour of #362, but it's not up to me, what do actual users of Microkit think?
I wouldn't do that, that doesn't seem within scope of Microkit. Don't forget all you can count on is the SMC Calling Convention, you can't count on it following e.g. PSCI. |
I'm specifically thinking about an equivalent to |
|
I understand wanting to generalize this and provide a very powerful tool for advanced seL4 developers, but I think it would be quite confusing for newer developers, especially if its the only option. <system>
<protection_domain name="arm_smc" priority="1">
<program_image path="arm_smc.elf" />
<cspace>
<cap_initial type="smc" badge="0x84000000" slot="1"/>
</cspace>
</protection_domain>
</system>Presumably there will be some updates to the documentation, but a user needs to understand that they need a cap of type SMC for each smc call they want to allow and that the func_id is represented by the badge (which isn't actually mentioned in the seL4 User manual). Then they need to understand what value to use for slot. While the microkit API is somewhat inconsistent about what it provides, it has provided benefit by abstracting some of the more confusing parts of the microkernel. Do you think we could support both approaches? The commented proposal provides the escape hatch which essentially lets you do whatever you need with initial_caps, but is likely only going to be used by advanced developers. Then Microkit could still provide abstractions on commonly used functionality, such as SMC. As a user, I would hope for a more simple specification such as this: <system>
<protection_domain name="arm_smc" priority="1">
<program_image path="arm_smc.elf" />
<allowed_smc_calls>
<smc_call func_id="0x84000000"/>
<smc_call func_id="0x84000020"/>
<smc_call func_id="0x8400003A"/>
</allowed_smc_calls>
</protection_domain>
</system>You could also have a more obvious way to specify things like allowing all calls, without needing to understand how that is actually done: <system>
<protection_domain name="arm_smc" priority="1">
<program_image path="arm_smc.elf" />
<allowed_smc_calls allow_all="true" />
</protection_domain>
</system> |
|
OK, thanks for the feedback. I think your proposal makes sense. I'll propose that this generates the metadata used for a Just to confirm, the other proposal was this, which is explicit about function IDs: <protection_domain name="arm_smc">
<!-- elided -->
<cspace>
<!-- An (ARM) SMC capability that permits SMC calls to 0x84000000 (PSCI_VERSION) -->
<cap_smc slot="1" function_id="0x84000000" />
</cspace>
</protection_domain>Not cap_initial which does then use badge, which I agree is quite confusing. |
|
Something to note that if we do provide an |
Yes, SMC is currently not properly documented in the manual, other than the SMC syscall with too little information, see seL4/seL4#1422.
The old, simple way can be retained easily enough.
Implementing this would be quite tricky in Microkit though: It would need to pass the func_id<->cap mapping to user space via e.g. bootinfo and use that to check if the call is allowed and find the right cap. Maybe this could be done via setvar or something, but that's not exactly user friendly either at this point. I think it would be much simpler to expand the existing way by adding function_id support instead of just "true", like The complicated cspace way can be used for when that's not good enough. But adding more and more very use case specific, tricky code to Microkit is exactly the kind of thing that I'm trying to push back against. Simple wrappers for simple things is somewhat fine, but now you're proposing to add complicated wrappers for complicated things, without supporting all use cases. That's the road to bloatware, subtle bugs and maintenance hell in 10 year time. Maybe Microkit is already really close to mapping a read-only page per process with PD-specific metadata, then adding this wouldn't be too bad I suppose... |
The most important part for me personally is that I need to support around 20 to 30 function IDs for each VM on the ZCU102.
Yes, I see that argument.
|
Yeah, we have a bunch of separate setvars already for things like this. I was considering something here: #422. But we can do this with setvars. I am leaning towards Microkit providing this feature, I think. |

Please review commit by commit.
Summary
Add the ability to provide caps for performing SMC invocations which are 'badged',
only allowing certain function invocations. This allows for exposing certain
functions to specific PDs without granting unilateral rights to do anything, i.e.
following a principle of least privilege. This mechanism was explicitly
discussed in RFC 9: New Capability for seL4 SMC Forwarding.
Motivation
The existing Microkit SDF syntax allows for protection domains to be given
SMC capabilities. However, this is an unbadged SMC capability, which allows
access to all SMC functions, i.e. a lot of power over the system.
PDs are then allowed to invoke the
microkit_arm_smc_call(...)function withthe
seL4_ARM_SMCContext *argsandseL4_ARM_SMCContext *respstructs. Thisperforms an invocation on
seL4_ARM_SMC_Call(ARM_SMC_CAP, args, resp).Even if all a PD wants to do is call the
PSCI_VERSION(function0x84000000),they have all the rights to reboot the system, on/offline CPUs, etc.
seL4 provides a simple mechanism to restrict
SMCcapabilities; by providinga badged SMC capability, only function IDs that match the badge are allowed.
For allowing multiple SMC function IDs, one needs multiple badged copies of the
SMC capability.
Proposal
Using the existing
<cspace>cap-mapping feature, we add a new node type to theSDF file, the
cap_smc.User code then looks like this:
Specifying a
function_id="0"is an escape hatch for development, or when youdon't care about security, which provides an SMC capability that is unbadged
and so allows any SMC function call.
As part of this proposal, we remove the
microkit_arm_smc_call()andsmc="true"attribute from the Microkit API. This is because the next release, Microkit 3.0.0,
is planned to be a breaking change. This
is the last commit of this PR and could be dropped instead, leaving in a deprecated
API.
Rationale and alternatives
We briefly discuss the choices in the design space made in this proposal.
First, we continue allowing unbadged SMC capabilities to be provided, i.e.
function_id="0". We could instead disallow this entirely and have part of thisinclude policy to never allow this to be the case. We reject this as it can be
useful for development to allow any function ID.
The second point is the decision to expose the seL4 API and capabilities directly,
for calling
seL4_ARM_SMC_Call. This makes it the responsibility of the userto manage calling multiple SMC call function IDs themselves. This is instead how
CAmkES works: see
camkes_get_smc_capand
vm_smc_handlerof CAmkES-VM.We could do this in Microkit, too. This requires providing information to the PD
about which SMC capabilities are where, and then providing a function to distinguish
based on function ID. We choose not to do this, generally we only pass information
to PDs when the user requests, e.g.
setvar, and it is up to the user to choosehow to encode data about the system in their program; Microkit just provides the
mechanisms.
Original README
Original README
Note: this contains a breaking change by removing the SMC attribute.
This should be fine, as the 3.0.0 release is planned to be breaking anyway.
This change could be reverted; it is left as a separate commit to make that easy.
The other design choice here was that we do not permit "function_id=0", or some other way to make
badge = 0 <=> unbadged smc capwhich has no allowlisting, instead allowing everything. This is always (in my opinion) a bad design.