Skip to content

Conversation

@deeplow
Copy link
Contributor

@deeplow deeplow commented Jan 30, 2026

Fixes #1265. Blocked by #1373

Custom-persist is a feature introduced in Qubes 4.3 that, as the name implies, enables persisting particular files. This turns these qubes into semi-disposables. This makes an attack slightly more challenging if persistence is the goal, although it is by no means equivalent to the properties of full disposables (e.g. here the persistence is enforced by the kernel and not the hypervisor).

Properties:

  • qubes should retain only specified files and directories
  • data previously stored in the user's home is preserved but not mounted in /home (you can find it under /rw/home/user)
  • arbitrary data can be persisted in /rw/, but it won't be mounted in critical locations.

Test plan

Before running make-dev

  • Start client application and send and receive some messages (to ensure that there is some state
  • (repeat for the app)
  • sdw-admin --apply or make dev with this branch
  • Start client and ensure state persisted. Play around and see if there are any glitches caused by files going away. Also watch out for slowness due to missing caches.
  • (repeat for the app)

Clean installation — also test in a clean environment (sdw-admin --uninstall is fine). This is important because some in existing installations the files have already been created under /rw/` and it's possible we run into some edge-conditions where being saved for the first time can make then not persist.

Code review: (particular things to watch out for)

  • Confirm that no other sd-workstation-tagged remain with full persistence (except disposable templates — should we also add it to them?)
  • Are there any other directories/files that should also be included
  • Of the persisted files / directories does any allow the persistence of easily executable code (.e.g /home/user/.profile) — we don't want this kind of behavior

Checklist

This change accounts for:

  • any necessary RPM packaging updates (e.g., added/removed files, see MANIFEST.in and rpm-build/SPECS/securedrop-workstation-dom0-config.spec)
  • any required documentation

- enable:
- service.custom-persist
- set:
- custom-persist.client_dir: /home/user/.securedrop_client/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the client is going away, this is not too critical, but is there something here that we don't fully need?

Custom-persist is a feature introduced in Qubes 4.3 that, as the name
implies, enables persisting particular files. This turns these qubes
into semi-disposables. This makes an attack slightly more challenging if
persistence is the goal, although it is by no means equivalent to the
properties of full disposables (e.g. here the persistence is enforced by
the kernel and not the hypervisor).

Properties:
  - qubes should retain only specified files and directories
  - data previously stored in the user's home is preserved but not
    mounted in /home (you can find it under /rw/home/user)
  - arbitrary data can be persisted in /rw/, but it won't be mounted in
    critical locations.
@deeplow deeplow force-pushed the 1265-custom-persist branch from 190c83a to bec5c86 Compare January 30, 2026 21:14
- service.custom-persist
- set:
- custom-persist.gnupg_dir: /home/user/.gnupg
{% endif %}
Copy link
Contributor Author

@deeplow deeplow Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we stopped persisting ~/.profile, we're essentially undoing the gpg prompt removal introduced in #1466. To work around this, we have two options:

Option 1

Include in this PR some on-boot step that adds export QUBES_GPG_AUTOACCEPT=2147483647 to ~/.profile.

To avoid a complementary client package, this implementation may share the functionality proposed for #1505.

Option 2 (probably easier)

Add export QUBES_GPG_AUTOACCEPT=2147483647 to /etc/.profile in the template, under /etc/profile.d.

This would ideally be done through a package as opposed to salt, but since it's it's in the template we're not incurring extra installation time. Furthermore, we can target only sd-gpg either by its name (kind of how the client does) to set's sd-gpg as its backend domain. But arguably preferably is to implement this by a qubes-service. This way, should we ever need to remove this behavior in sd-gpg we don't have to care about whether or not the file exists in the system (see problem described bellow), but simply remove the qubes service...

  • Via salt/ansible: We'll forever need to care about this file in the template
  • Through package: One more package, but we can change whatever we want (including remove that file). However, because the package is itself installed through salt, we get to the same exact problem ­should we no longer need it, we need to tell salt to remove it :/

- enable:
- service.custom-persist
- set:
- custom-persist.gnupg_dir: /home/user/.gnupg
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this more fine-grained? Or do we risk loosing important files?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the app is default + we have the dom0 RPC to get the secret key the entire VM will be made disposable so I don't think we need to worry too much about this.

@deeplow deeplow moved this to In Progress in SecureDrop Jan 30, 2026
@deeplow deeplow linked an issue Feb 2, 2026 that may be closed by this pull request
@nathandyer nathandyer moved this from In Progress to Blocked or Waiting in SecureDrop Feb 3, 2026
@deeplow deeplow moved this from Blocked or Waiting to In Progress in SecureDrop Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Make use of custom-persist on app qubes

2 participants