qubes.vm.dispvm – Disposable VM¶
A disposable qube implementation
- class qubes.vm.dispvm.DispVM(app, xml, *args, **kwargs)[source]¶
Bases:
QubesVMDisposable qube.
Disposable behavior¶
A disposable template is a qube which has the
AppVMclass and thetemplate_for_dispvmsproperty enabled, being aDVMTemplateMixin.A disposable is a qube with the
DispVMclass and is based on a disposable template. Every disposable type has all of its volumes configured to disablesave_on_stop, therefore no changes are saved on shutdown. Unnamed disposables enables the propertyauto_cleanupby default, thus automatically removes the qube upon shutdown.Named disposables are useful for service qubes, as referencing static names is easier when the qube name is mentioned on Qrexec policies (
qubes.UpdatesProxytarget) or as a property of another qube, such as a disposable net qube which is referenced by downstream clients in thenetvmproperty.Unnamed disposables have their names in the format
disp1234, where1234is derived from thedispidproperty, a random integer ranging from 0 to 9999 with a fail-safe mechanism to avoid reusing the same value in a short period.The system and every qube can have the
default_dispvmproperty. If the qube property is set to the default value, it will use the system’s property. This property can only have disposable template as value or an empty value. Qubes which have this property set are allowed to request the creation of a disposable from this property. An exception to the rule is the property of disposables, which always default to their disposables templates to avoid data leaks such as using unintended network paths.There are some Qrexec services that which allows execution to disposables created from the
default_dispvmproperty when the destination qube of the Qrexec field uses the @dispvm tag, most commonly used to open files and URLs, (qubes.OpenInVMandqubes.OpenURL, respectively).Preload queue¶
Preloaded disposables are started in the background and kept hidden from the user when not in use. They are interrupted (paused or suspended, as appropriate) and resumed (transparently) when a disposable qube is requested by the user.
Goals:
Fast: Usage must be always instantaneous from user perspective when requesting the use of disposables. Pause/suspend must be skipped if qube is requested before the interrupt can be performed.
Easy-to-use: Preloading requires a single qube feature (preload-dispvm-max), and its use must be transparent, indistinguishable from working with normal (non-preloaded) unnamed disposable qubes.
Reliable:
Avoid race conditions: Marking a qube as preloaded or marking the preloaded as used must be synchronous.
Recovery from failed or incomplete preload: The system must attempt to preload qubes even if previous preloading attempts failed due to errors, qubesd restart or lack of available memory, regardless of whether preloaded disposable qubes have been requested on this instance. If current qube list is invalid, it must be cleaned up before being used.
Avoid copy of invalid attributes: Qube operation (in particular cloning, renaming or creating a standalone based on a template) must not result in properties that are invalid on the target.
Full start: Preloaded disposable must only be interrupted (paused/suspended) or used after all basic services in it have been started. Failure to complete this step must remove the qube from the preload list.
Prevents accidental tampering:
Preloaded qubes have the internal feature set when they are created. This feature hides the qube from GUI tools and discourages user tampering. It is unset when the qube is marked as used. Remember to validate if all GUI applications correctly react to setting and removing the internal feature (optionally, the is_preload property can be helpful). GUI applications may react to domain-add before the internal feature is set and the qube entry may briefly appear on some GUI applications, that is a bug because features cannot be set before that event.
Preloaded qubes must be marked as used after being unpaused/resumed, even if it was not requested. The goal of pause/suspend in case of preloaded disposables is mostly detecting whether a qube was used or not, not managing resource consumption; thus, even with abundant system resources, they should not be unpaused/resumed without being requested.
Features and properties relationship on stages:
Properties indicate the runtime stage of preloaded qubes and intentionally lost on qubesd restart.
Features indicate that a preloaded qube has reached certain stage at any qubesd cycle.
Comparing the value of certain features and properties can indicate that there were qubes being preloaded or requested but qubesd restarted between the stages, interrupting the process. The only stage that should conserve the preloaded qubes is a qubes that has completed preloading but has not been requested.
Stages:
Preload: The qube is created and marked as preloaded. Qube is not visible in GUI applications.
Startup: Begins qube startup, start basic services in it and attempt to interrupt (suspend/pause).
Request: The qube is removed from the preload list. If startup has not yet reached interrupt, the latter is skipped.
Used: The qube is marked as used and may be unpaused/resumed (if applicable). Only in this phase, GUI applications treat the qube as any other unnamed disposable and the qube object is returned to the caller if requested.
- classmethod can_gen_disposable(appvm, preload=False) bool[source]¶
Check if app qube can be used to generate a disposable.
- Return type:
- async classmethod from_appvm(appvm, preload=False, **kwargs) DispVM | None[source]¶
Use a preloaded disposable if available, else fallback to creating a new disposable instance from given app qube.
- Parameters:
appvm (qubes.vm.appvm.AppVM) – template from which the qube should be created
preload (bool) – Whether to preload a disposable
- Returns:
new disposable qube
- Return type:
kwargs are passed to the newly created disposable.
>>> import qubes.vm.dispvm.DispVM >>> dispvm = qubes.vm.dispvm.DispVM.from_appvm(appvm).start() >>> dispvm.run_service('qubes.VMShell', input='firefox') >>> dispvm.cleanup()
This method modifies
qubes.xmlfile.
- async classmethod gen_disposable(appvm, preload=False, **kwargs) DispVM[source]¶
Create a new disposable instance from a given app qube. If preload is truthy, the qube is started.
- Parameters:
appvm (qubes.vm.appvm.AppVM) – template from which the qube should be created
preload (bool) – Whether to preload a disposable
- Return type:
- async cleanup(force: bool = False) None[source]¶
Clean up after the disposable.
This stops the disposable qube and removes it from the store. This method modifies
qubes.xmlfile.- Parameters:
force (bool) – Auto clean up if property is enabled and domain is not running, should be used in special circumstances only as the sole purpose of this option is because using it may not be reliable.
- is_preload_outdated() dict[source]¶
Show properties that differ on disposable compared to its template.
- Return type:
- on_domain_paused(event, **kwargs)[source]¶
On pause, log if it is a preloaded disposable.
- Parameters:
event (str) – Event which was fired.
- async on_domain_pre_paused(event, **kwargs) None[source]¶
Before the qube is paused, if the qube is a preloaded disposable that has memory balancing enabled, attempt to set it’s memory to its preferred memory configuration, which is just enough to get the qube working at that time.
This helps preloaded disposables to be paused with just enough memory.
- Parameters:
event (str) – Event which was fired.
- on_domain_remove_from_disk(_event, **_kwargs) None[source]¶
On volume removal, remove preloaded disposable from
preload-dispvmfeature in disposable template. If the feature is still here, it means thedomain-shutdowncleanup was bypassed, possibly by improper shutdown, which can happen when a disposable is running, qubesd stops and system reboots.
- async on_domain_started_dispvm(event, **kwargs)[source]¶
When starting a qube, await for basic services to be started on preloaded disposables and interrupts the domain if the qube has not been requested yet.
- Parameters:
event (str) – Event which was fired.
- async on_domain_unpaused(event, **kwargs)[source]¶
When qube is unpaused, mark preloaded disposables as used.
- Parameters:
event (str) – Event which was fired.
- on_property_pre_reset_template(event, name, oldvalue=None) None[source]¶
Forbid deleting template of qube.
- Parameters:
event (str) – Event which was fired.
name (str) – Property name.
oldvalue (qubes.vm.mix.dvmtemplate.DVMTemplateMixin) – Old value of the property.
- on_property_pre_set_template(event, name, newvalue, oldvalue=None)[source]¶
Forbid changing template of running qube.
- Parameters:
event (str) – Event which was fired.
name (str) – Property name.
newvalue (qubes.vm.mix.dvmtemplate.DVMTemplateMixin) – New value of the property.
oldvalue (qubes.vm.mix.dvmtemplate.DVMTemplateMixin) – Old value of the property.
- on_property_set_template(event, name, newvalue, oldvalue=None) None[source]¶
Adjust root (and possibly other snap_on_start=True) volume on template change.
- Parameters:
event (str) – Event which was fired.
name (str) – Property name.
newvalue (qubes.vm.mix.dvmtemplate.DVMTemplateMixin) – New value of the property.
oldvalue (qubes.vm.mix.dvmtemplate.DVMTemplateMixin) – Old value of the property.
- async use_preload() None[source]¶
Marks preloaded disposable as used (tainted), delete the
internalwhen appropriate, making GUI applications show the qube as any other disposable. Start the preload cycle to fill gaps.
- async wait_operational_preload(service: str, timeout: int | float) None[source]¶
Await for preloaded disposable to become fully operational.
- auto_cleanup¶
automatically remove this qube upon shutdown
- default_dispvm¶
Default disposable template to be used for spawning disposable qubes for service calls.
- dispid¶
Internal, persistent identifier of particular disposable.
- include_in_backups¶
If this domain is to be included in default backup.
- property preload_requested: bool¶
Check if preloaded disposable was requested and still is preloaded (not used yet).
This property exists because the qube may still be a preloaded disposable and not be on the
preload-dispvmfeature of the disposable template. This offload is done to avoid race conditions:Decreasing
preload-dispvm-maxfeature will not remove the qube;Another request to this function will not return the same qube.
- Return type:
- template¶
AppVM, on which this disposable is based.
- qubes.vm.dispvm.get_preload_max(qube) int | None[source]¶
Get the
preload-dispvm-maxfeature as an integer.- Parameters:
qube (qubes.vm.qubes.QubesVM) – Qube to query the feature from.
- Return type:
int | None
- qubes.vm.dispvm.get_preload_templates(app) list[source]¶
Get all disposable templates that have the
preload-dispvm-maxfeature greater than 0, either directly or indirectly by being the global default_dispvm and dom0 has the feature enabled.- Parameters:
app (qubes.app.Qubes) – Qubes application.
- Return type: