Skip to content

Commit 47f1125

Browse files
committed
Adapt disposable documentation up to 4.3
- Cleared misunderstandings of disposable templates, this word was sometimes used interchangeably with disposables; - Deduplicate content as much as possible; - Reference other pages or previous sections; - Assume the user has read the previous sections up until the current section they are reading; - All this deduplication enables easier reading, less clutter, but each section doesn't stand by itself, each page does. Some things were reinforced on multiple sections, but limited to when extremely necessary to learn by reinforcement; - Structure the files to their distinct use cases: - how-to-use-disposables is just the basics to learn what are disposables and how to use them, using GUI and CLI alternatives; - disposable-customization has everything specific to different disposables templates as well their creation and configuration; - disposable-implementation assumes the user understand the previous pages and contains a more technical description of disposables and preloaded disposables as well as their implementation; - Prepared usage for a GUIVM setup, avoiding mentions to dom0; - Usage modes has been organized in GUI first and CLI second, grouped by origin such as GUIVM and app qube; - Usage page restricts itself to "default-dvm", it's name is not variable like the Whonix disposable template variant and it is the most used disposable template, thus we avoid variables replacement that the user should think of the value to a definitive value to use when learning. Customization page could not benefit much from this though, as it is intended to create alternative disposable templates; - Usage page links to Tails documentation of why using it on a VM is not amensiac, so it can be referenced for users that ask to have Tails in a VM for anti-forensics purposes; - Updated the images to R4.3, nobody deserves to see the Qubes version of the Xfce application menu anymore when the new app menu rocks. The images also had to be updated because it was fullscreen screenshot on a large resolution, making it very difficult to read unless opening the image in a new tab and zooming in; - Implementation page shows preloaded disposables alternatives that were once used or considered as a comparative for future studies, to answer why a different option is not being used and what requirements a replacement must meet; - Content from previous releases have been deleted; - Updates to Qrexec policy v4; - Use rST roles; - Change non-ASCII quotes and em-dashes to ASCII; - Standardized text writing style, many people have contributed to these pages over the years, there is a lot of different writings styles which make the text difficult to map. I rewrote a lot of the paragraphs to my liking and understanding of the different stages that a user may go through when using disposables, and even on paragraphs that I didn't completely write, it was modified to follow the same standard with the rest of the pages. The usage must be very simple with just the basics, we don't want to scare the user's off of using disposables, we want to convince them. The customization is a bit more advanced, it assumes a lot more knowledge from the user to make decisions by themselves such as customizing applications and qube settings, which can affect system security. The implementation details do not require reading the code, it just exist to explain what is being used and why it was chosen. Fixes: QubesOS/qubes-issues#10282 For: QubesOS/qubes-issues#1512
1 parent 1d4bfbc commit 47f1125

14 files changed

+391
-260
lines changed
-395 KB
Binary file not shown.
-368 KB
Binary file not shown.
-101 KB
Binary file not shown.
101 KB
Loading
84.8 KB
Loading
136 KB
Loading
59.9 KB
Loading
518 KB
Loading
229 KB
Loading

developer/services/disposablevm-implementation.rst

Lines changed: 97 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,138 @@
22
Disposable implementation
33
=========================
44

5+
.. warning::
56

6-
**Note: The content below applies to Qubes R3.2.**
7+
This page is intended for advanced users.
78

8-
DisposableVM image preparation
9-
------------------------------
9+
Disposable behavior
10+
-------------------
1011

1112

12-
DisposableVM is not started like other VMs, by executing equivalent of ``xl create`` - it would be too slow. Instead, DisposableVM are started by restore from a savefile.
13+
A :term:`disposable template` is an :term:`app qube` with the property ``template_for_dispvms`` enabled.
1314

14-
Preparing a savefile is done by ``/usr/lib/qubes/qubes_prepare_saved_domain.sh`` script. It takes two mandatory arguments, appvm name (APPVM) and the savefile name, and optional path to “prerun” script. The script executes the following steps:
15+
A :term:`disposable` qube is a qube with the ``DispVM`` class based on a disposable template. Every disposable type has all of its volumes configured to disable ``save_on_stop``, therefore no changes are saved on shutdown. Unnamed disposables enables the property ``auto_cleanup`` by default, thus automatically removes the qube upon shutdown.
1516

16-
1. APPVM is started by ``qvm-start``
17+
Named disposables are useful for service qubes, as referencing static names is easier when the qube name is mentioned on Qrexec policies (:file:`qubes.UpdatesProxy` target) or as a property of another qube, such as a disposable :term:`net qube` which is referenced by downstream clients in the ``netvm`` property.
1718

18-
2. xenstore key ``/local/domain/appvm_domain_id/qubes_save_request`` is created
19+
Unnamed disposables have their names in the format :samp:`disp{1234}`, where :samp:`{1234}` is derived from the ``dispid`` property, a random integer ranging from 0 to 9999 with a fail-safe mechanism to avoid reusing the same value in a short period.
1920

20-
3. if prerun script was specified, copy it to ``qubes_save_script`` xenstore key
21+
The system and every qube can have the ``default_dispvm`` property. 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. There are some Qrexec services that which allows execution to this newly created disposable when the destination qube (Qrexec field) uses the ``@dispvm`` tag, most commonly used to open files and URLs, (:file:`qubes.OpenInVM` and :file:`qubes.OpenURL`, respectively).
2122

22-
4. wait for the ``qubes_used_mem`` key to appear
23+
Preloaded disposables
24+
---------------------
2325

24-
5. (in APPVM) APPVM boots normally, up to the point in ``/etc/init.d/qubes_core`` script when the presence of ``qubes_save_request`` key is tested. If it exists, then
2526

26-
1. (in APPVM) if exists, prerun script is retrieved from the respective xenstore key and executed. This preloads filesystem cache with useful applications, so that they will start faster.
27+
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.
2728

28-
2. (in APPVM) the amount of used memory is stored to ``qubes_used_mem`` xenstore key
29+
Every process that is slow the user will want to circumvent, preloaded disposables enables fast retrieval of fresh disposables, so users don't have to get away from the computer or switch tasks when requesting disposables (or not requesting one at all because it was slow).
2930

30-
3. (in APPVM) busy-waiting for ``qubes_restore_complete`` xenstore key to appear
31+
Preloaded disposable stages
32+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
3133

34+
There are several stages a disposable goes through while preloading and being used. In short:
3235

36+
- **Preload**: The qube is created and marked as preloaded. Qube is not visible in GUI applications.
3337

34-
6. when ``qubes_used_mem`` key appears, the domain memory is reduced to this amount, to make the savefile smaller.
38+
- **Startup**: Begins qube startup, start basic services in it and attempt to interrupt (suspend/pause).
3539

36-
7. APPVM private image is detached
40+
- **Request**: The qube is removed from the preload list. If startup has not yet reached interrupt, the latter is skipped.
3741

38-
8. the domain is saved via ``xl save``
42+
- **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.
3943

40-
9. the COW file volatile.img (cow for root fs and swap) is packed to ``saved_cows.tar`` archive
44+
Preloaded disposable's worry-free life-cycle
45+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4146

4247

48+
There are several events that may trigger the creation or deletion of preloaded disposables. These events happen for different reasons, mostly because:
4349

44-
The ``qubes_prepare_saved_domain.sh`` script is lowlevel. It is usually called by ``qvm-create-default-dvm`` script, that takes care of creating a special AppVM (named template_name-dvm) to be passed to ``qubes_prepare_saved_domain.sh``, as well as copying the savefile to /dev/shm (the latter action is not done if the ``/var/lib/qubes/dvmdata/dont_use_shm`` file exists).
50+
- There is a gap between the current number of preloaded disposables and the max; or
51+
- The current number of preloaded disposable is over the max.
4552

46-
Restoring a DisposableVM from the savefile
47-
------------------------------------------
53+
The preload creation can also fail for different reasons:
4854

55+
- Qubesd was interrupted mid preload creation, on the next service restart, ``domain-load`` of the disposable template will refresh the incomplete disposables;
56+
- Service to check if the system is fully operation has failed; and
57+
- There is not enough memory to preload at the moment.
4958

50-
Normally, disposable VM is created when qubes rpc request with target *$dispvm* is received. Then, as a part of rpc connection setup, the ``qfile-daemon-dvm`` program is executed; it executes ``/usr/lib/qubes/qubes_restore`` program. It is crucial that this program executes quickly, to make DisposableVM creation overhead bearable for the user. Its main steps are:
59+
If there is a gap, it will be capped *event*\ ually, if it is over the max, it will be deleted as soon as possible. If the volumes are outdated, they will be refreshed. These are common events that trigger changes in preloaded disposables quantity:
5160

52-
1. modify the savefile so that the VM name, VM UUID, MAC address and IP address are unique
61+
- Setting or deleting the ``preload-dispvm-max`` feature will refill or remove;
62+
- (Re)starting :file:`qubes-preload-dispvm.service` will refresh;
63+
- Using a preloaded disposable will refill;
64+
- Requesting a disposable will refill;
65+
- Updating the volumes of a template or disposable template will refresh;
66+
- Changing system's ``default_dispvm`` while system's feature is set to a different value than the disposable template setting will refill or remove;
5367

54-
2. restore the COW files from the ``saved_cows.tar``
68+
Preloaded disposables memory management
69+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5570

56-
3. create the ``/var/run/qubes/fast_block_attach`` file, whose presence tells the ``/etc/xen/scripts/block`` script to bypass some redundant checks and execute as fast as possible.
5771

58-
4. execute ``xl restore`` in order to restore a domain.
72+
At the end of preloading, the qube is paused if it has not been requested yet, but before pausing, on ``domain-pre-paused``, it attempts to retrieve memory from the qube by setting it to use its preferred memory value, which in :doc:`qmemman parlance </developer/services/qmemman>`, is just enough to have the qube running. The memory must be managed before the qube is paused, cause once on the paused state, it is not possible to negotiate with the domain.
5973

60-
5. create the same xenstore keys as normally created when AppVM boots (e.g. ``qubes_ip``)
74+
This process can take a bit of time because it depends on how fast the qube can free up memory. There is a timeout and a threshold in transfer speed. When any of these exit conditions are met, the memory management seizes and the preloaded disposable is paused. Although this process takes some time, we do not worry much about it because it economizes memory on the long run, the biggest problems is that qmemman is synchronous, so only one request can be made at a time, anything that takes too much time on qmemman could prevent ballooning/balancing of other qubes on the system.
6175

62-
6. create the ``qubes_restore_complete`` xenstore key. This allows the boot process in DisposableVM to continue.
76+
Preloaded disposables security
77+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6378

6479

80+
As preloaded disposables are started before being used, methods to prevent accidental tampering have been put in place as well as guarantees to prevent reuse:
6581

66-
The actual passing of files between AppVM and a DisposableVM is implemented via qubes rpc.
82+
- The qube has the ``internal`` feature enabled, Qubes GUI applications were patched to hide internal qubes, handling events for ``domain-feature-(set|delete):internal``;
83+
- When requesting an unnamed disposable, the qube object is only returned to the user once it has finished preloading;
84+
- The qube is paused as the last stage of preloading, this permits receiving ``domain-unpaused`` events and be notified that the qube was used, marked as such and removed from the preload list to avoid reuse, even without the qube being requested with ``DispVM.from_appvm``;
85+
- The GUID only connects to the GUI agent on the qube after the preloaded disposable is marked as used, this prevents that an autostarted application such as a terminal appears on the screen before preloading has finished. Enabling a GUI is is controlled by the ``is_preload`` property, that when disabled, allows the GUI connection to initiate. This method delays GUI calls considerably as establishing the connection can take ~2 seconds, research is being done to prevent this delay.
6786

68-
Validating the DisposableVM savefile
69-
------------------------------------
87+
Another point of security is reliability:
7088

89+
- The feature ``preload-dispvm-threshold`` controls how much free memory must be present on the system before attempting to create a new preloaded disposable. Used to ensure preloaded disposables do not consume all available memory, which would prevent starting other qubes.
7190

72-
DisposableVM savefile contains references to template rootfs and to COW files. The COW files are restored before each DisposableVM start, so they cannot change. On the other hand, if templateVM is started, the template rootfs will change, and it may not be coherent with the COW files.
91+
Alternatives considered
92+
^^^^^^^^^^^^^^^^^^^^^^^
7393

74-
Therefore, the check for template rootfs modification time being older than DisposableVM savefile modification time is required. It is done in ``qfilexchgd`` daemon, just before restoring DisposableVM. If necessary, an attempt is made to recreate the DisposableVM savefile, using the last template used (or default template, if run for the first time) and the default prerun script, residing at ``/var/lib/qubes/vm-templates/templatename/dispvm_prerun.sh``. Unfortunately, the prerun script takes a lot of time to execute - therefore, after template rootfs modification, the next DisposableVM creation can be longer by about 2.5 minutes.
94+
95+
For an alternative to be considered for implementation, it must meet the following requirements:
96+
97+
- No memory or ``vcpus`` restrictions such as limiting to a few number of ``vcpus`` or assigns memory on request (can be slow).
98+
- Performant as much as a normal disposable even on long running sessions;
99+
- Caller transparency, no change necessary for callers, the request must be transparent and the server must find the fastest option. This is to avoid transition burden (API breakage).
100+
101+
From the evaluated options, only :ref:`preload queue <developer/services/disposablevm-implementation:preload queue>` meets all requirements.
102+
103+
104+
Restoration from savefile
105+
"""""""""""""""""""""""""
106+
107+
108+
**Description**: Disposable template booted, its image was dumped (suspend to disk), newly disposables would restore this image to become their own.
109+
110+
**Evaluation**:
111+
112+
- Used in R3.2, worked at that time, when there was only one disposable template available, see next points of why it can't be used anymore.
113+
- Incompatible with multiple ``vcpus``.
114+
- Some memory issues.
115+
- Savefile creation takes a long time. The disposable qube savefile contains references to template rootfs and :abbr:`CoW (Copy-on-Write)` files, if there is a modification on the template or disposable template, it took longer than 2.5 minutes to generate the next disposable.
116+
117+
Xen domain fork
118+
"""""""""""""""
119+
120+
121+
**Description**: domain forking is the process of creating a domain with an empty memory space and a parent domain specified from which to populate the memory when necessary. For the new domain to be functional the domain state is copied over as part of the fork operation (HVM params, heap allocation etc). This description was sourced from `[Xen-devel] [RFC PATCH for-next 17/18] xen/mem_sharing: VM forking, Tamas K Lengyel <https://lists.xenproject.org/archives/html/xen-devel/2019-09/msg02497.html>`__.
122+
123+
**Evaluation**:
124+
125+
- Shares too much information from the trunk to the forks. This appears to have improved if not totally fixed on Linux 6.14, as mentioned by Andrew Cooper on Qubes OS Summit 2025;
126+
- Requires changing properties after the fork is done, this includes, but not limited to, ``xid`` of connected qubes, network uplink;
127+
- Not designed for long running sessions, the initial intention was fuzzing. As fast as the creation can be, the usage may be slower as memory is mapped on request. Xen doesn't have a poper :abbr:`CoW (Copy-on-Write)` support for domain memory, so making a full copy of a domain on fork also has some overhead;
128+
- Tamas K Lengyiel `VM Forking & Hypervisor-Based Fuzzing with Xen <https://www.youtube.com/watch?v=3MYo8ctD_aU>`__ presentation during the Open Source Summit Europe in 2022, showed impressive results on CPU i5-8350U, an average of time of 0.745 ms per fork (created 1300 VM/s). These fast results were later explained that was due to not initializing the whole VM memory on the fork unless it was requested, as explained on the point above. Still impressive results but current usage is limited to fuzzing.
129+
130+
Preload queue
131+
"""""""""""""
132+
133+
134+
**Description**: Start disposables and queue them in a disposable template feature, unnamed disposables requested will prefer to retrieve disposables from this list.
135+
136+
**Evaluation**:
137+
138+
- Because the qube is running prior to being requested, multiple components have to be patched to support it to various levels off difficulty. Excluding from backups to allowing removal of disposable templates that only have preloaded disposables to even stranger issues such as deferring net qube change from a preloaded disposable where the old net qube has already been purged from the system.
139+
- The biggest difference between the queue and the other alternatives is that this solution works, is reliable and fulfills all requirements. A proper solution would be patching upstream Xen to implement :abbr:`CoW (Copy-on-Write)`, but that would involve a lot more work than what the Qubes Team can provide with current resources.

0 commit comments

Comments
 (0)