DriveStage/SECURITY.md

170 lines
7.7 KiB
Markdown
Executable File

# Security Policy
## Supported versions
drivestage is pre-1.0 software. Only the most recent minor release line
receives security fixes.
| Version | Supported | Notes |
|---------|--------------------|--------------------------------------|
| 0.2.x | :white_check_mark: | Current release line |
| 0.1.x | :x: | EOL — upgrade to 0.2.x |
| < 0.1 | :x: | Never released |
When 0.4.0 ships, 0.2.x will move to a 30-day security-only window before EOL.
---
## Reporting a vulnerability
**Do not open a public GitHub issue for security vulnerabilities.**
Email vulnerability reports to **[security@dcos.net](mailto:security@dcos.net)**.
Please include:
1. A description of the issue and its impact.
2. The exact `blkstage.sh` subcommand(s) or GUI flow involved.
3. Reproduction steps (commands, ISO filenames, device path).
4. The output of `blkstage.sh --version`.
5. Your distro, kernel, and (if relevant) Rust toolchain version.
6. Any suggested remediation.
You will receive an acknowledgement within **5 business days**. If you do not,
follow up — the maintainer may be offline.
### Coordinated disclosure
We follow a **90-day coordinated disclosure** timeline:
| Day | Action |
|------|-------------------------------------------------------------------|
| 0 | Reporter emails `security@dcos.net` |
| ≤ 5 | Maintainer acknowledges receipt |
| ≤ 14 | Maintainer triages and assigns a severity (see below) |
| ≤ 30 | Maintainer proposes a fix or mitigation; reporter reviews |
| ≤ 60 | Fix lands on a maintenance branch and a patch release is cut |
| ≤ 90 | Public advisory published (CVE requested if eligible) |
If a fix is delayed, the reporter is kept informed at each milestone. Reporters
who wish to extend the 90-day window are encouraged to ask — extensions are
granted in good faith.
### Severity
We use [CVSS v3.1](https://www.first.org/cvss/calculator/3.1). Examples
relevant to this project:
| Severity | Example |
|-----------|----------------------------------------------------------------------------------|
| Critical | Script wipes the OS disk on a non-USB device under any input |
| High | Sudo password leaks to disk, logs, or another process |
| Medium | A distro-detection false negative causes the wrong kernel args on a known ISO |
| Low | Cosmetic information leak (e.g. device serial printed to stdout) |
---
## Threat model
drivestage is a **disk-destroying, privilege-elevating** tool. Treat it
with the same caution as `dd`, `mkfs`, or `parted`. The realistic threats are:
1. **Wrong-device wipe.** The user runs `setup` against a path that turns out
to be the OS disk, an LVM member, or a LUKS-backed device. Data loss is
total and unrecoverable.
2. **Credential exposure.** The GUI captures the user's sudo password to run
the engine. A leak (logs, core dump, swap, /proc/<pid>/environ) discloses
it to other local users or to anyone with later physical access.
3. **Tampered config file.** `blkstage.sh` sources an optional
`CONF_FILE` (`/etc/drivestage.conf`). A world-writable or non-root-owned
conf file is a local privilege escalation vector — any user could plant
shell that runs as root on the next invocation.
4. **Concurrent invocation.** Two `setup` or `deploy` runs racing on the same
device produce a corrupted partition table or half-written GRUB image.
5. **Hostile ISO payloads.** The tool copies ISO files verbatim. It does not
inspect ISO contents. Booting a malicious ISO is the user's responsibility
— but the tool must not silently boot a different ISO than the one the user
selected.
6. **CI/supply-chain.** A compromised dependency in `Cargo.lock` could ship
malicious code into the GUI binary.
The tool is **not** designed to defend against an attacker with write access
to the drivestage installation itself (`/usr/local/bin/drivestage`,
`/usr/local/lib/drivestage/`, or the git checkout). At that point the
attacker already has the privileges the tool runs with.
---
## Security measures in place
The following mitigations are present in 0.2.x. Each is documented in
[`CHANGELOG.md`](./CHANGELOG.md) and tested where feasible.
### Disk safety
- **`guard_root_disk`** refuses to operate on the device hosting `/`. It walks
the `lsblk PKNAME` chain so it also catches the OS disk when root sits on
LVM, LUKS, or mdadm. A second check blocks any device whose `PKNAME` chain
mentions `crypt`, `lvm`, `md`, or `dm-`.
- **Typed confirmation.** `setup` requires the user to type the device name
verbatim before any destructive operation begins.
- **Recursive unmount.** `unmount_all` uses `umount -R` so nested mounts under
`/mnt/drivestage/*` are cleaned up before re-partitioning.
- **Free-space check.** `deploy_payload` verifies sufficient free space on the
payloads partition before invoking `rsync`.
- **Cleanup trap.** A trap on `EXIT`/`INT`/`TERM` calls `unmount_all` so a
Ctrl-C mid-deploy doesn't leave partitions mounted and confusingly writable.
### Credential handling
- **`Zeroizing<String>`** wraps the sudo password in the GUI (`core/sudo.rs`).
The string is zeroized on drop — never written to logs, never serialized,
never sent across an IPC channel that persists.
- **`flock`-based single-instance lock.** Concurrent invocations are refused
with an explicit error rather than racing on shared state.
- **No password on the command line.** The script never accepts a password as
an argument or environment variable; the GUI passes it through `sudo -S`'s
stdin only.
### Configuration file safety
- **`CONF_FILE` ownership and mode validation.** Before sourcing
`/etc/drivestage.conf`, the script verifies:
- Owner is `root:root`.
- Mode is `0644` or stricter (no group/other write).
- File is a regular file (not a symlink, FIFO, or device node).
Failure aborts before sourcing.
### Build & supply chain
- **Pinned `Cargo.lock`.** The lockfile is committed; CI runs `--locked` for
test/build/clippy. A `cargo update` is a deliberate, reviewable change.
- **Dependabot** opens PRs for cargo + GitHub Actions dependency updates on a
weekly cadence (see [`.github/dependabot.yml`](./.github/dependabot.yml)).
- **CI gate.** Every push and PR runs `fmt`, `clippy -D warnings`, `test`,
`build --release`, `shellcheck`, `bash-tests`, and MSRV check on Rust 1.75
and stable (see [`.github/workflows/ci.yml`](./.github/workflows/ci.yml)).
---
## Hardening recommendations for users
- Install the script to a root-owned, mode-0755 location
(`/usr/local/bin/drivestage`).
- If you use `/etc/drivestage.conf`, `chown root:root` it and `chmod 0644`
it. The script will refuse to source it otherwise.
- Run the GUI as your normal user, not as root. The GUI escalates via `sudo`
only when needed; running it as root skips the privilege boundary.
- Verify the device path with `lsblk` before each `setup`. The script's
`guard_root_disk` catches the OS disk — it does **not** catch a second data
disk you care about.
- Don't leave a drivestage stick plugged into a multi-user host. The
payloads partition is world-readable ext4 by default.
---
## Contact
- **Security reports:** [security@dcos.net](mailto:security@dcos.net)
- **General issues:** [GitHub Issues](https://git.dcos.net/dcosnet/DriveStage/issues)
- **Maintainer:** Jeremy Anderson <info@dcos.net> — [dcos.net](https://dcos.net)