Plausible deniability in Qubes OS requires certain features in qubes-core-admin

20 views
Skip to first unread message

Anderson Rosenberg

unread,
Feb 5, 2026, 4:44:25 AM (5 days ago) Feb 5
to qubes-devel
Dear Qubes OS Users and Developer Team,

I am the developer of the RELIANT project, which provides support for plausible deniability in Qubes OS via volatile dom0 and Shufflecake encryption system. As of now, it relies on separating qubes.xml into 'shards' located in each deniable volume and merging them during the initramfs stage, as well as applying patches to the core system in order to maintain a RAM-based dom0. Both of these methods are unreliable and that is not something I believe should be kept in a security-focused project. Given that both deniable encryption and live dom0 have been explicitly requested by users, as well as positive forum feedback, I would like to propose a set of changes to the qubes-core-admin codebase that would make this possible without relying on unstable workarounds.

     1. Support for split qubes.xml.

We need a robust way to dynamically pick up qubes from the following locations,
  • /var/lib/qubes/qubes.xml for core domains, templates and sys-*,
  • /run/shufflecake/sflc_X_X/qubes.xml for deniable domains.
Currently this is handled by surgeon-dissect and surgeon-suture. The locations are hardcoded into the script. My proposal is as follows,
  • Designate the qubes.xml in /var/lib/qubes as authoritative,
  • Establish a non-authoritative XML format as a set of <domain> entries,
  • Allow the original qubes.xml or other configuration file deemed appropriate to link to an additional root folder,
  • Recursively load additional domains.xml files within the linked folder.
We could modify app.py in qubesd to support sharding on both save and load. Otherwise, there could be an official tool to merge and split qubes.xml which respects any changes to the format. However, I believe the former would be both easier to implement and more robust, despite requiring changes to a core system component.


     2. Randomized qube IDs.

Sequential qube IDs will leak information about the presence of qubes in 'gaps' when the system is booted under duress. Current workaround is to programmatically change them in the XML files. A better solution would be to modify app.py to provide randomized QIDs from a CSPRNG following a collision check with existing identifiers. In order to avoid confusing existing users, this feature should be highly optional. Existing qube IDs can be left as-is.


     3. create-snapshot must respect rw="False".

Otherwise, create-snapshot fails for large images (>~2 GB) such as templates under volatile dom0. For images tagged as rw="False", create-snapshot should invoke losetup with the --readonly flag. The condition is to be identified within file.py and passed to create-snapshot as a commandline argument. Since readonly images must not be modified, this should not contain any breaking changes and can be seamlessly implemented without opt-in flags.


     4. Copying between qubes in deniable volumes must be forbidden.

Suppose you copy any file from a hidden qube 'secret' to a public qube 'work'. This will clearly reveal the source of the copied files as ~/QubesIncoming/secret, and the worst part is that even when you delete this directory, there will be forensically visible traces in the filesystem journal. Therefore, this must be strictly forbidden. I believe this can be handled via a tagging policy in Qubes RPC, but I will need to look deeper into that. The main point is that there must be a policy filter which can be applied based on storage pools (same/different) or an equivalent measure. An alternative solution could be to optionally obfuscate the source qube name in Qubes RPC for the target qube.


Please share your thoughts on the matter and consider whether these features would be welcome in the codebase. If approved and we agree on an approximate implementation course, I will be ready to start working on individual PRs for each one.

Kind regards,
Anderson Rosenberg




unman

unread,
Feb 5, 2026, 7:46:25 AM (5 days ago) Feb 5
to Anderson Rosenberg, qubes-devel
Thanks for this. There's a lot to dig in to here.

How much of this is tied to the current state of shufflecake, which is
still in the experimental stage, no? I think it has only been tested
by the developers on Debian based system, and is not recommended as
reliable as yet.

I'd be reluctant to see changes in Qubes, for these reasons.

Marek Marczykowski-Górecki

unread,
Feb 5, 2026, 9:07:37 AM (5 days ago) Feb 5
to Anderson Rosenberg, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

On Thu, Feb 05, 2026 at 04:33:36AM +0000, 'Anderson Rosenberg' via qubes-devel wrote:
> Dear Qubes OS Users and Developer Team,

Hello!

> I am the developer of the https://codeberg.org/andersonarc/reliant-system project, which provides support for plausible deniability in Qubes OS via volatile dom0 and  https://codeberg.org/shufflecake/shufflecake-c  encryption system. As of now, it relies on separating qubes.xml into 'shards' located in each deniable volume and merging them during the initramfs stage, as well as applying patches to the core system in order to maintain a RAM-based dom0. Both of these methods are unreliable and that is not something I believe should be kept in a security-focused project. Given that both  https://github.com/QubesOS/qubes-issues/issues/2402  and  https://github.com/QubesOS/qubes-issues/issues/4982  have been explicitly requested by users, as well as  https://forum.qubes-os.org/t/reliant-deniable-encryption-for-qubes-os , I would like to propose a set of changes to the https://github.com/QubesOS/qubes-core-admin  codebase that would make this possible without relying on unstable workarounds.

This is quite complicated topic, as you already know. In general,
proposed features mostly align with some other planned features.
Especially, it would be useful for several other reasons to store some
of the qubes on separate partitions or even external disks - and make
them available only when such partition/disk is visible. Not only for
plausible deniability reasons.
A stretch goal could an architecture allowing such qubes (on an external
disk) to be connected to different Qubes OS installations, and just
work (imagine having home PC and work PC, and being able to easily take
some of the qubes with you and connect to the other). Ideally, such
mechanism should treat external qubes as untrusted (in other words:
prevent "home PC" compromising "work PC" by some malicious XML
modification, for example). But I'm not very optimistic about
feasibility of this scenario (see below)...

But also, due to complexity I would advice some patience in having them
properly implemented.

To the collection of your related tickets, I'd also add this one:

https://github.com/QubesOS/qubes-issues/issues/3820
and also kinda related:
https://github.com/QubesOS/qubes-issues/issues/1293


>      1. Support for split qubes.xml.
>
>
>
> We need a robust way to dynamically pick up qubes from the following locations,
>
> /var/lib/qubes/qubes.xml for core domains, templates and sys-*,
>
> /run/shufflecake/sflc_X_X/qubes.xml for deniable domains.
>
>
> Currently this is handled by  https://codeberg.org/andersonarc/reliant-system/src/branch/master/tools/surgeon-dissect  and  https://codeberg.org/andersonarc/reliant-system/src/branch/master/tools/surgeon-suture . The locations are hardcoded into the script. My proposal is as follows,
>
> Designate the qubes.xml in /var/lib/qubes as authoritative,
>
> Establish a non-authoritative XML format as a set of <domain> entries,
>
> Allow the original qubes.xml or other configuration file deemed appropriate to link to an additional root folder,
>
> Recursively load additional domains.xml files within the linked folder.
>
>
> We could modify  https://github.com/QubesOS/qubes-core-admin/blob/main/qubes/app.py  in qubesd to support sharding on both save and load. Otherwise, there could be an official tool to merge and split qubes.xml which respects any changes to the format. However, I believe the former would be both easier to implement and more robust, despite requiring changes to a core system component.

This one is I think the most complex change from those proposed here.
This is because of dependencies between qubes - they must not fail, even
if some of the qubes in separate qubes.xml (lets call them "external
qubes" for now) are not available at the time. For example, imagine the
following situations:

1. You have an external qube based on debian-12-xfce template. You start
your system with external qubes not visible, and then remove
debian-12-xfce template (for install debian-13-xfce, migrate all visible
qubes to it and then remove debian-12-xfce). What should happen next
time you boot with external qubes visible? Same applies to other types
of dependencies (netvm, default_dispvm, audiovm, guivm, etc).

2. You create a template as an external qube, or vpn qube as an external
qube, and then make one of the standard qubes (non-external) use it (as
template or netvm respectively). What should happen next time you boot
with external qubes not visible?

The second situation might be "solved" by simply forbidding it - it
would limit usefulness of the feature (especially forbidding external
vpn qube), but it wouldn't be too bad. And for the deniable plausibility
case, it wouldn't be a problem at all - you don't want standard qubes to
have any trace of any external qubes. Note it might still be okay to
reference one external qube from another external qube (as long as they
are part of the same external storage/qubes.xml "shard").

But the first case is more problematic. You don't want to save any
information about external qubes in the main qubes.xml (that would be
counter deniable plausibility), but without such info, you cannot
prevent breaking dependencies. So, for this feature to work, it would
require some recovery mechanism, I think. I have two ideas:

1. Allowing to load such broken qube, but prevent starting it, until
user fixes the dependencies (in the above example, like change the
template to debian-13-xfce). The problem with this approach is, we
generally assume no broken objects all over the code - for example if
you have vm.template, then you can access vm.template.netvm. When
allowing loading broken objects, that wouldn't be the case anymore, and
would require carefully reviewing all the places where dependencies are
accessed and choosing a fallback in all of them. This also applies to
presenting such situation in CLI and GUI tools. TBH, I'm not optimistic
about feasibility of such change.

2. Automatically change such broken dependencies to some other value
(the obvious choice would be the default one - based on global
properties). While I think in most situations it would just work, there
are surely some corner cases. For example resetting, say, netvm from
sys-whonix to sys-firewall (just because you renamed sys-whonix) might
be very undesirable. Some workaround might be preventing starting such
"recovered" external qube until user review the change (this could use
'prohibit-start' feature added in R4.3), but it would still be clunky
and prone to errors IMHO...

>      2. Randomized qube IDs.
>
>
>
> Sequential qube IDs will leak information about the presence of qubes in 'gaps' when the system is booted under duress. Current workaround is to programmatically change them in the XML files. A better solution would be to modify  https://github.com/QubesOS/qubes-core-admin/blob/main/qubes/app.py  to provide randomized QIDs from a CSPRNG following a collision check with existing identifiers. In order to avoid confusing existing users, this feature should be highly optional. Existing qube IDs can be left as-is.

I don't think randomized QIDs are a good idea.

The QID range is just 16 bits, and it's IMO too little to avoid
conflicts just by hoping CSPRNG will not hit one. Note, you still need
to be able to create qubes while external qubes are not visible.

I see two alternative options:

1. Use dedicated QID ranges per qubes.xml "shard". You still need to
avoid conflicts between those ranges, but requiring all shards to be
visible when allocating new range is IMHO an acceptable limitation.

2. Don't store QIDs for external qubes at all - allocate them at load
time (possibly from a single range dedicated for all external qubes). QID is
used mostly at runtime (in various structures), but on-disk metadata
operate on names (most cases) and UUID (very few cases). The only
downside I can think of is dynamic IP allocation (internal IP addresses
are built based on QID) - this would break some custom firewall rules.
But if you need static IP address, you can simply set "ip" property to a
static value (and avoid IP conflicts on your own...).

But this also brings up another problem: how to avoid qube name
conflicts? What should happen if you create a qube with the same name as
one of external ones (while external qubes are not visible)?

>      3. create-snapshot must respect rw="False".
>
>
>
> Otherwise, create-snapshot fails for large images (>~2 GB) such as templates under volatile dom0. For images tagged as rw="False",  https://github.com/QubesOS/qubes-core-admin/blob/main/linux/system-config/create-snapshot  should invoke losetup with the --readonly flag. The condition is to be identified within  https://github.com/QubesOS/qubes-core-admin/blob/main/qubes/storage/file.py  and passed to create-snapshot as a commandline argument. Since readonly images must not be modified, this should not contain any breaking changes and can be seamlessly implemented without opt-in flags.

While I'm not strictly against such change, there are two things you
need to be aware:

1. Such block device (with rw=False) is connected as read-only block
device to the VM anyway (see templates/libvirt/xen.xml). So, setting
loop device read-only is not strictly necessary.

2. The "file" storage driver should be avoided, and will eventually be
removed (in Qubes OS 5.0, whenever that happens). The use of dm-snapshot
is very inefficient (especially when reverting to an earlier snapshot),
and is incompatible with many features (like making a backup while the
qube is running).

If you need plain files, I'd recommend using file-reflink driver, on a
CoW-enabled filesystem (like xfs or btrfs).


>      4. Copying between qubes in deniable volumes must be forbidden.
>
>
>
> Suppose you copy any file from a hidden qube 'secret' to a public qube 'work'. This will clearly reveal the source of the copied files as ~/QubesIncoming/secret, and the worst part is that even when you delete this directory, there will be forensically visible traces in the filesystem journal. Therefore, this must be strictly forbidden. I believe this can be handled via a tagging policy in Qubes RPC, but I will need to look deeper into that. The main point is that there must be a policy filter which can be applied based on storage pools (same/different) or an equivalent measure. An alternative solution could be to optionally obfuscate the source qube name in Qubes RPC for the target qube.

Indeed a policy is a way to go. And you can quite easily make an
extension that adds tags based on the storage pool. See for example an
addon that add tags based on a template:
https://github.com/QubesOS/qubes-core-admin-addon-kicksecure/blob/main/qubeskicksecure/__init__.py

- --
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEEhrpukzGPukRmQqkK24/THMrX1ywFAmmEpCAACgkQ24/THMrX
1yySFgf+N1XwZ5IkJ5M2AVa3zki/c+CgJwRorTeFk1ntQppQzbj7poOBlH+zC13z
INkXdOiX2HqjSjnAJYoyB2/ocBwGyOpt0I8J19El2PFYojEEkQvl6X8vpk1Ci+M/
0KagqU7e9Lus4zl4A4Pf6s2j7YHF2E9gusyYKKN7nktDUTeecptiIq+AelSrxMgi
cs4+E8axHkuf59n9joFHNIJ2wmSwx2U33I7DpP27KY4CU23JNp7Jzq5sItPOgvTT
X8cHf5FsGX4VIdHPufECEClo+KdZ8VgX/vXUp9FhvdF1ZMrZignUqCu7xcJQgn4w
VSu4TVpm5oy6eYE8/c96dnZ1cyt+bQ==
=WkFQ
-----END PGP SIGNATURE-----

Rusty Bird

unread,
Feb 5, 2026, 11:31:23 AM (5 days ago) Feb 5
to Anderson Rosenberg, qubes-devel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Anderson Rosenberg:
>      3. create-snapshot must respect rw="False".
>
> Otherwise, create-snapshot fails for large images (>~2 GB) such as
> templates under volatile dom0. For images tagged as rw="False", 
> https://github.com/QubesOS/qubes-core-admin/blob/main/linux/system-config/create-snapshot
> should invoke losetup with the --readonly flag. The condition is to
> be identified within 
> https://github.com/QubesOS/qubes-core-admin/blob/main/qubes/storage/file.py
> and passed to create-snapshot as a commandline argument. Since
> readonly images must not be modified, this should not contain any
> breaking changes and can be seamlessly implemented without opt-in
> flags.

Can you switch to the 'file-reflink' storage driver? The legacy 'file'
storage driver is deprecated and due to be ripped out:

https://github.com/QubesOS/qubes-issues/issues/6399

Rusty
-----BEGIN PGP SIGNATURE-----

iQKTBAEBCAB9FiEEhLWbz8YrEp/hsG0ERp149HqvKt8FAmmEvHpfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDg0
QjU5QkNGQzYyQjEyOUZFMUIwNkQwNDQ2OUQ3OEY0N0FBRjJBREYACgkQRp149Hqv
Kt/llw/+IAlyfXPETJCmejq4lmzcyZzoMsoFH3WdmbGO0jN7tA8h7pT+ijkcQ7ul
BhVHPcAUZdS8L4UfJlMsKcGxuHHRG5WXNH+MKyr8khzfZ+rL/lB7cNoAh8/3NLwm
h5kGaYbSJEyMVwzbCje1QIeoM+kZGNjiUs/FLkfhbM/RR+/G6XMyppqnslBNK4Hb
yAOjVgTrrexhhWJ1QIs4KWNuxgcP55aAlyu3pphDlB83lGwStfUhb5QCSPk2tP0b
r3F3pwN5JJwLEw2kAIcjzCWlRdZjC52gahbYHr+wudPbPoOSh30kIAAinr7aCfWK
PG2H4DNduJkFY/8y5FTs9+4xqBHN+sb9KhfANu7BnLHZrYdfuTxWqQaZkTz3XUPZ
s15R9Ai1Usxx3mar7CZVqQvEgegFkv2lr4rAjPFQdtyO8x1b/QI2GQ+c17i7WLsu
dl4mZgH1iG81Rr6bzV0AGBjj8Yu4o0Jqfx4xtjsXRGM/iRhsR0RHXlbEnPjqm2cF
Fv/WJslSi5eG6VPA1buHZTt2EKtrfEyGhPqLoLADaSpIyc11/yx3W4wRgcSVGPGv
46S7xJAbaXH8TyluH+ujPAZMoVgSe9ZEik6SBpcl2gr2hBCmKhQF6N8hPf2vkg7n
WHWJ3a2O2QmL5Kp1rp+3gNk/xsTK55yS/1Ru50N4vcSy3OO/9w8=
=A+Q1
-----END PGP SIGNATURE-----

Anderson Rosenberg

unread,
Feb 6, 2026, 8:50:28 AM (4 days ago) Feb 6
to "Marek Marczykowski-Górecki", unman, rustybird, qubes-devel
Thanks everyone for the feedback. I'll address the concerns individually.

On Thu, 5 Feb 2026 12:46:19 +0000, 'unman' via qubes-devel wrote:
> How much of this is tied to the current state of shufflecake, which is
> still in the experimental stage, no?

Actually, at least 3 out of 4 proposed changes (No. 1, 2 and 4) are completely unrelated to Shufflecake itself. No. 3 is related, but indirectly. They would be necessary for any form of multi-layer plausible deniability. As far as I am aware, Shufflecake is the most mature deniable encryption toolkit that satisfies modern standards, although you are right that it is experimental. I am also a contributor to Shufflecake and will be ready to address any issues on this side, should they arise at some point.

> I think it has only been tested
> by the developers on Debian based system, and is not recommended as
> reliable as yet.

It's true that they do not guarantee stable operation. However, that's exactly why I am not proposing that we add Shufflecake to the Qubes package distribution. The features I outlined are just necessary compatibility changes. The project itself, I think, should remain an external codebase which advanced users can install for themselves. Regarding testing, I have been running RELIANT (Qubes + Shufflecake) on my own system for about half a year now without any major issues. There was a problem with garbage collection (fstrim/discard) at some point, but I have addressed that with an upstream PR.


On Thu, 5 Feb 2026 15:07:28 +0100, 'Marek Marczykowski-Górecki' via qubes-devel wrote:
> This is quite complicated topic, as you already know. In general,
> proposed features mostly align with some other planned features.
> Especially, it would be useful for several other reasons to store some
> of the qubes on separate partitions or even external disks - and make
> them available only when such partition/disk is visible. Not only for
> plausible deniability reasons.
Agreed, this will certainly be useful. However, by going beyond the plausible deniability usecase, we're actually adding new restrictions to the problem.

> This one is I think the most complex change from those proposed here.
> This is because of dependencies between qubes - they must not fail, even
> if some of the qubes in separate qubes.xml (lets call them "external
> qubes" for now) are not available at the time.
The main point here is that under Shufflecake PD, when you have external qubes unavailable (boot under duress), any interaction with the system is very likely to break something in the hidden parts. The reason for this is that fundamentally, locked hidden space is equivalent to free space, which will be used for allocating new data. The exception is Maintenance Mode, where the entire Shufflecake device is locked and unaccessible.

> 1. You have an external qube based on debian-12-xfce template. You start
> your system with external qubes not visible, and then remove
> debian-12-xfce template (for install debian-13-xfce, migrate all visible
> qubes to it and then remove debian-12-xfce). What should happen next
> time you boot with external qubes visible? Same applies to other types
> of dependencies (netvm, default_dispvm, audiovm, guivm, etc).
I believe a reasonable solution here would be to store a journal of such changes, and determine the most preferable replacement candidate. This will rely either on the user's explicit choice or heuristics. Another way would be to select a family of templates (Debian/Fedora/etc.) as a target instead of an exact template. However, neither are readily implementable from my understanding. Still, we need some kind of approach here. No. 1 is both the most complex and the most necessary feature.

> 2. You create a template as an external qube, or vpn qube as an external
> qube, and then make one of the standard qubes (non-external) use it (as
> template or netvm respectively). What should happen next time you boot
> with external qubes not visible?
Agreed that this should be forbidden. We cannot reliably guarantee that an external qube which other qubes depend on will be present at any point for USB or external storage. And in case of plausible deniability, we cannot have dependencies beyond the local XML, as you have correctly mentioned.

> 1. Allowing to load such broken qube, but prevent starting it, until
> user fixes the dependencies (in the above example, like change the
> template to debian-13-xfce). The problem with this approach is, we
> generally assume no broken objects all over the code - for example if
> you have vm.template, then you can access vm.template.netvm. When
> allowing loading broken objects, that wouldn't be the case anymore, and
> would require carefully reviewing all the places where dependencies are
> accessed and choosing a fallback in all of them. This also applies to
> presenting such situation in CLI and GUI tools. TBH, I'm not optimistic
> about feasibility of such change.
I think it might work if the fixing process occurs inside initramfs, like what RELIANT does currently. We could analyze the shards and find problematic dependencies, then prompt the user for fixes. The advantage of this is that qubesd is not running yet, hence we do not need to modify the codebase to look for fallbacks. This would only require a self-contained system-healing script, which sound must more practical to me. Again, this is not applicable to hot-plug qubes, but No. 1 only requires static sharding where the shards are already known during the early boot stages.

However, a better option would be to conduct checks within qubesd load() and skip loading shards with broken configuration until resolution. This would avoid any need to interact with the initramfs or rewrite many components, but brings the additional complexity of a dedicated qubes.xml validator which must be thorough. While substantial, I believe this is the most straightforward and practical approach.

> 2. Automatically change such broken dependencies to some other value
> (the obvious choice would be the default one - based on global
> properties). While I think in most situations it would just work, there
> are surely some corner cases. For example resetting, say, netvm from
> sys-whonix to sys-firewall (just because you renamed sys-whonix) might
> be very undesirable. Some workaround might be preventing starting such
> "recovered" external qube until user review the change (this could use
> 'prohibit-start' feature added in R4.3), but it would still be clunky
> and prone to errors IMHO...
There are several solutions I see here,
  1. The journaling feature I mentioned before, which would work reliably for renames since the mappings are unambiguous.
  2. Use a heuristic-based fixing algorithm (e.g. debian-12 can become debian-13), and for missing network qubes just set them to None, circumventing security problems.
  3. Prompt the user manually for each fix, either during initramfs where we can alter the XMLs or live using the prohibit-start feature or changes to load().
Neither is ideal, but I'd like to hear which one you're leaning towards. Perhaps a combination could work as well.


> The QID range is just 16 bits, and it's IMO too little to avoid
> conflicts just by hoping CSPRNG will not hit one.
Agreed. That's why I mentioned explicit collision prevention.

> Note, you still need
> to be able to create qubes while external qubes are not visible.
Not quite. In case of RELIANT, as I mentioned before, doing anything with the system when it's only partially unlocked is guaranteed to break things. If we consider hot-plug qubes or Maintenance Mode, however, this does become a problem.

> 1. Use dedicated QID ranges per qubes.xml "shard". You still need to
> avoid conflicts between those ranges, but requiring all shards to be
> visible when allocating new range is IMHO an acceptable limitation.
Sounds like a great solution to me. Ranges themselves could be randomly sampled from the 16-bit space, and the range size we'd have to decide upon (perhaps 128?). This does not sacrifice any security and allows shards to be more self-contained. Varlibqubes could have a fixed range 1-127, where 0 is reserved for dom0.

> 2. Don't store QIDs for external qubes at all - allocate them at load
> time (possibly from a single range dedicated for all external qubes). QID is
> used mostly at runtime (in various structures), but on-disk metadata
> operate on names (most cases) and UUID (very few cases). The only
> downside I can think of is dynamic IP allocation (internal IP addresses
> are built based on QID) - this would break some custom firewall rules.
> But if you need static IP address, you can simply set "ip" property to a
> static value (and avoid IP conflicts on your own...).
Also possible, but seems more difficult to implement. This will be more robust since there is no requirement for external qubes to be visible when allocating new ranges.

From my perspective, Option 1 is preferable here due to minimal infrastructure changes. When creating a new qube, allow tagging it as external and in this case 1) store the relevant qubes in a shard 2) allocate a QID range and put it into the shard XML.


> But this also brings up another problem: how to avoid qube name
> conflicts? What should happen if you create a qube with the same name as
> one of external ones (while external qubes are not visible)?
I suggest establishing some precedence rules where e.g. varlibqubes takes priority over any shards, and static shards take priority over hot-plug qubes. This brings us back to the same problem where there is an issue preventing a qube from starting or even being loaded, similar to what was discussed about templates/renaming. The new qubesd load() function could be designed to automatically perform collision and existence checks on every shard, and 'freeze' broken shards following the precedence rules. The conflicts could then be resolved by any of the 3 methods (manual/heuristic/journal) and asynchronously the shards will be unfrozen and loaded afterwards. This would also be a significant improvement in terms of user experience, since currently any issues must be resolved with manual XML editing and a mandatory reboot.

> 1. Such block device (with rw=False) is connected as read-only block
> device to the VM anyway (see templates/libvirt/xen.xml). So, setting
> loop device read-only is not strictly necessary.
Yes, but apparently there are some issues with how OverlayFS and loopback devices interact. The issue is on the side of dom0. Without the --readonly flag, create-snapshot simply fails for any of the template images. It works for small images (~100 MB) so I suspect that it might be checking for free space under the OverlayFS, of which there is only 1-2 GB, and failing the allocating in case the image is writeable and exceeds that constraint.

> 2. The "file" storage driver should be avoided, and will eventually be
> removed (in Qubes OS 5.0, whenever that happens). The use of dm-snapshot
> is very inefficient (especially when reverting to an earlier snapshot),
> and is incompatible with many features (like making a backup while the
> qube is running).
I think varlibqubes was under the file driver by default when I installed the system. Regarding the sflc_X_X pools, I have chosen the file driver for them due to 1) simplicity 2) conservative filesystem choices preferences for ext4 3) Shufflecake being optimized for ext4. Neither of these is a blocking issue, so when the time comes I'd be ready to migrate to either LVM storage pools or file-reflink.

> If you need plain files, I'd recommend using file-reflink driver, on a
> CoW-enabled filesystem (like xfs or btrfs).
We need some form of metadata attached to the volume for the shards, firewall rules, and other things. This could be achieved by either using btrfs for the whole volume with file-reflink, or using a LVM storage pool subdivided into data and metadata. This mostly depends on hot-plug capabilities of these drivers.

> Indeed a policy is a way to go. And you can quite easily make an
> extension that adds tags based on the storage pool.
Understood, thanks.


On Thu, 5 Feb 2026 15:51:22 +0000, 'Rusty Bird' via qubes-devel wrote:
> Can you switch to the 'file-reflink' storage driver? The legacy 'file'
> storage driver is deprecated and due to be ripped out:
Thanks, I'll look into that. See above for the rationale behind choosing the file driver.

Kind regards,
Anderson Rosenberg


Reply all
Reply to author
Forward
0 new messages