sec: AppArmor profile skeletons + audit shipping draft + veilor-firstboot SELinux module (#3)
Co-authored-by: veilor-org <admin@veilor.org>
This commit is contained in:
parent
8127f32868
commit
3cbffaf714
8 changed files with 609 additions and 5 deletions
|
|
@ -41,6 +41,21 @@ kickstart `%post` or the overlay tree shipped in `/etc`.
|
|||
`sys_admin` and `perfmon` capabilities required by the modules-lock
|
||||
service. Source: `scripts/selinux/veilor-systemd.te`.
|
||||
|
||||
### veilor-firstboot SELinux confinement
|
||||
|
||||
The first-boot password service is privileged (it has to write
|
||||
`/etc/shadow`) but small. Module `veilor-firstboot` carves a tight domain:
|
||||
|
||||
- Allowed: read `/etc/passwd`, exec `passwd(1)`, write
|
||||
`/var/lib/veilor-firstboot.done`, write `/etc/sddm.conf.d/`,
|
||||
start `sddm.service`.
|
||||
- `neverallow` rules block: network sockets (no phone-home),
|
||||
`home_root_t` / `user_home_t` access, `sys_module`, `sys_ptrace`,
|
||||
`sys_rawio`.
|
||||
|
||||
Source: `scripts/selinux/veilor-firstboot.te`. Build & load with
|
||||
`scripts/selinux/build-policy.sh` (loads all modules in one pass).
|
||||
|
||||
## Network surface
|
||||
|
||||
- **firewalld** default zone = `drop`.
|
||||
|
|
@ -119,6 +134,57 @@ sudo usbguard allow-device <id>
|
|||
`bluetooth`, `ModemManager`, `gssproxy`, `atd`, `pcscd.socket`,
|
||||
`pcscd.service`, `kdeconnectd` (removed at package level).
|
||||
|
||||
## AppArmor (v0.5)
|
||||
|
||||
Fedora 43 ships AppArmor alongside SELinux. veilor-os keeps SELinux as the
|
||||
primary MAC layer (enforcing, targeted) but ships AppArmor profile
|
||||
skeletons for high-risk userland binaries that benefit from a second,
|
||||
binary-scoped policy on top of SELinux's role-based one.
|
||||
|
||||
Profiles live in `scripts/apparmor/`:
|
||||
|
||||
| Profile | Target | Default mode |
|
||||
|---------|--------|--------------|
|
||||
| `usr.bin.thorium` | Thorium browser | `complain` |
|
||||
| `usr.local.bin.lm-studio` | LM Studio LLM runner | `complain` |
|
||||
| `usr.bin.veilor-power` | Power profile switcher | `enforce` |
|
||||
|
||||
Profiles are **not** loaded automatically — they are opt-in until v0.5.
|
||||
Enable a profile post-install with:
|
||||
|
||||
```bash
|
||||
sudo dnf install apparmor-utils apparmor-parser
|
||||
sudo install -m 0644 scripts/apparmor/usr.bin.thorium /etc/apparmor.d/
|
||||
sudo apparmor_parser -r /etc/apparmor.d/usr.bin.thorium
|
||||
sudo aa-complain /etc/apparmor.d/usr.bin.thorium # log only
|
||||
sudo aa-enforce /etc/apparmor.d/usr.bin.thorium # block
|
||||
```
|
||||
|
||||
Refine `complain`-mode profiles with `aa-logprof` after exercising the
|
||||
app through normal use; it converts logged denials into rule additions
|
||||
interactively.
|
||||
|
||||
## Audit log shipping (optional)
|
||||
|
||||
Local journald is the default audit sink. For off-device shipping to a
|
||||
trusted log collector (Loki / Wazuh / Splunk), veilor-os ships a
|
||||
disabled-by-default plugin template:
|
||||
|
||||
- `/etc/audit/plugins.d/veilor-remote.conf` — auditd plugin shim
|
||||
(set `active = yes` to enable).
|
||||
- `/etc/audisp/audisp-remote.conf.disabled` — audisp-remote target
|
||||
config template (rename to `audisp-remote.conf` and edit
|
||||
`remote_server` to enable).
|
||||
|
||||
**Warning:** enabling remote audit shipping leaks every privileged syscall,
|
||||
file-watch hit, and auth event off-device. Treat the collector as a host
|
||||
with the same trust level as root. Only enable if the collector itself is
|
||||
hardened and the transport is TLS or kerberized.
|
||||
|
||||
Reference integration paths in the template: Loki via promtail/vector
|
||||
syslog source, Wazuh via local wazuh-agent (no network shipping needed),
|
||||
Splunk via HEC bridge.
|
||||
|
||||
## What's *not* enabled by default
|
||||
|
||||
- **Disk swap** — replaced by zram (RAM-only, no key leak risk).
|
||||
|
|
|
|||
58
overlay/etc/audisp/audisp-remote.conf.disabled
Normal file
58
overlay/etc/audisp/audisp-remote.conf.disabled
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# veilor-os audisp-remote configuration template (DISABLED by default)
|
||||
#
|
||||
# IMPORTANT: enabling remote audit shipping leaks security events off-device.
|
||||
# Only enable if you have a trusted log collector — the remote endpoint
|
||||
# will receive every privileged syscall, file-watch hit, auth event, and
|
||||
# sudoers/SSH config change recorded by auditd.
|
||||
#
|
||||
# To activate:
|
||||
# 1. Set veilor-remote.conf `active = yes` (in /etc/audit/plugins.d/).
|
||||
# 2. Copy this file to /etc/audisp/audisp-remote.conf (drop `.disabled`).
|
||||
# 3. Edit `remote_server` + TLS settings below.
|
||||
# 4. systemctl restart auditd
|
||||
#
|
||||
# Loki / Wazuh / Splunk integration paths:
|
||||
#
|
||||
# Loki - point remote_server at a syslog-to-Loki shim (promtail or
|
||||
# vector with `syslog` source, format = "rfc5424"). Use TCP+TLS.
|
||||
# Wazuh - run wazuh-agent locally; it pulls /var/log/audit/audit.log
|
||||
# directly. In that case leave remote_server empty and rely on
|
||||
# wazuh-agent's filebeat-style tailer instead of audisp-remote.
|
||||
# Splunk - use a Splunk HEC bridge (rsyslog-omhttp or vector http sink).
|
||||
# audisp-remote speaks plain syslog/TLS; it does not speak HEC
|
||||
# natively.
|
||||
|
||||
# ---- transport ----
|
||||
remote_server = logs.example.org
|
||||
port = 60
|
||||
transport = tcp # plain | tcp | krb5
|
||||
queue_file = /var/spool/audit/remote.log
|
||||
mode = immediate # immediate | forwarding
|
||||
queue_depth = 10240
|
||||
format = managed # managed | ascii
|
||||
|
||||
# ---- TLS (transport = tcp + use_libwrap=no recommended) ----
|
||||
enable_krb5 = no
|
||||
krb5_principal =
|
||||
krb5_client_name = auditd
|
||||
krb5_key_file = /etc/audit/audit.key
|
||||
|
||||
# ---- failure handling ----
|
||||
network_failure_action = stop # ignore | syslog | exec | suspend | single | halt | stop
|
||||
disk_low_action = syslog
|
||||
disk_full_action = syslog
|
||||
disk_error_action = syslog
|
||||
remote_ending_action = reconnect
|
||||
generic_error_action = syslog
|
||||
generic_warning_action = syslog
|
||||
overflow_action = syslog
|
||||
|
||||
# ---- heartbeat ----
|
||||
heartbeat_timeout = 60
|
||||
network_retry_time = 1
|
||||
max_tries_per_record = 3
|
||||
max_time_per_record = 5
|
||||
|
||||
# ---- formatting ----
|
||||
# `managed` wraps each event in a syslog-RFC5424 header with veilor-os
|
||||
# hostname + audit facility (LOG_AUTHPRIV). Loki/Splunk prefer this.
|
||||
23
overlay/etc/audit/plugins.d/veilor-remote.conf
Normal file
23
overlay/etc/audit/plugins.d/veilor-remote.conf
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# veilor-os audit remote shipping (DISABLED by default)
|
||||
#
|
||||
# IMPORTANT: enabling remote audit shipping leaks security events off-device.
|
||||
# Only enable if you have a trusted log collector (Loki / Wazuh / Splunk).
|
||||
# The remote endpoint will see every privileged syscall, file watch hit,
|
||||
# auth event, and sudoers change. Treat the collector with the same trust
|
||||
# level as the host root account.
|
||||
#
|
||||
# Enable:
|
||||
# 1. Edit `active = yes` below.
|
||||
# 2. Configure /etc/audisp/audisp-remote.conf (see audisp-remote.conf.disabled).
|
||||
# 3. systemctl restart auditd.
|
||||
# 4. Verify with: auditctl -s | grep enabled
|
||||
#
|
||||
# Plugin pipes audit events out of auditd via a UNIX socket; audisp-remote
|
||||
# reads from that socket and forwards to the configured remote_server.
|
||||
|
||||
active = no
|
||||
direction = out
|
||||
path = builtin_af_unix
|
||||
type = builtin
|
||||
args = /var/run/audit_events
|
||||
format = string
|
||||
114
scripts/apparmor/usr.bin.thorium
Normal file
114
scripts/apparmor/usr.bin.thorium
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# veilor-os AppArmor profile — Thorium browser (Chromium fork)
|
||||
#
|
||||
# Scope:
|
||||
# Confine the Thorium browser binary at /usr/bin/thorium. Thorium is a
|
||||
# Chromium derivative; it sandboxes its own renderer/GPU/utility processes,
|
||||
# but the *browser* process itself runs with the full user's permissions
|
||||
# unless an MAC layer scopes it down. This profile is that scope.
|
||||
#
|
||||
# Mode:
|
||||
# complain — log violations to audit.log but do NOT block. This is the
|
||||
# first-fit profile; the user is expected to refine it from observed
|
||||
# denials before flipping to enforce. See `aa-logprof` to convert audit
|
||||
# denials into rule additions.
|
||||
#
|
||||
# Manual enable:
|
||||
# sudo install -m 0644 scripts/apparmor/usr.bin.thorium /etc/apparmor.d/
|
||||
# sudo apparmor_parser -r /etc/apparmor.d/usr.bin.thorium
|
||||
# sudo aa-complain /etc/apparmor.d/usr.bin.thorium # log only
|
||||
# sudo aa-enforce /etc/apparmor.d/usr.bin.thorium # block
|
||||
#
|
||||
# NOT enabled in kickstart by default. v0.5 work.
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
profile thorium /usr/bin/thorium flags=(complain) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/audio>
|
||||
#include <abstractions/dbus-session>
|
||||
#include <abstractions/fonts>
|
||||
#include <abstractions/freedesktop.org>
|
||||
#include <abstractions/gnome>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/openssl>
|
||||
#include <abstractions/X>
|
||||
|
||||
# ---- network: outbound HTTP/HTTPS only ----
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
network inet dgram, # DNS resolution
|
||||
network inet6 dgram,
|
||||
network netlink raw, # NetworkManager state queries
|
||||
deny network raw,
|
||||
deny network packet,
|
||||
deny network bluetooth,
|
||||
deny network can,
|
||||
deny network rds,
|
||||
deny network sctp,
|
||||
|
||||
# ---- binary + libs ----
|
||||
/usr/bin/thorium mr,
|
||||
/usr/lib/thorium/** mr,
|
||||
/usr/share/thorium/** r,
|
||||
/opt/thorium/** mr,
|
||||
/etc/thorium/** r,
|
||||
|
||||
# ---- per-user state ----
|
||||
owner @{HOME}/.config/thorium/** rwk,
|
||||
owner @{HOME}/.cache/thorium/** rwk,
|
||||
owner @{HOME}/.local/share/thorium/** rwk,
|
||||
|
||||
# ---- file pickers: only Downloads is writable ----
|
||||
owner @{HOME}/Downloads/ rw,
|
||||
owner @{HOME}/Downloads/** rwk,
|
||||
owner @{HOME}/Documents/ r,
|
||||
owner @{HOME}/Documents/** r,
|
||||
owner @{HOME}/Pictures/ r,
|
||||
owner @{HOME}/Pictures/** r,
|
||||
|
||||
# ---- /proc: own process only, deny memory peeking ----
|
||||
owner /proc/@{pid}/** r,
|
||||
deny /proc/*/mem rwk,
|
||||
deny /proc/*/maps r,
|
||||
deny /proc/sys/kernel/** w,
|
||||
|
||||
# ---- ptrace: forbidden ----
|
||||
deny ptrace,
|
||||
deny capability sys_ptrace,
|
||||
|
||||
# ---- kernel: no module load, no /dev/kmem, no /dev/mem ----
|
||||
deny capability sys_module,
|
||||
deny /dev/kmem rwk,
|
||||
deny /dev/mem rwk,
|
||||
deny /dev/port rwk,
|
||||
deny /sys/kernel/** w,
|
||||
|
||||
# ---- temp ----
|
||||
/tmp/ r,
|
||||
owner /tmp/** rwk,
|
||||
/var/tmp/ r,
|
||||
owner /var/tmp/** rwk,
|
||||
|
||||
# ---- system info read-only ----
|
||||
/etc/machine-id r,
|
||||
/etc/os-release r,
|
||||
/etc/localtime r,
|
||||
/sys/devices/system/cpu/** r,
|
||||
/sys/class/net/** r,
|
||||
|
||||
# ---- chrome sandbox helper (setuid/SUID-like child needs unconfined) ----
|
||||
/usr/lib/thorium/chrome-sandbox Cx -> sandbox,
|
||||
/usr/bin/xdg-open Pix,
|
||||
|
||||
profile sandbox {
|
||||
#include <abstractions/base>
|
||||
capability sys_admin,
|
||||
capability sys_chroot,
|
||||
capability sys_ptrace,
|
||||
/usr/lib/thorium/chrome-sandbox mr,
|
||||
/usr/lib/thorium/** mrix,
|
||||
/proc/*/setgroups w,
|
||||
/proc/*/uid_map w,
|
||||
/proc/*/gid_map w,
|
||||
}
|
||||
}
|
||||
78
scripts/apparmor/usr.bin.veilor-power
Normal file
78
scripts/apparmor/usr.bin.veilor-power
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# veilor-os AppArmor profile — veilor-power
|
||||
#
|
||||
# Scope:
|
||||
# Confine /usr/local/bin/veilor-power, the power profile switcher. The
|
||||
# script is small but invokes sudo to talk to tuned-adm; we want a tight
|
||||
# surface so a compromised user shell cannot abuse the sudoers entry to
|
||||
# pivot beyond profile switching.
|
||||
#
|
||||
# Mode:
|
||||
# enforce — this binary is ours, the surface is small, no need for a
|
||||
# complain runway. Verified rules at write time.
|
||||
#
|
||||
# Manual enable:
|
||||
# sudo install -m 0644 scripts/apparmor/usr.bin.veilor-power /etc/apparmor.d/
|
||||
# sudo apparmor_parser -r /etc/apparmor.d/usr.bin.veilor-power
|
||||
# sudo aa-enforce /etc/apparmor.d/usr.bin.veilor-power
|
||||
# # to debug:
|
||||
# sudo aa-complain /etc/apparmor.d/usr.bin.veilor-power
|
||||
#
|
||||
# NOT enabled in kickstart by default. v0.5 work.
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
profile veilor-power /usr/local/bin/veilor-power flags=(enforce) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/bash>
|
||||
#include <abstractions/consoles>
|
||||
|
||||
# ---- the script itself + bash ----
|
||||
/usr/local/bin/veilor-power r,
|
||||
/usr/bin/bash ix,
|
||||
/usr/bin/awk ix,
|
||||
/usr/bin/cat ix,
|
||||
|
||||
# ---- read CPU + ASUS sysfs for status ----
|
||||
/sys/devices/system/cpu/cpufreq/ r,
|
||||
/sys/devices/system/cpu/cpufreq/** r,
|
||||
/sys/devices/system/cpu/cpu*/cpufreq/ r,
|
||||
/sys/devices/system/cpu/cpu*/cpufreq/** r,
|
||||
/sys/devices/platform/asus-nb-wmi/ r,
|
||||
/sys/devices/platform/asus-nb-wmi/** r,
|
||||
|
||||
# ---- sudo handoff to tuned-adm ----
|
||||
/usr/bin/sudo Cx -> sudo_tuned,
|
||||
/usr/bin/tuned-adm Pix,
|
||||
|
||||
# ---- forbidden ----
|
||||
deny network,
|
||||
deny ptrace,
|
||||
deny capability sys_ptrace,
|
||||
deny capability sys_module,
|
||||
deny capability sys_rawio,
|
||||
deny /dev/kmem rwk,
|
||||
deny /dev/mem rwk,
|
||||
deny /etc/shadow r,
|
||||
deny /etc/sudoers w,
|
||||
deny /etc/sudoers.d/** w,
|
||||
deny @{HOME}/.ssh/** rwk,
|
||||
deny @{HOME}/.gnupg/** rwk,
|
||||
|
||||
# ---- child profile for the sudo subprocess ----
|
||||
profile sudo_tuned {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/authentication>
|
||||
#include <abstractions/nameservice>
|
||||
/usr/bin/sudo mr,
|
||||
/etc/sudoers r,
|
||||
/etc/sudoers.d/ r,
|
||||
/etc/sudoers.d/veilor-power r,
|
||||
/usr/bin/tuned-adm Pix,
|
||||
/var/log/sudo* w,
|
||||
/var/db/sudo/** rwk,
|
||||
capability setuid,
|
||||
capability setgid,
|
||||
capability audit_write,
|
||||
deny network,
|
||||
}
|
||||
}
|
||||
96
scripts/apparmor/usr.local.bin.lm-studio
Normal file
96
scripts/apparmor/usr.local.bin.lm-studio
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# veilor-os AppArmor profile — LM Studio (local LLM runner)
|
||||
#
|
||||
# Scope:
|
||||
# Confine LM Studio's binary. LM Studio loads arbitrary GGUF/safetensors
|
||||
# weights and exposes an OpenAI-compatible HTTP server on :1234. The
|
||||
# binary itself is closed-source — we don't trust it with the full home
|
||||
# directory.
|
||||
#
|
||||
# Mode:
|
||||
# complain initially. Flip to enforce once observed denials are reviewed.
|
||||
#
|
||||
# Manual enable:
|
||||
# sudo install -m 0644 scripts/apparmor/usr.local.bin.lm-studio /etc/apparmor.d/
|
||||
# sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.lm-studio
|
||||
# sudo aa-complain /etc/apparmor.d/usr.local.bin.lm-studio
|
||||
# sudo aa-enforce /etc/apparmor.d/usr.local.bin.lm-studio
|
||||
#
|
||||
# NOT enabled in kickstart by default. v0.5 work.
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
profile lm-studio /usr/local/bin/lm-studio flags=(complain) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/openssl>
|
||||
#include <abstractions/dbus-session>
|
||||
#include <abstractions/freedesktop.org>
|
||||
#include <abstractions/X>
|
||||
#include <abstractions/fonts>
|
||||
|
||||
# ---- network: HTTP server :1234 + outbound model downloads ----
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
network inet dgram,
|
||||
network inet6 dgram,
|
||||
deny network raw,
|
||||
deny network packet,
|
||||
deny network bluetooth,
|
||||
|
||||
# ---- binary + electron runtime (LM Studio is Electron-based) ----
|
||||
/usr/local/bin/lm-studio mr,
|
||||
/opt/lm-studio/** mr,
|
||||
/usr/lib/lm-studio/** mr,
|
||||
|
||||
# ---- model weights + metadata ----
|
||||
owner @{HOME}/.lmstudio/ rw,
|
||||
owner @{HOME}/.lmstudio/** rwk,
|
||||
owner @{HOME}/.cache/lm-studio/** rwk,
|
||||
owner @{HOME}/.config/LMStudio/** rwk,
|
||||
|
||||
# ---- temp ----
|
||||
/tmp/ r,
|
||||
owner /tmp/** rwk,
|
||||
/var/tmp/ r,
|
||||
owner /var/tmp/** rwk,
|
||||
|
||||
# ---- GPU device nodes (CUDA / ROCm / Vulkan) ----
|
||||
/dev/dri/ r,
|
||||
/dev/dri/** rw,
|
||||
/dev/nvidia* rw,
|
||||
/dev/nvidiactl rw,
|
||||
/dev/nvidia-uvm rw,
|
||||
/dev/nvidia-uvm-tools rw,
|
||||
/dev/kfd rw,
|
||||
/dev/shm/** rwk,
|
||||
|
||||
# ---- system info ----
|
||||
/etc/machine-id r,
|
||||
/etc/os-release r,
|
||||
/etc/localtime r,
|
||||
/sys/devices/system/cpu/** r,
|
||||
/sys/class/drm/** r,
|
||||
/proc/cpuinfo r,
|
||||
/proc/meminfo r,
|
||||
/proc/stat r,
|
||||
|
||||
# ---- /proc: own process only ----
|
||||
owner /proc/@{pid}/** r,
|
||||
deny /proc/*/mem rwk,
|
||||
|
||||
# ---- forbidden ----
|
||||
deny ptrace,
|
||||
deny capability sys_ptrace,
|
||||
deny capability sys_module,
|
||||
deny capability sys_rawio,
|
||||
deny /dev/kmem rwk,
|
||||
deny /dev/mem rwk,
|
||||
deny /dev/port rwk,
|
||||
deny /sys/kernel/** w,
|
||||
deny /etc/shadow r,
|
||||
deny @{HOME}/.ssh/** rwk,
|
||||
deny @{HOME}/.gnupg/** rwk,
|
||||
|
||||
# ---- xdg / browser handoff for "Open in browser" UI button ----
|
||||
/usr/bin/xdg-open Pix,
|
||||
}
|
||||
|
|
@ -1,10 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
# Build + load veilor-systemd SELinux policy module.
|
||||
# Build + load veilor-os SELinux policy modules.
|
||||
#
|
||||
# Modules:
|
||||
# veilor-systemd — capabilities for systemd-modules-load (post-boot lock)
|
||||
# veilor-firstboot — confine /usr/local/sbin/veilor-firstboot one-shot
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./build-policy.sh # build + install all
|
||||
# sudo ./build-policy.sh <name> # build + install one module
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
checkmodule -M -m -o veilor-systemd.mod veilor-systemd.te
|
||||
semodule_package -o veilor-systemd.pp -m veilor-systemd.mod
|
||||
semodule -i veilor-systemd.pp
|
||||
echo "[OK] veilor-systemd SELinux module loaded"
|
||||
MODULES=(veilor-systemd veilor-firstboot)
|
||||
if [[ $# -gt 0 ]]; then
|
||||
MODULES=("$@")
|
||||
fi
|
||||
|
||||
for m in "${MODULES[@]}"; do
|
||||
if [[ ! -f "$m.te" ]]; then
|
||||
echo "[ERR] $m.te not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[*] Building $m ..."
|
||||
checkmodule -M -m -o "$m.mod" "$m.te"
|
||||
semodule_package -o "$m.pp" -m "$m.mod"
|
||||
semodule -i "$m.pp"
|
||||
echo "[OK] $m loaded"
|
||||
done
|
||||
|
||||
# Apply file context for veilor-firstboot if module just loaded.
|
||||
if printf '%s\n' "${MODULES[@]}" | grep -qx veilor-firstboot; then
|
||||
if command -v restorecon >/dev/null 2>&1; then
|
||||
# Mark the binary + state file with the right types.
|
||||
semanage fcontext -a -t veilor_firstboot_exec_t '/usr/local/sbin/veilor-firstboot' 2>/dev/null || true
|
||||
semanage fcontext -a -t veilor_firstboot_state_t '/var/lib/veilor-firstboot\.done' 2>/dev/null || true
|
||||
restorecon -v /usr/local/sbin/veilor-firstboot 2>/dev/null || true
|
||||
[[ -e /var/lib/veilor-firstboot.done ]] && restorecon -v /var/lib/veilor-firstboot.done 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[done] all modules loaded"
|
||||
|
|
|
|||
136
scripts/selinux/veilor-firstboot.te
Normal file
136
scripts/selinux/veilor-firstboot.te
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
policy_module(veilor-firstboot, 1.0)
|
||||
#
|
||||
# veilor-os SELinux module — confine veilor-firstboot.service.
|
||||
#
|
||||
# The firstboot service runs once on TTY1 before SDDM, prompts for the
|
||||
# admin password, then enables SDDM and self-disables. It is privileged
|
||||
# (it must be — `passwd` writes /etc/shadow) but the surface is small and
|
||||
# bounded. This module narrows what the service is allowed to do so that a
|
||||
# bug or hostile env in firstboot.sh can't, e.g., dial out, scrape /home,
|
||||
# or load a kernel module.
|
||||
#
|
||||
# Build + load:
|
||||
# cd scripts/selinux
|
||||
# ./build-policy.sh # builds & loads all .te modules
|
||||
#
|
||||
# Verify:
|
||||
# semodule -l | grep veilor-firstboot
|
||||
# ls -Z /usr/local/sbin/veilor-firstboot
|
||||
# -> system_u:object_r:veilor_firstboot_exec_t:s0
|
||||
#
|
||||
# Audit any denials with:
|
||||
# ausearch -m AVC -ts recent -c veilor-firstboot
|
||||
|
||||
require {
|
||||
type init_t;
|
||||
type passwd_exec_t;
|
||||
type passwd_file_t;
|
||||
type shadow_t;
|
||||
type systemd_unit_file_t;
|
||||
type systemd_passwd_var_run_t;
|
||||
type sddm_unit_file_t;
|
||||
type sddm_var_lib_t;
|
||||
type tmp_t;
|
||||
type tty_device_t;
|
||||
type devtty_t;
|
||||
type self_runtime_t;
|
||||
type chkpwd_exec_t;
|
||||
type pam_var_run_t;
|
||||
type security_t;
|
||||
type fs_t;
|
||||
type usr_t;
|
||||
type bin_t;
|
||||
type lib_t;
|
||||
type etc_t;
|
||||
type proc_t;
|
||||
type unconfined_service_t;
|
||||
class file { read write create unlink getattr setattr open execute execute_no_trans map };
|
||||
class dir { read write add_name remove_name search getattr open };
|
||||
class chr_file { read write open getattr ioctl };
|
||||
class capability { setuid setgid chown dac_override dac_read_search fowner fsetid };
|
||||
class process { transition signal sigchld sigkill noatsecure rlimitinh siginh };
|
||||
class service { start stop status enable disable };
|
||||
class systemd { start };
|
||||
class lnk_file { read getattr };
|
||||
class filesystem { getattr };
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# 1. Define the firstboot domain + executable type
|
||||
# ---------------------------------------------------------------------
|
||||
type veilor_firstboot_t;
|
||||
type veilor_firstboot_exec_t;
|
||||
type veilor_firstboot_state_t; # /var/lib/veilor-firstboot.done
|
||||
|
||||
init_daemon_domain(veilor_firstboot_t, veilor_firstboot_exec_t)
|
||||
files_type(veilor_firstboot_state_t)
|
||||
|
||||
# Auto-transition: when init_t executes /usr/local/sbin/veilor-firstboot,
|
||||
# enter veilor_firstboot_t.
|
||||
domain_auto_trans(init_t, veilor_firstboot_exec_t, veilor_firstboot_t)
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# 2. Allow rules — what the service IS allowed to do
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# read /etc/passwd, /etc/group, /etc/shadow (passwd needs shadow write)
|
||||
allow veilor_firstboot_t passwd_file_t:file { read getattr open };
|
||||
allow veilor_firstboot_t shadow_t:file { read write open getattr setattr };
|
||||
|
||||
# exec passwd(1)
|
||||
allow veilor_firstboot_t passwd_exec_t:file { read getattr open execute execute_no_trans map };
|
||||
allow veilor_firstboot_t chkpwd_exec_t:file { read getattr open execute execute_no_trans map };
|
||||
|
||||
# capabilities passwd needs
|
||||
allow veilor_firstboot_t self:capability { setuid setgid chown dac_override dac_read_search fowner fsetid };
|
||||
|
||||
# write the state marker /var/lib/veilor-firstboot.done
|
||||
allow veilor_firstboot_t veilor_firstboot_state_t:file { create write open getattr setattr unlink };
|
||||
allow veilor_firstboot_t veilor_firstboot_state_t:dir { search write add_name remove_name };
|
||||
|
||||
# write /etc/sddm.conf.d/ entries (autologin disable, theme, etc.)
|
||||
allow veilor_firstboot_t sddm_var_lib_t:dir { read write search add_name remove_name open };
|
||||
allow veilor_firstboot_t sddm_var_lib_t:file { read write create open getattr setattr };
|
||||
|
||||
# start sddm.service via systemctl
|
||||
allow veilor_firstboot_t sddm_unit_file_t:file { read getattr open };
|
||||
allow veilor_firstboot_t sddm_unit_file_t:service { start status enable disable };
|
||||
allow veilor_firstboot_t init_t:system { start };
|
||||
|
||||
# tty1 I/O
|
||||
allow veilor_firstboot_t tty_device_t:chr_file { read write open getattr ioctl };
|
||||
allow veilor_firstboot_t devtty_t:chr_file { read write open getattr ioctl };
|
||||
|
||||
# usual base reads
|
||||
allow veilor_firstboot_t bin_t:file { read getattr open execute execute_no_trans map };
|
||||
allow veilor_firstboot_t lib_t:file { read getattr open execute execute_no_trans map };
|
||||
allow veilor_firstboot_t usr_t:file { read getattr open };
|
||||
allow veilor_firstboot_t etc_t:file { read getattr open };
|
||||
allow veilor_firstboot_t etc_t:dir { read search getattr open };
|
||||
allow veilor_firstboot_t fs_t:filesystem getattr;
|
||||
allow veilor_firstboot_t self:fifo_file { read write };
|
||||
allow veilor_firstboot_t self:unix_stream_socket { create connect read write };
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# 3. Deny rules — what the service is NOT allowed to do
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# no network — firstboot must never phone home
|
||||
neverallow veilor_firstboot_t self:tcp_socket *;
|
||||
neverallow veilor_firstboot_t self:udp_socket *;
|
||||
neverallow veilor_firstboot_t self:rawip_socket *;
|
||||
neverallow veilor_firstboot_t self:packet_socket *;
|
||||
neverallow veilor_firstboot_t self:netlink_route_socket *;
|
||||
|
||||
# no kernel module load
|
||||
neverallow veilor_firstboot_t self:capability sys_module;
|
||||
|
||||
# no /home access except the bits ferror-firstboot.sh writes (admin's
|
||||
# .config dir staging, if any). /home/admin general read = forbidden.
|
||||
neverallow veilor_firstboot_t home_root_t:dir { read write };
|
||||
neverallow veilor_firstboot_t user_home_t:dir { read write search };
|
||||
neverallow veilor_firstboot_t user_home_t:file { read write open };
|
||||
|
||||
# no ptrace, no /dev/mem, no /dev/kmem
|
||||
neverallow veilor_firstboot_t self:capability sys_ptrace;
|
||||
neverallow veilor_firstboot_t self:capability sys_rawio;
|
||||
Loading…
Reference in a new issue