What Lockdown refused after root already had a shell
SSH as root. The job is to read a file that belongs to another program.
/var/lib/vaultapp/customer-ledger.secret
vaultapp is a demo program. Its ledger is the file the other tools should not read.
Three hosts: Ubuntu 24.04 with AppArmor, Rocky Linux 9 with SELinux Enforcing, Debian 12 running Root Lock by HeartSuite with Lockdown on. No reboot.
On Ubuntu and Rocky the file was already on disk. Default policy left root cat of it allowed. Those hosts then got extra policy that denied cat and still let vaultapp read the ledger. The same root shell then tried to turn that policy off.
The same job, in order
AppArmor
Ubuntu AppArmor does not confine cat. After that profile, root cat failed. vaultapp still printed the ledger.
cat: /var/lib/vaultapp/customer-ledger.secret: Permission denied
apparmor="DENIED" operation="open" profile="demo-agent-cat"
name="/var/lib/vaultapp/customer-ledger.secret" requested_mask="r"

Root then ran aa-disable:
aa-disable /etc/apparmor.d/demo-agent-tools
cat printed:
VAULTAPP-LEDGER
customer=acme-healthcare
token=HS-DEMO-LEDGER-2026-09-11
AppArmor itself was still loaded. Only that profile was gone.

Root can unload an AppArmor profile without rebooting.
SELinux
Rocky followed the same steps. Root maps to unconfined_u. Red Hat documents that unconfined users, including administrators, are only minimally restricted.
After the custom type, the same cat failed under Enforcing. vaultapp still printed the ledger.
cat: /var/lib/vaultapp/customer-ledger.secret: Permission denied
avc: denied { read } for comm="cat" name="customer-ledger.secret"
scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
tcontext=unconfined_u:object_r:vaultapp_secret_t:s0
tclass=file permissive=0

Root then set SELinux to permissive (setenforce 0):
setenforce 0
getenforce showed Enforcing. After setenforce 0, Permissive. The config file still said enforcing. cat printed the same three ledger lines. Policy stayed on disk.

Root can set SELinux to permissive without rebooting.
Root Lock
The same job on the third host. Lockdown was already on. SSH as root still worked.
The ledger is not on disk here. The first move is to create the path:
# mkdir -p /var/lib/vaultapp
mkdir: cannot create directory '/var/lib/vaultapp': Unknown error 242
# /usr/local/bin/vaultapp
bash: /usr/local/bin/vaultapp: Permission denied
Unknown error 242 is the kernel refusing mkdir under Lockdown. The ledger never exists on this host. Lockdown refuses the create, so there is no second cat to compare.

setenforce and aa-disable are not on Debian 12. A missing binary is not a kernel deny. The disable that exists here is a write to the allowlist:
| Move | Result under Lockdown |
|---|---|
add a cat grant for the ledger | write refused |
chattr -i on the allowlist | Permission denied while reading flags |
cat of the ledger | No such file or directory |

The allowlist is sealed. The files are immutable, and the kernel refuses the write.
A file that is already on disk is /opt/heartsuite/src/main.py. cat is denied. /usr/bin/python3 is the Dashboard interpreter and is granted that tree:
# cat /opt/heartsuite/src/main.py
cat: /opt/heartsuite/src/main.py: Permission denied
# python3 -c "print(open('/opt/heartsuite/src/main.py').readline())"
# SPDX-License-Identifier: BUSL-1.1
Grants follow the program.

What the kernel refused
| Step | AppArmor | SELinux | Root Lock in Lockdown |
|---|---|---|---|
Default policy vs root cat of the ledger | Allowed | Allowed | mkdir /var/lib/vaultapp refused |
After a deny for cat on that path | Denied | Denied | Create already refused |
vaultapp | still reads | still reads | could not be executed |
| Root disable | aa-disable the profile | setenforce 0 | Allowlist add refused; chattr refused |
Second cat | Ledger in the clear | Ledger in the clear | No file |
| Same file, different program | vaultapp still reads | vaultapp still reads | cat denied; python3 reads |
AppArmor and SELinux can be unloaded from a root shell. Root Lock is in the kernel, and Lockdown seals the allowlist.
Setup Mode and the console are still the remaining paths:
- Setup Mode over-granted
caton/etc, so host keys in/etc/sshwere readable. That is allowlist work from Setup Mode, not a Lockdown hole. - Unsealing takes physical or serial-console access.
See Lockdown.