-
Notifications
You must be signed in to change notification settings - Fork 0
Security
slacker is fail-closed: a bad signature or a failed integrity check stops the operation, it never warns-and-continues. Verification, key pinning, and a quarantine model work together.
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#161b22','primaryBorderColor':'#1f6feb','primaryTextColor':'#e6edf3','lineColor':'#6e7781','fontFamily':'monospace'}}}%%
flowchart TB
U["slacker update"]:::blue --> G{"CHECKSUMS.md5<br/>vs its .asc signature"}
G -->|good| OK["metadata accepted"]:::green
G -->|bad / key changed| DROP["metadata discarded,<br/>repo warned, others continue"]:::grey
I["install a package"]:::blue --> V{"per-package check<br/>(policy = VERIFY)"}
V -->|".txz.asc GPG"| VG["verified: gpg"]:::green
V -->|"md5 / sha"| VM["integrity verified"]:::green
V -->|"nothing available"| STOP["install stops"]:::grey
classDef grey fill:#0d1117,stroke:#6e7781,color:#8b949e;
classDef blue fill:#0d1117,stroke:#1f6feb,color:#e6edf3;
classDef green fill:#0d1117,stroke:#2ea043,color:#e6edf3;
Once a repo's key is imported, slacker verifies its CHECKSUMS.md5 against the
detached signature on every update. If that signature is bad or the key is
missing, the repo is not aborted wholesale: slacker warns, discards that repo's
freshly-fetched metadata so it is never used unverified, and continues with the
others - then tells you how to proceed if you trust the repo anyway.
Each package is checked according to the repo's policy. Slackware ships a
per-package .txz.asc, so under the default all policy slacker also
GPG-verifies the package itself when a signature is present (falling back to
the md5 from the signature-verified CHECKSUMS otherwise), and prints which
checks passed (e.g. verified: gpg (signer) + md5). At least one of gpg/md5/sha
must pass; if none is available, the install stops.
Set globally in slacker.conf and overridable per repo with a verify= flag in
repos.
| Policy | Behaviour |
|---|---|
all (default)
|
GPG verified when present (a bad signature always fails); at least one integrity checksum (md5 or sha) must match. If neither is available, install stops. |
gpg,md5,sha (a required list)
|
Requires every listed method; if one is absent slacker stops and explains how to relax it. |
none |
Disables verification - slacker prints a warning after update and in check-updates naming that repo. Applies to file:// repos too. |
The official repo gets no exemption - official only affects install-new
scope and ChangeLog tracking, never verification.
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#161b22','primaryBorderColor':'#1f6feb','primaryTextColor':'#e6edf3','lineColor':'#6e7781','fontFamily':'monospace'}}}%%
flowchart LR
F["first GPG-KEY import"]:::green --> PIN["fingerprint pinned"]:::blue
PIN --> L{"later import:<br/>same fingerprint?"}
L -->|yes| OK["accepted"]:::green
L -->|no| REJ["refused -<br/>possible key substitution"]:::grey
classDef grey fill:#0d1117,stroke:#6e7781,color:#8b949e;
classDef blue fill:#0d1117,stroke:#1f6feb,color:#e6edf3;
classDef green fill:#0d1117,stroke:#2ea043,color:#e6edf3;
The first time a repo's GPG-KEY is imported, slacker pins its fingerprint.
On every later import the fetched key must match the pinned one; a changed or
substituted key is refused as a possible attack rather than trusted silently.
For a subtree repo the key is fetched from the parent/root URL, where
Slackware keeps the one key that signs the whole tree - so extra/testing/
patches pin the same fingerprint as the official repo.
Run slacker update gpg once before trusting a mirror.
A GPG or checksum signature authenticates who built a package, not which
Slackware release it targets. So a repo left pointing at the wrong release - a
classic example is an alienbob -current repo still active on a 15.0 system - can
verify perfectly yet install packages that break the system. Before any install
or upgrade, slacker refuses a package whose source repo targets a different
release than the running system (read from /etc/os-release), naming the
offenders; status reports the same mismatch on its Repo release row. Pass
--yes to override when you are sure. A distribution upgrade (upgrade-dist)
changes the release on purpose and is exempt - it is the supported way to cross
that boundary. See Distribution Upgrade.
A repository that fails vetting - unreachable, or serving metadata that looks malformed or hostile - is put into quarantine and provides no packages until you act.
| Command | What it does |
|---|---|
vet-repo NAME |
Re-run the safety vetting on demand (quarantine on fail, clear on pass). |
trust-repo NAME |
Lift a quarantine you judge a false positive (overriding the verdict, at your responsibility). |
distrust-repo NAME |
Manually quarantine (freeze) a repo yourself. |
A freshly added or as-yet-untrusted repo is light-vetted on the next
update; add-repo and vet-repo run a thorough vet. Quarantine state is shown
by list-repos and status.
Public Slackware mirrors need no login, and slacker fetches them anonymously.
For a repository that does require one - a private Forgejo/Gitea repo, an
authenticated mirror - slacker sends HTTP Basic credentials, modelled on
zypper: the secret lives in a file you control, never in the repos file.
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#161b22','primaryBorderColor':'#1f6feb','primaryTextColor':'#e6edf3','lineColor':'#6e7781','fontFamily':'monospace'}}}%%
flowchart LR
R["repo needs a login"]:::blue --> F{"credentials= NAME<br/>flag on the repo?"}
F -->|yes| N["credentials.d/NAME"]:::green
F -->|no| C{"longest matching prefix<br/>in credentials.cat?"}
C -->|match| CAT["that section's login"]:::green
C -->|none| A["anonymous"]:::grey
classDef grey fill:#0d1117,stroke:#6e7781,color:#8b949e;
classDef blue fill:#0d1117,stroke:#1f6feb,color:#e6edf3;
classDef green fill:#0d1117,stroke:#2ea043,color:#e6edf3;
Two ways to supply a login, both under /etc/slacker:
-
Named set - a file
credentials.d/NAMEholding oneusername/passwordpair, referenced from a repo line with thecredentials=NAMEflag (zypper's?credentials=). The flag carries only the name, never the secret:80 myforge https://forge.slackware.nl/rizitis/myrepo credentials=forge -
Global catalogue -
credentials.catwith one[url-prefix]section per login; any repo whose URL begins with a prefix uses that section, no flag needed.
Lookup per repo: the credentials=NAME flag first, else the longest matching
catalogue prefix, else anonymous.
| Guarantee | How |
|---|---|
| Never in the repo list | the repos line holds only the name (or nothing - the catalogue matches by URL) |
| Never in a URL | the user:pass@host form is unsupported on purpose - it leaks into logs and the process list |
| Never logged or printed | on a failed fetch the URL is shown without credentials |
| In transit only | sent solely as an Authorization: Basic header, to the matching repo |
A credential file is honoured only when it is a regular file owned by
root with no group or other permission bits (chmod 600, chown root:root). Anything looser is refused with a warning and the repo is
fetched anonymously - a mis-permissioned secret never silently leaks, exactly as
ssh refuses a world-readable private key. Keep the directory itself 0700 so
the file names stay invisible to non-root users.
This is the same model apt (/etc/apt/auth.conf.d) and zypper
(/etc/zypp/credentials.d) use: plain files under /etc, protected by
permissions, not encrypted in place. Encryption at rest would only re-lock
what root can already read; offline protection is the job of full-disk
encryption (LUKS), not the package manager.
Credentials are sent over https only, so the login is never exposed on the
wire. A repository whose URL is plaintext http does not receive them, and
add-repo refuses to add a credentials= repo over http. This matches apt,
which by default matches credentials to https only.
The escape hatch is the per-repo insecure flag - an explicit,
at-your-own-risk override (like trust-repo for a quarantine, or verify=none
for verification):
55 local http://10.0.0.9/repo credentials=lab insecure
With insecure, credentials are sent over http for that repo (with a
warning), and vetting no longer freezes it for its plaintext transport - the user
opted into that risk. GPG/checksum verification still applies. Without insecure,
a hand-written http credentials= line simply has its credentials withheld.
Either state is surfaced by status (the Credentials row) and by
list-repos (which shows the (credentials=NAME) and (insecure) flags).
Verification, key pinning, and quarantine are only worth their current state on
the box. slacker status is how you check that the machinery on this page is
actually intact and active, not merely configured. The security-relevant rows
it prints (see Commands for the full report):
| Row | What it proves |
|---|---|
| Verify | every repo verifies packages, or it names the ones where verify=none has switched it off |
| Transport | every repo uses https/file, or it names a plaintext-http repo a MITM could tamper with |
| Credentials | flags any repo carrying credentials= over plaintext http - red when they are withheld (no insecure), yellow when insecure forces them onto the wire at your own risk |
| Repo release | every repo targets the running system's Slackware release, or it names a repo built for a different one - a mismatch normal installs refuse (a signature proves who built a package, not which release it targets) |
| Repo trust | which repos are frozen - hard (failed vetting, needs trust-repo) or soft (unreachable, auto-retried) - each with its reason |
| GPG keys | the keyring is actually exercised: every repo's cached CHECKSUMS.md5 signature is re-verified, reporting a BAD signature (tampering), no imported key verifies, or how many repos verify (+N via md5). Root only. |
A repo verifies under any pinned key, so
extra/testing/patchesshow as verified off the single official key they share - exactly as pinning intends.
The pinned fingerprints and the trusted/quarantine markers are files under
STATE_DIR (default /var/lib/slacker), kept separate from the disposable
CACHE_DIR so that clearing the cache can never destroy the trust anchors.
Anyone who could rewrite them would defeat key pinning and the quarantine model
before a single signature was checked. So status audits slacker's own
config + cache + state, not just the repos:
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#161b22','primaryBorderColor':'#1f6feb','primaryTextColor':'#e6edf3','lineColor':'#6e7781','fontFamily':'monospace'}}}%%
flowchart TB
C["STATE_DIR holds the trust state:<br/>pinned fingerprints + trusted/quarantine markers"]:::blue --> T{"tampered?<br/>world-writable / stray symlink"}
T -->|"yes, undetected"| BAD["pinning & quarantine defeated<br/>before any check runs"]:::grey
T -->|"status audit"| DET["lstat walk, never follows a link -<br/>flagged with the exact chown/chmod fix"]:::green
classDef grey fill:#0d1117,stroke:#6e7781,color:#8b949e;
classDef blue fill:#0d1117,stroke:#1f6feb,color:#e6edf3;
classDef green fill:#0d1117,stroke:#2ea043,color:#e6edf3;
✗ Symlinks 1 unexpected symlink(s) - slacker plants none here; investigate
before trusting the state: /var/lib/slacker/gpg/slackware.fpr -> /tmp/x.fpr
✗ Writable 1 world-writable path(s) - anyone can tamper (e.g. /var/lib/slacker/gpg);
fix: sudo chmod -R go-w /etc/slacker /var/cache/slacker /var/lib/slacker
It flags world-writable, group-writable, and not-root-owned paths, and
any unexpected symlink (slacker creates none under these paths). The walk uses
lstat and never follows a symlink, so a planted link cannot lure the audit
outside the tree - only the roots themselves are followed. Every finding carries
the exact chown/chmod to fix it.
status turns "configured to be secure" into "verified secure, right now." It
is the one command that proves the fail-closed checks are live, surfaces a bad
signature as an explicit advisory ("do NOT install from it until resolved"), and
protects the integrity of the very state - pinned keys, trust markers - that
everything above depends on.
Run slacker status after every update, and sudo slacker status for the
full GPG verification and integrity audit (the keyring and markers are root-only
to read).
slacker - slackpkg + slackpkg+ in one - Apache-2.0 - by Ioannis Anagnostakis (rizitis) - beta / WIP, for Slackware -current (64-bit & 32-bit)
Getting started
Using slacker
- Commands
- Common Workflows
- Distribution Upgrade
- Repositories and Priority
- Package History
- Dependencies
- Docker
- Templates
- Blacklist
Trust & safety
Reference
For contributors