Open marmarek opened 5 years ago
More complex rules, more dependencies -> harder to reason about data flows by just looking at qrexec policy
My 2 cents: IMHO it is common to want to reason about the entire effective policy (i.e. including any automatically added/removed tags, any automatically modified files and any decisions made by an external tool) at a future point in time (e.g. "if foo-vm becomes compromised I don't want it to be able to do bar"). Anything that can change (especially automatically) between now and that point in time makes that task rather hard. Currently there are several components of QubesOS that work around the limitations of the policy language by either automatically adding tags or automatically modifying policy files. My takeaway from this is that not acknowledging an effective dependency of the effective policy in the policy language only moves it somewhere else. I would argue that if we could replace at least some of the workarounds currently in place with concise declarative syntax that it would make the effective policy more transparent.
Example:
qubes.VMShell
currently: automatically modified by qubesctl to add and remove rules of the form disp-mgmt-foo foo allow
new: @anyvm @srcproperty:vmtomanage allow
where vmtomanage is new pref automatically assigned by qubesctl
The effective policy is exactly the same but is somewhat more transparent.
First impression is: I don't like it. This seems complicated. We deliberately introduced tags, because we didn't want to use properties in policy.
Properties are complicated. A property might have default value set by imperative code (and this is particularly the case of netvm
), so this would be a departure from declarative nature of the policy. I think this is wrong in principle.
But the "ask" resolution is also imperative and not statically defined, so I'd suggest adding a parameter, say ask program=/path/to/executable
with well-defined interface, like "0=allow, 1=deny, anything else=also deny, because tool crashed". The default program asks the user.
It is already possible to patch the program to selectively answer about particular calls and this is not reflected in the policy either.
This would be good for policy analysis: "ask" in practice means "maybe yes", so this solution won't introduce anything problematic. And will be easy to implement.
Indeed this can be ask
action used directly, not a separate action. Makes sense. We'll need to change ask
prompt implementation anyway, because of guivm.
Related: #3118 - UpdateVM for templates always defaults to sys-net
The problem you're addressing (if any)
Some qrexec policy entries in practice are bound to VM properties or global properties. Few examples:
netvm
property): https://github.com/QubesOS/qubes-core-admin-addon-whonix/blob/master/qubes-rpc-policy/whonix.NewStatus.policyupdatevm
property, or non-existent per-vmupdatevm
property)Some of them can be handled by (dynamically?) assigning tags and using them in the static policy (Whonix case), but some can't (
target=
argument can't use tags).Describe the solution you'd like Consider adding
@srcproperty:xxx
policy keyword meaning "VM pointed by the propertyxxx
of the source VM". This always names at most one VM (or none if the property is empty), so can be used in both destination. There might be also a need for dual keyword@destproperty:xxx
meaning "VM of which propertyxxx
points back at the source VM". This could be a set of many VMs, so can't be used intarget=
argument. And a third one for global property:@globalproperty:xxx
.Example policies using them:
qubes.UpdatesProxy
:@type:TemplateVM @default allow,target=sys-net
(hardcodedsys-net
)@type:TemplateVM @default allow,target=@srcproperty:updatevm
(or@globalproperty:updatevm
whonix.NewStatus
:@tag:anon-vm @tag:anon-gateway allow
(allows calls to any whonix gateway)@tag:anon-vm @srcproperty:netvm allow
(allows calls to its netvm only)@tag:anon-vm @default allow,target=@srcproperty:netvm
(same as the above, but whonix ws does not need to know its netvm name)qubes.StartApp
:sys-gui @tag:guivm-sys-gui allow
@tag:guivm @dstproperty:guivm allow
(allow calls from VM withguivm
tag to VM that has it as its guivm)Where is the value to a user, and who might that user be? Pros:
Cons:
Alternative 1 Having some tags and/or policy rules automatically generated. With new multi-file policy format it should be doable - have selected files generated. One can always (with this proposal and without it) override decisions there by placing policy file with a lower number (parsed earlier). I think this is the current idea I've discussed before with @woju.
Alternative 2 Alternative option is adding another action (besides
allow
,ask
,deny
) delegating the decision to an external tool. That tool could perform the logic described above. From policy analysis point of view, it's similar toask
- a call may be allowed depending on some other factor (the difference toask
is the "other factor" is an external tool instead of the user). On one hand, it will keep the base policy parser simpler (the added complexity will be elsewhere, reachable only for selected calls). On the other hand, effective policy will be spread across multiple places (main policy, and the logic of that tool).Alternative 3 There is also intermediate option: have generated policy files, but make them affect only selected calls. Some thing like constrained include, that will filter/verify that rules apply only to specific calls. This may be about qrexec service name (already exists for legacy policy handling), but also source/destination selections. I'm not sure how such syntax would looks like, maybe an
include
action? This would allow most of the above, but with slightly better reasoning about the policy - one can verify that regardless of what the policy generator does, it surely for example can affect only calls from VMs with taganon-vm
. Example idea how it would work:It isn't clear to me yet how
@default
should be handled in this case. Strictly speaking it doesn't directly name a VM withanon-gateway
tag. But it names one intarget=
argument. If that would count, then it's violation of the current behavior (target=
being independent on destination column in the policy). But maybe a desirable one? If going this way, we might want to change this for non-included files too:allow,target=...
would allow the call only when the target is also allowed with another rule.Additional context This is mostly request for comments stage, exploring ideas. Not a definite development plan, yet.
Relevant documentation you've consulted https://www.qubes-os.org/doc/qrexec/ https://github.com/QubesOS/qubes-core-qrexec/blob/master/Documentation/multifile-policy.markdown
Related, non-duplicate issues https://github.com/QubesOS/qubes-issues/issues/5253 https://github.com/QubesOS/qubes-issues/issues/5187
cc @woju @jpouellet @HW42 @adrelanos