RELIANT - Deniable encryption for Qubes OS

Many users have been requesting plausible deniability in Qubes in some form, either for the installation as a whole or specific qubes. RELIANT is a project that provides multi-level plausible deniability in Qubes via Shufflecake, a modern deniable encryption system.

  • dom0 is made live/volatile via intrinsic systemd functionality.
  • Deniable qubes are stored in Shufflecake volumes.
  • During boot you enter the standard LUKS password for dom0, and the Shufflecake password for the top volume you want to decrypt.
  • RELIANT facilitates this through initramfs and userspace tooling.

We emphasize the importance of preventing and avoiding leakage of any information, direct or indirect, about the hidden volumes and qubes within. This is largely addressed by moving dom0 to RAM, supported by hash verification of non-volatile storage media. But there are side channels we cannot address, such as traffic analysis or eavesdropping. For more information, see the README.

The project is in a highly experimental state and uses several features not officially supported by QubesOS, and I do not have the time or resources to maintain a fork. However, subject to the developers’ approval, I can start working on patches that will bring the necessary functionality into core Qubes codebase.

If anyone is interested in testing the system, I would be happy to provide support if you contact me. I have tested it myself and it does work, but as a developer I will inevitably be biased, especially regarding usability and convenience.

Q: How to update dom0 or templates?

A: There is a Maintenance Mode which can be entered by erasing systemd.volatile=overlay from the GRUB command line.

Q: Does volatile dom0 require lots of RAM?

A: Not really - most devices which can run Qubes, can run RELIANT as well.

Q: How to copy files between qubes?

A: Never copy directly between hidden qubes in different Shufflecake volumes - this will reveal the source qube’s existence and name to the target. Use a proxy disposable qube.

Q: What are the prerequisites for installation?

A: Enough free space on disk for the Shufflecake partition, a bootstrap qube with Docker, good knowledge of Linux and Qubes for troubleshooting.

13 Likes

Hell yeah. This sounds fuckin’ awesome, I look forward to trying it out.

1 Like

It would be amazing to implement this in Qubes. Besides shufflecake hidden volumes, a volatile dom0 is also a good idea.

2 Likes

The codeberg readme mentions how there’s no ram wipe. Recently, a RAM wipe script posted to the forum. It also includes two live modes which may improve security. Are you considering adding this script to RELIANT in the future?

1 Like

Indeed, I have seen that topic. Regarding the RAM wipe, I will have to look into it. Our main concern is kernel-space memory, which contains the dm-sflc module with all the encryption and volume information. At a glance, I do not see any mention of kexec, which would be necessary for such an operation. The script posted by the OP just does

echo 3 > /proc/sys/vm/drop_caches

which is IMO insufficient for full cold boot attack protection.

However, in the related GitHub issue, adrelanos says

ram-wipe relies on the operating system during shutdown to shutdown all processes, VMs, umount all disks, etc. ram-wipe then runs its first pass at the end of the shutdown process to fill up all RAM which will hopefully overwrite everything of importance. ram-wipe will then kexec into the same kernel with a special kernel parameter to make sure even the old kernel gets wiped from RAM and does another pass of RAM wiping.

which would imply there is indeed a kexec in the process. Therefore, it is possible to do a proper RAM wipe, including kernel-space. When adding the functionality to RELIANT, I’d prefer the full solution. It also should be noted that there are several security issues with the RAM wipe approach,

  • An attacker could just hard reset the device,
  • On some devices, the proper shutdown sequence may take a while,

which was also brought up in the issue thread,

Can’t the attacker hard reset the system, and bypass any protection that rely on the system going through a controlled shutdown sequence?

Yes. So for ram-wipe or any alternative to be useful, it needs to be triggered. Potential triggers are A) shutdown; B) device removal; or C) a panic key.

In this case there are two modes of attack, attended and unattended. Attended is simple - unplug the panic key, device is shut down and RAM is erased. I would also highly advise physical security measures, such as tape or epoxy, to be applied to the device. For unattended mode, the situation is much more difficult. Do we need to include some kind of tamper detection? Of course, the best practice is to never leave your device unattended and turned on, but this could literally happen in a matter of minutes.

I’d be interested to hear yours and other users’ thoughts on the matter since that is something I intend to address at some point. In any case, the conclusion is that, despite being an imperfect solution, the RAM wipe would be a net positive for security and therefore should be included after I review all the relevant code.

For the live modes they present, I won’t be so sure, because they mention

The size of the dom0 memory must exceed the amount of space used on the dom0 disk! Otherwise live modes won’t start. The size of dom0 changes after each update; kernel updates can significantly increase the dom0 size on disk, and live modes may stop working after a kernel update.

I don’t think this is correct, since an OverlayFS-based live mode only stores deltas and does not need to copy the entire disk into RAM. Regardless, I suspect that our implementation of the live mode would have a lower RAM footprint than the alternatives thanks to certain patches we apply to the Qubes storage pool management code. It has been verified to function on a machine with 16 GB of total RAM and 4 GB of RAM allocated to dom0.

Despite this, there are some issues with it since SystemD, which we use to create the tmpfs, unmounts it by default, leaving it permanently with the default size of 1 GB. This can work, but barely. RELIANT_PROFILING solves this, but relies on patching the relevant SystemD binary, which is undesirable. Therefore, in the future we’ll have to move to custom overlay creation code. For the same reason, I am hesitant to include any third-party modules as-is, since we may need to make heavy modifications for our usecase, and at this point it could be better to write our own.

1 Like

this is so cool

1 Like

Hi, I tried to install RELIANT from your codeberg. It looks like you are working on it (even recently) for Qubes 4.2. It won’t work on 4.3 (different python versions, file hashes etc..) Will you be releasing or planning on working on it for 4.3?

2 Likes

Yes, 4.3 is not supported yet but that’s certainly in the works. The main roadblock is our reliance on the file pool type for most operations, while 4.3 is designed to use lvm-thin pools. Some of the patches have been upstreamed (qubesvm.rbatch and storage.rbatch) so they won’t have any 4.3 variant. create-snapshot.rbatch is only applicable to file pools so is not relevant for 4.3. init.rbatch is the important one, responsible for domU RAM overlays, but since the patch system supports versioning, it should be relatively straightforward to have patches for multiple origin files. Unfortunately I have been very busy with other things so couldn’t get my hands on porting to 4.3, but that’s the prioritized next step. If you, or other interested people, wish to contribute, I’d be happy to go into more detail on the roadmap for this.

1 Like

Codeberg has restricted LLM-generated content, so I cannot contribute to the project even if I wanted to.

…are you an LLM? :smiley:

To the best of my knowledge the restriction is on projects “mostly consisting of AI-generated code”, which is not the case here. As a security focused project I would prefer not to have AI contributions without thorough human review, and also because there is little value in such contributions otherwise - anyone, including myself, could ask AI to whip up a solution. The real bottleneck is testing, which is especially time consuming on Qubes because the lack of nested virtualization necessitates a physical system to run it on.

1 Like

Yep, they are not strict at all.

1 Like

Thanks, I did quite a bit of work trying to get it to work on 4.3, changed the python version, file hashes etc.. I am sorry I didn’t document it. I did notice it failing with rpatch. My end result was that I finally got it to boot. I was able to unlock the Shufflecake volumes etc.. However none of my qubes showed up in the end so the final steps of the install script failed.

FWIW I was able to achieve a similar (somewhat deniable) result by using a detached header on a Vault pool.

For my RAM-WIPE module I used init_on_alloc=1 and init_on_free=1 on the ephemeral Grub entry.

1 Like

Could you check whether you were using a file pool or a lvm-thin pool for varlibqubes and the Shufflecake device? Good news that you got it to boot, and the mode of failure is actually not surprising. No qubes in the menu likely means that the surgeon-suture script is failing, which is expected if you were using lvm-thin and did not adapt it as well. It’s also a bit unclear from your post whether you were trying to open an existing Shufflecake device or a freshly formatted one created by RELIANT and managed via surgeon-dissect? I’d appreciate if you could elaborate a bit more and/or send over what modifications you have made, since this could potentially save quite a bit of time.

1 Like

yes surgeon-suture did fail.

Unfortunately I have now moved to using BTRFS and BTRFS snapshots for an ephemeral option which uses a throw-away encrypted snapshot and loads dom0 in RAM so I won’t be able to go back to square-one.

It was a somewhat unconventional install though.
When I installed RELIANT the Shufflecake volumes (I made 5) were created from your install script on a new Qubes 4.3 Install (ext4) which was manually created with a detached LUKS header. VM-pool was manually created lvm-thin. However during the Qubes Install I left free 80GB unused space and I used that for the shufflecake volume.

I think I see now in hindsight, thanks to your reply where it failed though.

Explains it. I wonder how I missed it.:thinking:

Once again, when I am in dev mode, I just push on to the end and try many many things, a lot of which I forget. So I apologize I did not document it.

1 Like