- Shell 100%
| lainos-security-status | ||
| LICENSE | ||
| protocol7-core-security-status | ||
| README.md | ||
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-coreandlainos-apparmor) doasconfigured for the invoking user- AppArmor active in the kernel (
/sys/kernel/security/apparmorpresent)
License
GPLv3, matching the rest of the LainOS Layer 02 project.