Scripts for inspecting Protocol 7 daemon hardening, AppArmor enforcement, and overall system state.
Find a file
2026-07-26 12:44:31 -07:00
lainos-security-status add test scripts 2026-07-26 12:44:31 -07:00
LICENSE Initial commit 2026-07-26 21:28:31 +02:00
protocol7-core-security-status add test scripts 2026-07-26 12:32:33 -07:00
README.md Update README.md 2026-07-26 21:43:29 +02:00

lainos-security-suite

Two scripts for inspecting and adversarially testing the security posture of a running LainOS Layer 02 system: Protocol 7 daemon hardening, AppArmor enforcement, and overall system state.


Scripts

lainos-security-status

A read-only status dashboard. Reports current state without attempting to break anything ~ safe to run any time, including in production, with no side effects beyond reading /proc, dmesg, and calling aa-status/rc-service status.

Covers:

  • Installed package versions (lainos-apparmor, protocol7-core, apparmor)
  • AppArmor kernel module state, profile counts (enforce/complain/unconfined)
  • Which profiles are currently enforced against running processes
  • OpenRC service status for core daemons and the DNS/networking stack
  • AppArmor denial count since boot (via dmesg), with the most recent denials summarized (profile, operation, path)
  • Basic connectivity and NTP sync state
  • Per-daemon hardening state for the two long-running Protocol 7 daemons: AppArmor enforcement, capability bounding set, seccomp filter mode, privilege drop (running as nobody)
  • Boot-time enforce symlink presence for each profile
lainos-security-status
doas (lain@navi) password:
╔══════════════════════════════════════════╗
║   LainOS Layer 02 — Security Status      ║
╚══════════════════════════════════════════╝
  Host:    navi
  Kernel:  7.1.4-arch1-1
  Uptime:  up 10 hours, 54 minutes

--- Layer 02 Packages ---
    lainos-apparmor 1.2.1-29
    protocol7-core 5.5.3-27
    apparmor 4.1.7-1

--- AppArmor Global State ---
  ✓ AppArmor kernel module active
    Total profiles:   24
    Enforce mode:     24
    Complain mode:    0
    Unconfined procs: 31

--- Enforced Profiles ---
    /usr/bin/chronyd
    /usr/bin/dhcpcd
    /usr/bin/dnsmasq
    /usr/bin/gpg
    /usr/bin/gpg-agent
    /usr/bin/keepassxc
    /usr/bin/mpv
    /usr/bin/nft
    /usr/bin/pipewire
    /usr/bin/pipewire-pulse
    /usr/bin/snowflake-pt-client
    /usr/bin/ssh
    /usr/bin/stubby
    /usr/bin/syslog-ng
    /usr/bin/tor
    /usr/bin/unbound
    /usr/bin/vlc
    /usr/bin/wireplumber
    /usr/lib/iwd/iwd
    /usr/lib/librewolf/librewolf
    /usr/libexec/lainos/lainos-dbus-bridge
    /usr/libexec/lainos/lainos-init
    /usr/libexec/lainos/lainos-notifyd
  ✓ /usr/bin/chronyd (8405)
  ✓ /usr/bin/dhcpcd (8237)
  ✓ /usr/bin/dhcpcd (8242)
  ✓ /usr/bin/dhcpcd (8243)
  ✓ /usr/bin/dhcpcd (8244)
  ✓ /usr/bin/dhcpcd (8416)
  ✓ /usr/bin/dnsmasq (9945)
  ✓ /usr/bin/gpg-agent (30951)
  ✓ /usr/lib/gnupg/scdaemon (31000) /usr/bin/gpg-agent
  ✓ /usr/bin/pipewire (2871)
  ✓ /usr/bin/pipewire (2970)
  ✓ /usr/bin/syslog-ng (1701)
  ✓ /usr/bin/unbound (9908)
  ✓ /usr/bin/wireplumber (2936)
  ✓ /usr/lib/iwd/iwd (7759)
  ✓ /usr/lib/librewolf/librewolf (3908)
  ✓ /usr/lib/librewolf/librewolf (4032)
  ✓ /usr/lib/librewolf/librewolf (4108)
  ✓ /usr/lib/librewolf/librewolf (4144)
  ✓ /usr/lib/librewolf/librewolf (4152)
  ✓ /usr/lib/librewolf/librewolf (4243)
  ✓ /usr/lib/librewolf/librewolf (4280)
  ✓ /usr/lib/librewolf/librewolf (4545)
  ✓ /usr/lib/librewolf/librewolf (4611)
  ✓ /usr/lib/librewolf/librewolf (8664)
  ✓ /usr/lib/librewolf/librewolf (9046)
  ✓ /usr/lib/librewolf/librewolf (14093)
  ✓ /usr/lib/librewolf/librewolf (14098)
  ✓ /usr/lib/librewolf/librewolf (14303)
  ✓ /usr/libexec/lainos/lainos-dbus-bridge (16715)
  ✓ /usr/libexec/lainos/lainos-notifyd (16773)

--- OpenRC Services ---
  ✓ dhcpcd running
  ✓ dnsmasq running
  ! stubby service not found
  ✓ unbound running
  ✓ dnscrypt-proxy running
  ✓ iwd running
  ✓ chrony running
  ! tor service not found
  ! sdwdate service not found
  ✓ syslog-ng running
  ✓ lainos-dbus-bridge running
  ✓ lainos-notifyd running

--- AppArmor Denials ---
  ✗ 0
0 denials since boot

--- Network & Time ---
  ✓ Internet connectivity OK
  ✓ NTP sync: Normal

--- Protocol 7 Daemon Hardening ---
  ✓ lainos-dbus-bridge (PID 16715) AppArmor enforced
  ✓ lainos-dbus-bridge capability bounding set empty
  ✓ lainos-dbus-bridge seccomp filter mode
  ✓ lainos-dbus-bridge running as nobody
  ✓ lainos-notifyd (PID 16773) AppArmor enforced
  ✓ lainos-notifyd capability bounding set empty
  ✓ lainos-notifyd seccomp filter mode
  ✓ lainos-notifyd running as nobody

--- Boot Security Chain ---
  ✓ lainos-dbus-bridge enforce symlink present
  ✓ lainos-notifyd enforce symlink present

========================================

protocol7-core-security-status

An adversarial test suite. Unlike the status script above, this one actively attempts things a real attacker would try ~ escaping the mount namespace, reading blocked paths, cross-process ptracing, writing to /proc/sys ~ and checks that each attempt is actually denied. It restarts both Protocol 7 daemons at the end of every run (one test sends SIGTERM to lainos-notifyd as part of testing shutdown behavior, and a gdb ptrace attempt can leave lainos-dbus-bridge in a traced/stopped state), so expect a brief interruption to Protocol 7 services while it runs.

36 tests across 12 categories:

# Category What it actually proves
1 AppArmor enforcement Both daemons are confined, not just loaded
2 Privilege drop Both daemons run as nobody, not root
3 Capability drop CapBnd reads zero on both ~ no regainable capabilities
4 Seccomp Filter mode active (not just loaded, actually filtering)
5 Mount namespace /tmp, /home, /root are tmpfs overlays, not the real filesystem
5b Filesystem isolation effectiveness /home//root are genuinely empty inside the namespace even when the host has real data; /tmp is bidirectionally isolated (neither side can see the other's files)
6 Path blocking (DAC baseline) /etc/shadow, /home, /root are inaccessible ~ not AppArmor-specific, since plain UNIX permissions already block nobody here
6b AppArmor negative control /var/tmp write is denied even though it's world-writable (1777) and DAC alone would allow it ~ this is the test that actually proves AppArmor is enforcing, not just present
6c ptrace denial Neither daemon can PTRACE_ATTACH the other, despite sharing the same UID
7 Network No listening sockets on either daemon, and the loaded profile text itself contains no network inet/inet6 grant (checked directly, not inferred from current runtime state)
8 Capability abuse /proc/sys write blocked
9 Denial log Zero new denials during this run (ring buffer cleared at start)
10 D-Bus The bridge actually responds to a real D-Bus introspection call
11 lainos-init whitelist Unsafe relative and nonexistent-absolute P7_CMD values are rejected; root sessions are refused without explicit override
12 notifyd regressions Survives an embedded-newline (log injection) payload without crashing; exits promptly on SIGTERM

Why 6 and 6b are both present: 6 alone would keep passing even if the AppArmor profile were unloaded entirely, since plain filesystem permissions already block nobody from those specific paths. 6b uses a path that is world-writable at the permission layer, so if it's still blocked, something beyond DAC has to be doing the blocking ~ that's the actual proof of enforcement.

doas protocol7-core-security-status
doas (lain@navi) password:
==========================================
Protocol 7 AppArmor Adversarial Test Suite
==========================================

--- Layer 02 Packages ---
lainos-apparmor 1.2.1-29
protocol7-core 5.5.3-27
apparmor 4.1.7-1

Target PIDs:
  lainos-dbus-bridge: 2639
  lainos-notifyd:     1124

--- Test 1: AppArmor Enforcement ---
  [PASS] lainos-dbus-bridge in enforce mode
  [PASS] lainos-notifyd in enforce mode

--- Test 2: Privilege Drop ---
  [PASS] dbus-bridge as nobody
  [PASS] notifyd as nobody

--- Test 3: Capability Drop ---
  [PASS] lainos-dbus-bri CapBnd zero
  [PASS] lainos-notifyd CapBnd zero

--- Test 4: Seccomp ---
  [PASS] lainos-dbus-bri seccomp active
  [PASS] lainos-notifyd seccomp active

--- Test 5: Mount Namespace ---
  [PASS] lainos-dbus-bri /tmp tmpfs
  [PASS] lainos-dbus-bri /home tmpfs
  [PASS] lainos-dbus-bri /root tmpfs
  [PASS] lainos-notifyd /tmp tmpfs
  [PASS] lainos-notifyd /home tmpfs
  [PASS] lainos-notifyd /root tmpfs

--- Test 5b: Filesystem Isolation Effectiveness ---
  [PASS] /home is empty in daemon namespace (host has 1 entries)
  [PASS] /root is empty in daemon namespace
  [PASS] Daemon /tmp isolated from host
  [PASS] Host /tmp isolated from daemon

--- Test 6: Blocked Path Access (DAC baseline — not AppArmor-specific) ---
  [PASS] /etc/shadow blocked
  [PASS] /home write blocked
  [PASS] /root write blocked

--- Test 6b: AppArmor Negative Control ---
  [PASS] lainos-dbus-bri: /var/tmp write blocked by AppArmor (DAC alone would have allowed this)
  [PASS] lainos-notifyd: /var/tmp write blocked by AppArmor (DAC alone would have allowed this)

--- Test 6c: ptrace Denial ---
  [PASS] dbus-bridge cannot ptrace notifyd

--- Test 7: Network ---
  [PASS] dbus-bridge no network sockets
  [PASS] notifyd no network sockets
  [PASS] lainos-dbus-bridge profile text contains no inet/inet6 network rule
  [PASS] lainos-notifyd profile text contains no inet/inet6 network rule

--- Test 8: Capability Abuse ---
  [PASS] /proc/sys write blocked

--- Test 9: Denial Log ---
  [PASS] No current denials

--- Test 10: D-Bus ---
  [PASS] D-Bus responding

--- Test 11: lainos-init P7_CMD Whitelist ---
  [PASS] unsafe relative P7_CMD rejected
  [PASS] nonexistent absolute P7_CMD rejected
  [PASS] root session refused without P7_ALLOW_ROOT

--- Test 12: notifyd Behavioral Regressions ---
  [PASS] notifyd survived newline payload, socket functional
  [PASS] notifyd exited promptly on SIGTERM


==========================================
Test Summary: 36 passed, 0 failed
==========================================

Restarting Protocol 7 daemons...
 * Stopping lainos-dbus-bridge ...                                                                 [ ok ]
 * Starting lainos-dbus-bridge ...                                                                 [ ok ]
 * WARNING: you are stopping a sysinit service
 * Stopping lainos-notifyd ...
 * start-stop-daemon: no matching processes found                                                  [ ok ]
 * Starting lainos-notifyd ...                                                                     [ ok ]
All tests PASSED

Exit code 0 if all tests pass, 1 if any fail.

Requires: gdb (for the ptrace test in 6c; skipped gracefully with a warning if not installed), nsenter, socat, dbus-send, pgrep. Both Protocol 7 daemons (lainos-dbus-bridge, lainos-notifyd) must be running before the suite starts, or it exits immediately with an error.


When to use which

  • Routine check, or troubleshooting something that feels off: lainos-security-status ~ fast, read-only, safe anywhere.
  • After changing anything touching Protocol 7, AppArmor profiles, seccomp, or the daemons' privilege model; before a release; or when you want actual proof (not just configuration review) that confinement is holding: protocol7-core-security-status ~ slower, causes a brief service interruption, but tests real enforcement rather than just reading state.

Requirements

  • LainOS Layer 02 (or any OpenRC-based system running protocol7-core and lainos-apparmor)
  • doas configured for the invoking user
  • AppArmor active in the kernel (/sys/kernel/security/apparmor present)

License

GPLv3, matching the rest of the LainOS Layer 02 project.