Status flipped Draft → Final. In-scope rows now cite specific config files / settings (auditable from clean checkout): - LUKS2 params from kickstart/veilor-os.ks - sysctl knobs file path - USBGuard policy mode + rule type - sshd_config drop-in path + every directive - auditd rule path + watched paths - chrony NTS endpoints - systemd-resolved DoT settings - bootloader kernel args (lockdown, slab_nomerge, init_on_alloc/free, etc.) Out-of-scope rows un-hedged. 'May not always' phrasings removed; each adversary states unambiguously what veilor-os does NOT do.
157 lines
12 KiB
Markdown
157 lines
12 KiB
Markdown
# Threat Model
|
||
|
||
> **Status:** Final for v0.7 public launch. Honest scope.
|
||
|
||
veilor-os is a hardened daily-driver desktop. Not a paranoia OS, not an
|
||
anonymity OS, not an isolation OS. This document exists so that
|
||
security-conscious developers, journalists, and activists can decide whether
|
||
the threat model fits their actual adversary before they trust the system.
|
||
|
||
If your adversary is on the "out of scope" list below, **use a different
|
||
tool**. veilor-os will not save you, and we will not pretend otherwise.
|
||
|
||
---
|
||
|
||
## In scope — what veilor-os defends against
|
||
|
||
Every row cites the file or setting that implements the mitigation, so the
|
||
claim is auditable from a clean checkout.
|
||
|
||
| Adversary / scenario | veilor-os mitigation |
|
||
|---|---|
|
||
| Lost or stolen laptop, powered off | LUKS2 `aes-xts-plain64` + `argon2id` (`mem=1 GiB`, `time=9`) on root LV; swap is `zram` only — no persistent key material on disk. Defined in `kickstart/veilor-os.ks` `part pv.veilor` block. |
|
||
| Generic browser / email malware (drive-by RCE, malicious attachment) | SELinux `enforcing` + targeted policy + custom `veilor-systemd.te` module (`scripts/selinux/`); sysctl knobs in `/etc/sysctl.d/99-veilor-hardening.conf`: `kernel.kptr_restrict=2`, `kernel.yama.ptrace_scope=2`, `kernel.perf_event_paranoid=3`, `net.core.bpf_jit_harden=2`, `kernel.randomize_va_space=2`, `fs.suid_dumpable=0`, `dev.tty.ldisc_autoload=0`. AppArmor profile skeletons in `scripts/apparmor/` for Trivalent/Thorium/lm-studio (opt-in, complain mode, hardens to enforce per profile). |
|
||
| Console-side USB attack (BadUSB, rubber ducky, juice-jack) | USBGuard daemon, `ImplicitPolicyTarget=block`, **id-based** rules in `/etc/usbguard/rules.conf` (vendor:product, not hash — survives dock replug). Empty allowlist on first boot; operator runs `usbguard generate-policy` after plugging trusted devices. |
|
||
| SSH brute-force / credential-stuffing | `/etc/ssh/sshd_config.d/10-veilor-hardening.conf`: `PasswordAuthentication no`, `PermitRootLogin no`, `AllowUsers admin`, `MaxAuthTries 3`, `X11Forwarding no`, `LogLevel VERBOSE`. `fail2ban` `sshd` + `pam-generic` jails (journald backend) ban via firewalld `rich-rule` action. |
|
||
| Post-incident forensics ("what happened?") | `auditd` rules in `/etc/audit/rules.d/99-veilor-hardening.rules` watch `/etc/{passwd,shadow,group,sudoers,sudoers.d,ssh/sshd_config*,selinux,firewalld,cron.*,sysctl.*,systemd/system}`, every privileged binary (`sudo`, `su`, `passwd`, `mount`, `pkexec`, …), `init_module`/`finit_module`/`delete_module` syscalls, and uid≥1000 perm/owner changes. Logs persist across reboot. |
|
||
| Supply-chain on the OS image itself | Secure Boot enforced (Fedora signed shim → GRUB → kernel). v0.7 adds cosign-signed OCI image at `ghcr.io/veilor/veilor-os:43`, GPG-signed ISO + sha256 + .asc, plus our own MOK for out-of-tree module signing. |
|
||
| Unprivileged local user attempting LPE | Root account locked (`passwd -l root`; `passwd -S root` → `L`); single `admin` user in `wheel`; `pwquality.conf` `minlen=14`, `minclass=4`, dictcheck on. Kernel `lockdown=integrity`, `slab_nomerge`, `init_on_alloc=1`, `init_on_free=1`, `randomize_kstack_offset=on`, `vsyscall=none` set in bootloader args. Module loading frozen 30 s after graphical boot via `veilor-modules-lock.service`. |
|
||
| Network-listening services as attack surface | `firewalld` default zone = `drop`; only `sshd` answers. `abrt*`, `cups`, `cups-browsed`, `geoclue`, `avahi-daemon`, `bluetooth`, `ModemManager`, `gssproxy`, `atd`, `pcscd.{socket,service}` are masked; `kdeconnectd` and `PackageKit` are removed at the package level. |
|
||
| Time-based MITM (back-dated certs, replay) | `chrony` with NTS authentication against `time.cloudflare.com` and `nts.sth1/2.ntp.se` (pool fallback only). `systemd-resolved` with DNS-over-TLS opportunistic, DNSSEC `allow-downgrade`, LLMNR off; resolvers Cloudflare 1.1.1.1 / 1.0.0.1, fallback Quad9 9.9.9.9 / 149.112.112.112. |
|
||
|
||
---
|
||
|
||
## Out of scope — what veilor-os does NOT defend against
|
||
|
||
These adversaries are unambiguously outside our scope. Pretending otherwise
|
||
gets people hurt. **If your adversary is on this list, pick a different tool.**
|
||
|
||
| Adversary / scenario | Why veilor-os doesn't help | Use instead |
|
||
|---|---|---|
|
||
| Firmware-level implant (UEFI, Intel ME, BMC, EC) | veilor-os does not protect against firmware implants. Secure Boot validates the OS chain only; we do not flash, audit, or sign firmware below GRUB. | Heads / coreboot on supported hardware. |
|
||
| Evil-maid attack on a running, unlocked system | LUKS master keys live in RAM while the system is up. A physically present attacker can dump RAM (cold-boot, Thunderbolt DMA, debug header) and recover them. | Power off when unattended. Disable Thunderbolt DMA in firmware. Qubes-in-a-Faraday-bag if you are that target. |
|
||
| Hardware keylogger / interposer between keyboard and machine | veilor-os is software. Software cannot detect a passive hardware tap. | Physical custody of the device. Tamper-evident seals. |
|
||
| Targeted RCE on the user session (browser 0-day, messenger exploit) | KDE Plasma is not sandboxed. A logged-in compromise owns the user's data and tokens. SELinux confines daemons; it does not confine the desktop session. | Qubes OS (per-app Xen VM isolation). |
|
||
| Side-channel attacks on AES (timing, cache, power, EM) | veilor-os ships stock kernel crypto. We provide no constant-time or power-analysis guarantees beyond what the kernel and CPU deliver. | Threat-specific HSM, air-gap. |
|
||
| Physical attack on a TPM2 chip (bus probe, glitch, decap) | veilor-os does not bind keys to TPM2 in v0.7. Even when binding lands post-v1.0, TPM2 is not anti-tamper hardware. | Off-device key custody (smartcard / YubiKey / OnlyKey). |
|
||
| Network-level traffic correlation / traffic analysis | All packets leave the box on the local IP. veilor-os does not onion-route. | Tails, Whonix, Tor. |
|
||
| Trust-on-first-use attacks (operator accepts a bad cert) | veilor-os cannot override the operator's explicit decisions. Bad SSL or SSH host-key acceptance is out of scope. | Enrolment policy, MDM, certificate pinning. |
|
||
| Adversary with sustained physical access and time | Given unlimited physical time and tools, any laptop falls. | Operational security, not OS choice. |
|
||
|
||
---
|
||
|
||
## Hardening tradeoffs (what you give up)
|
||
|
||
Hardening that breaks ordinary work gets called out, not hidden.
|
||
|
||
- **SELinux enforcing** — some apps (proprietary, out-of-tree) ship
|
||
without policy. Symptom: `EACCES` despite correct file perms.
|
||
Workaround: write a local policy module; do not switch to permissive.
|
||
- **LUKS2 argon2id (mem=1 GB / time=9)** — boot 5–30 s slower on older
|
||
CPUs. The cost of a passphrase that survives a GPU attacker.
|
||
- **USBGuard default-block** — every new device needs an explicit allow.
|
||
First-boot: plug trusted devices in, run `usbguard generate-policy`.
|
||
Forget this and your USB-C dock looks broken.
|
||
- **Module lockdown 30 s after graphical boot** — out-of-tree drivers
|
||
(NVIDIA proprietary, VirtualBox, out-of-tree wireguard) will fail.
|
||
Load early via initramfs or use the in-tree alternative.
|
||
- **firewalld zone = drop** — KDE Connect, mDNS printer discovery, SMB
|
||
browsing don't work until explicitly opened. This is the point.
|
||
- **No PackageKit / no Flatpak by default** — updates happen on your
|
||
terms via `dnf upgrade`.
|
||
|
||
---
|
||
|
||
## Where veilor-os IS like Tails / Whonix / Qubes
|
||
|
||
- Threat model published. Transparency about scope is the price of being
|
||
taken seriously.
|
||
- Default-deny firewall (`drop` zone, ssh inbound only).
|
||
- Encrypted at rest by default — LUKS2 + argon2id, no-disk-swap (zram).
|
||
|
||
## Where veilor-os DIFFERS
|
||
|
||
- **Daily-driver target.** Boot it once, install it, use it for years.
|
||
Not a session-only / amnesia OS.
|
||
- **Single-VM / single-kernel.** No per-app compartmentalisation. A
|
||
browser RCE owns your session. (See "out of scope".)
|
||
- **Persistent identity by design.** Your `~`, your keys, your shell
|
||
history persist. This is a feature for an operator, a misfeature for
|
||
an activist evading correlation.
|
||
|
||
---
|
||
|
||
## Comparison matrix
|
||
|
||
Scoring legend: `✓` shipped & on by default, `~` partial / opt-in,
|
||
`✗` not provided, `n/a` not applicable to that distro's model.
|
||
Project metrics are GitHub / Codeberg figures as of 2026-05.
|
||
|
||
| Axis | veilor-os | Stock Fedora KDE | Kicksecure | Tails | Qubes OS | secureblue | Athena OS |
|
||
|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||
| **Encrypted at rest by default** | ✓ (LUKS2 argon2id, mem=1 GiB) | ~ (optional in Anaconda) | ✓ | n/a (amnesic, session-only) | ✓ | ✓ | ~ (optional) |
|
||
| **MAC enforcing OOTB** | ✓ (SELinux + opt-in AppArmor) | ✓ (SELinux) | ✓ (AppArmor) | ✓ (AppArmor) | ✓ (per-VM) | ✓ (SELinux) | ✓ (AppArmor) |
|
||
| **Default-deny firewall** | ✓ (firewalld zone=drop) | ✗ | ✓ | ✓ (Tor-only) | ✓ | ✓ | ✓ |
|
||
| **USB default-block** | ✓ (USBGuard, id-rules) | ✗ | ✓ | ✓ | ✓ (sys-usb) | ✓ (USBGuard) | ✗ |
|
||
| **Per-app isolation (VM/sandbox)** | ✗ | ✗ | ✗ | ~ (AppArmor) | ✓ (Xen VMs) | ~ (Flatpak/bwrap) | ✗ |
|
||
| **Anonymity / Tor by default** | ✗ | ✗ | ✗ | ✓ | ~ (Whonix VMs) | ✗ | ✗ |
|
||
| **Daily driver target (persistent)** | ✓ | ✓ | ✓ | ✗ (amnesic) | ✓ (heavy, hardware-partitioning) | ✓ | ✓ |
|
||
| **Signed releases (cosign + GPG)** | ✓ (v0.7) | ✓ | ✓ | ✓ | ✓ | ✓ (cosign on OCI) | ~ (sha256 only) |
|
||
| **Threat model published** | ✓ (this doc) | ✗ | ✓ | ✓ | ✓ | ✗ | ✓ |
|
||
| **Hardware compatibility (laptops)** | ✓ (Fedora kernel) | ✓ | ~ | ~ (live USB) | ~ (Xen-pinned HCL) | ✓ | ✓ (Arch kernel) |
|
||
| **Project size (contributors / stars, 2026-05)** | solo / pre-public | n/a (Fedora-wide) | small team / ~600 | ~30 / ~3k | large / ~5k | ~30 / ~940, active monthly cadence | ~8 / ~1.4k |
|
||
|
||
---
|
||
|
||
## Where veilor-os fits
|
||
|
||
Pick veilor-os if your job is to write code, edit docs, manage
|
||
infrastructure, read mail, browse — and you want a desktop that won't
|
||
quietly betray you to a generic adversary while you do it. **You are the
|
||
user, not the target of a state.**
|
||
|
||
Pick **Tails** for amnesia and Tor by default. **Qubes** if you must assume
|
||
any app could be compromised. **Kicksecure** for similar hardening on
|
||
Debian. **secureblue** for a hardened atomic Fedora. **Stock Fedora KDE**
|
||
if you just want Fedora with no opinions.
|
||
|
||
---
|
||
|
||
## v0.7 public-launch checklist
|
||
|
||
These are the items that gate flipping the repo public and posting:
|
||
|
||
- [ ] Threat model finalised and published (this document).
|
||
- [ ] GPG-signed releases working (v0.4 dependency — ISO + sha256 + .asc).
|
||
- [ ] Reproducible build verifiable from clean checkout (v0.4).
|
||
- [ ] mkdocs-material (or Hugo) site live on `veilor.org`, generated from
|
||
`docs/`. INSTALL, HARDENING, BUILD, ROADMAP, RELEASE, THREAT-MODEL,
|
||
CONTRIBUTING all rendered.
|
||
- [ ] Comparison + benchmark numbers published (cold boot, idle RAM, idle
|
||
egress, suspend/resume) vs stock Fedora KDE.
|
||
- [ ] Press kit page: wallpapers, logo SVG, screenshots, feature
|
||
one-liner, signed quotes from early users.
|
||
- [ ] **"What veilor-os is not"** preempt page — direct link from launch
|
||
post. Answers "why not Qubes?", "why not Tails?", "why not just
|
||
stock Fedora?" so the first hundred comments don't have to.
|
||
- [ ] Comparison post drafted for **r/linux**, **r/Fedora**, **HN**.
|
||
Same body, three formats. Lead with the threat model link, not the
|
||
black wallpaper.
|
||
- [ ] CHANGELOG.md tagged at v0.7.0 release commit; GitHub Release
|
||
created with ISO + sha256 + .asc artefacts attached.
|
||
- [ ] Repo flipped to public, `veilor.org` DNS pointed at the docs site,
|
||
Mastodon / Matrix / SimpleX announcement queued.
|
||
|
||
---
|
||
|
||
*Last reviewed: v0.7 draft. Update every minor release.*
|