QubesOS / qubes-issues

The Qubes OS Project issue tracker
https://www.qubes-os.org/doc/issue-tracking/
541 stars 48 forks source link

Consider adding @*property:xxx qrexec policy keywords #5397

Open marmarek opened 5 years ago

marmarek commented 5 years ago

The problem you're addressing (if any)

Some qrexec policy entries in practice are bound to VM properties or global properties. Few examples:

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 property xxx 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 property xxx points back at the source VM". This could be a set of many VMs, so can't be used in target= argument. And a third one for global property: @globalproperty:xxx.

Example policies using them: qubes.UpdatesProxy:

whonix.NewStatus:

qubes.StartApp:

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 to ask - a call may be allowed depending on some other factor (the difference to ask 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 tag anon-vm. Example idea how it would work:

# main policy file:
# service        argument source       destination       action
whonix.NewStatus *        @tag:anon-vm @tag:anon-gateway !include:include/whonix-sdwdate.policy
# include/whonix-sdwdate.policy - generated based on netvm assignment:
whonix.NewStatus *        anon-whonix  sys-whonix         allow
# alternative version
whonix.NewStatus *        anon-whonix  @default           allow target=sys-whonix
# rules for other services and/or other VMs (not matching tags in main policy) are either ignored or rejected (with error message)

It isn't clear to me yet how @default should be handled in this case. Strictly speaking it doesn't directly name a VM with anon-gateway tag. But it names one in target= 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

hexagonrecursion commented 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.

hexagonrecursion commented 5 years ago

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.

woju commented 5 years ago

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.

marmarek commented 5 years ago

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.

iamahuman commented 3 years ago

Related: #3118 - UpdateVM for templates always defaults to sys-net