sec: polish THREAT-MODEL.md for v0.7 public launch
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.
This commit is contained in:
parent
abb67841f1
commit
d0738970e0
1 changed files with 38 additions and 33 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
# Threat Model
|
# Threat Model
|
||||||
|
|
||||||
> **Status:** Draft for v0.7 public flex. Honest scope.
|
> **Status:** Final for v0.7 public launch. Honest scope.
|
||||||
|
|
||||||
veilor-os is a hardened daily-driver desktop. Not a paranoia OS, not an
|
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
|
anonymity OS, not an isolation OS. This document exists so that
|
||||||
|
|
@ -14,36 +14,39 @@ tool**. veilor-os will not save you, and we will not pretend otherwise.
|
||||||
|
|
||||||
## In scope — what veilor-os defends against
|
## 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 |
|
| Adversary / scenario | veilor-os mitigation |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Lost or stolen laptop, powered off | LUKS2 (aes-xts-plain64, argon2id, mem=1 GB) on root + swap-as-zram. Disk yields ciphertext. |
|
| 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 + `veilor-systemd` policy + sysctl hardening (kptr_restrict, ptrace=2, perf=3, BPF JIT harden, full ASLR, no SUID core dumps). AppArmor stack lands in v0.5. |
|
| 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, default-block, empty allowlist on first boot. New device = explicit operator allow. |
|
| 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 | sshd password-auth off, root login off, MaxAuthTries=3, fail2ban with sshd + pam-generic jails wired to firewalld rich-rule. |
|
| 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 covering passwd/shadow/sudoers/ssh/cron/sysctl/kernel modules and all privileged binaries. Logs survive reboot. |
|
| 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 | Fedora's signed shim → GRUB → kernel chain (Secure Boot enforced). v0.4 adds GPG-signed ISO + sha256 + own MOK. |
|
| 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 -S root` → `L`), single sudo user with pwquality minlen=14 / 4 classes, kernel module loading frozen 30 s after graphical boot. |
|
| 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/avahi/bluetooth/ModemManager/kdeconnectd/PackageKit are masked. |
|
| 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) | NTS-authenticated chrony, DNS-over-TLS via systemd-resolved, LLMNR off. |
|
| 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
|
## Out of scope — what veilor-os does NOT defend against
|
||||||
|
|
||||||
We are honest about this list because pretending otherwise is how people get
|
These adversaries are unambiguously outside our scope. Pretending otherwise
|
||||||
hurt. **If your adversary is here, pick a different tool.**
|
gets people hurt. **If your adversary is on this list, pick a different tool.**
|
||||||
|
|
||||||
| Adversary / scenario | Why veilor-os doesn't help | Use instead |
|
| Adversary / scenario | Why veilor-os doesn't help | Use instead |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Nation-state firmware-level implant (UEFI, ME, BMC) | Secure Boot validates the OS, not the firmware below it. We do not flash custom firmware. | Heads / coreboot on supported hardware. |
|
| 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 keys live in RAM while the system is up. A physically present attacker can dump RAM (cold boot, DMA via Thunderbolt, debug header). | Power off when unattended. Disable Thunderbolt DMA in firmware. Qubes-in-a-Faraday-bag if you're that target. |
|
| 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 / hardware mod between keyboard and machine | We're software. Software cannot detect a passive hardware tap. | Physical custody of the device. Tamper-evident seals. |
|
| 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, signal-app exploit) | KDE Plasma is not sandboxed. A logged-in compromise has the user's full data and tokens. SELinux confines daemons, not the desktop. | Qubes (per-app VM isolation). |
|
| 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 analysis) | We use stock kernel crypto. No constant-time guarantees beyond what the kernel/CPU provide. | Threat-specific HSM. |
|
| 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 (probe, glitch, decap) | We don't ship TPM2 binding yet. Even when v1.0 lands, TPM2 is not anti-tamper hardware. | Off-device key custody. |
|
| 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. We don't onion-route. | Tails, Whonix, Tor. |
|
| 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 (user clicks "accept bad cert") | We can't override the user's decisions. Bad SSL/SSH key acceptance by the operator is out of scope. | Enrolment policy, MDM. |
|
| 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 enough physical time and tools, any laptop falls. | Operational security, not OS choice. |
|
| Adversary with sustained physical access and time | Given unlimited physical time and tools, any laptop falls. | Operational security, not OS choice. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -92,19 +95,21 @@ Hardening that breaks ordinary work gets called out, not hidden.
|
||||||
|
|
||||||
Scoring legend: `✓` shipped & on by default, `~` partial / opt-in,
|
Scoring legend: `✓` shipped & on by default, `~` partial / opt-in,
|
||||||
`✗` not provided, `n/a` not applicable to that distro's model.
|
`✗` 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 |
|
| Axis | veilor-os | Stock Fedora KDE | Kicksecure | Tails | Qubes OS | secureblue | Athena OS |
|
||||||
|---|:---:|:---:|:---:|:---:|:---:|:---:|
|
|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
| **Encrypted at rest by default** | ✓ (LUKS2 argon2id) | ~ (optional) | ✓ | n/a (amnesic) | ✓ | ✓ |
|
| **Encrypted at rest by default** | ✓ (LUKS2 argon2id, mem=1 GiB) | ~ (optional in Anaconda) | ✓ | n/a (amnesic, session-only) | ✓ | ✓ | ~ (optional) |
|
||||||
| **MAC enforcing OOTB** | ✓ (SELinux + AppArmor v0.5) | ✓ (SELinux) | ✓ (AppArmor) | ✓ (AppArmor) | ✓ (per-VM) | ✓ (SELinux) |
|
| **MAC enforcing OOTB** | ✓ (SELinux + opt-in AppArmor) | ✓ (SELinux) | ✓ (AppArmor) | ✓ (AppArmor) | ✓ (per-VM) | ✓ (SELinux) | ✓ (AppArmor) |
|
||||||
| **Default-deny firewall** | ✓ | ✗ | ✓ | ✓ (Tor-only) | ✓ | ✓ |
|
| **Default-deny firewall** | ✓ (firewalld zone=drop) | ✗ | ✓ | ✓ (Tor-only) | ✓ | ✓ | ✓ |
|
||||||
| **USB default-block** | ✓ (USBGuard) | ✗ | ✓ | ✓ | ✓ (sys-usb) | ✓ |
|
| **USB default-block** | ✓ (USBGuard, id-rules) | ✗ | ✓ | ✓ | ✓ (sys-usb) | ✓ (USBGuard) | ✗ |
|
||||||
| **Per-app isolation (VM/sandbox)** | ✗ | ✗ | ✗ | ~ (AppArmor) | ✓ (Xen VMs) | ~ (Flatpak/bwrap) |
|
| **Per-app isolation (VM/sandbox)** | ✗ | ✗ | ✗ | ~ (AppArmor) | ✓ (Xen VMs) | ~ (Flatpak/bwrap) | ✗ |
|
||||||
| **Anonymity / Tor by default** | ✗ | ✗ | ✗ | ✓ | ~ (Whonix VMs) | ✗ |
|
| **Anonymity / Tor by default** | ✗ | ✗ | ✗ | ✓ | ~ (Whonix VMs) | ✗ | ✗ |
|
||||||
| **Daily driver target (persistent)** | ✓ | ✓ | ✓ | ✗ | ✓ (heavy) | ✓ |
|
| **Daily driver target (persistent)** | ✓ | ✓ | ✓ | ✗ (amnesic) | ✓ (heavy, hardware-partitioning) | ✓ | ✓ |
|
||||||
| **Signed releases (publisher key)** | ✓ (v0.4) | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| **Signed releases (cosign + GPG)** | ✓ (v0.7) | ✓ | ✓ | ✓ | ✓ | ✓ (cosign on OCI) | ~ (sha256 only) |
|
||||||
| **Threat model published** | ✓ (this doc) | ✗ | ✓ | ✓ | ✓ | ✓ |
|
| **Threat model published** | ✓ (this doc) | ✗ | ✓ | ✓ | ✓ | ✗ | ✓ |
|
||||||
| **Hardware compatibility (laptops)** | ✓ (Fedora kernel) | ✓ | ~ | ~ (live USB) | ~ (Xen-pinned) | ✓ |
|
| **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 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue