Configure SELinux
SELinux (Security-Enhanced Linux) is a Linux security module that enforces mandatory access control on processes, files, ports, and users at the kernel level. Even when Unix permissions allow an action, SELinux still denies it unless the active policy explicitly permits it.
Parrot OS uses AppArmor by default. The two cannot serve as the primary security module at the same time, so enabling SELinux means switching away from AppArmor. For desktop use and offensive security work, AppArmor remains the recommended choice.
Check Whether SELinux Is Enabled
Section titled “Check Whether SELinux Is Enabled”Start by checking whether SELinux is active:
sestatusgetenforceWith AppArmor active, the output should look like this:
SELinux status: disabledDisabledThe following commands show the installed policy and boot configuration:
dpkg-query -W selinux-policy-defaultcat /proc/cmdlinecat /sys/kernel/security/lsmInstall SELinux
Section titled “Install SELinux”sudo apt updatesudo apt install selinux-basics selinux-policy-default auditd policycoreutils-python-utilsInstall these additional tools to inspect policy rules and follow the Firefox example:
sudo apt install setools selinux-policy-dev makeEnable SELinux
Section titled “Enable SELinux”The following steps are for GRUB. Leave AppArmor running until you reboot.
1. Configure Permissive Mode
Section titled “1. Configure Permissive Mode”sudo nano /etc/selinux/configSet the policy and mode as follows before rebooting:
SELINUX=permissiveSELINUXTYPE=default2. Configure GRUB
Section titled “2. Configure GRUB”Check /etc/default/grub and /etc/default/grub.d/*.cfg for conflicting options such as security=apparmor, selinux=0 or enforcing=1. If you have an explicit lsm= list, it takes precedence over security=. Replace AppArmor with SELinux in that list without removing the other modules.
Activate SELinux and inspect the generated boot entries:
sudo selinux-activatesudo grep -E '^[[:space:]]*linux' /boot/grub/grub.cfgParrot’s grub.cfg drop-in can overwrite the change made by selinux-activate. If security=selinux is missing from the normal boot entry, add the configuration below. If selinux.cfg already exists, edit it without overwriting unrelated settings.
sudo mkdir -p /etc/default/grub.decho 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT security=selinux"' | sudo tee /etc/default/grub.d/selinux.cfgsudo update-grubsudo grep -E '^[[:space:]]*linux' /boot/grub/grub.cfgCheck the output again before continuing. The normal boot entry should select SELinux without conflicting options. Recovery entries are unchanged.
3. Reboot and Verify
Section titled “3. Reboot and Verify”selinux-activate also schedules filesystem labelling for the next boot. Reboot now and wait for labelling and the automatic second reboot to finish:
sudo rebootOnce you can log in again, check the running configuration:
sestatusgetenforcecat /proc/cmdlinecat /sys/kernel/security/lsmsudo check-selinux-installationYou should see the default policy in Permissive mode and selinux in the module list. If SELinux is disabled, correct the boot configuration rather than running setenforce.
Change SELinux Mode
Section titled “Change SELinux Mode”| Mode | Effect |
|---|---|
enforcing |
Policy violations are blocked |
permissive |
Policy violations are allowed and logged |
disabled |
SELinux does not enforce a policy |
You can switch to permissive mode without rebooting:
sudo setenforce 0Check that your applications work and investigate any denials before switching to enforcing mode:
sudo setenforce 1Also set SELINUX= in /etc/selinux/config to keep the mode after rebooting. Empty logs alone do not show that the policy is ready, since applications may be unconfined or auditing inactive.
Relabel Filesystems
Section titled “Relabel Filesystems”The initial relabel is automatic. You may need to repeat it after restoring data saved before SELinux was enabled. Set permissive mode first, then run:
sudo touch /.autorelabelsudo rebootThe service labels mounted filesystems that support SELinux labels and are writable, then reboots. It skips any paths listed in /etc/selinux/fixfiles_exclude_dirs.
Btrfs Subvolumes
Section titled “Btrfs Subvolumes”Root and home commonly use the @ and @home subvolumes. Check how they are mounted and whether their labels match the policy:
sudo btrfs subvolume list /findmnt -T / -o TARGET,FSTYPE,OPTIONSfindmnt -T /home -o TARGET,FSTYPE,OPTIONSmatchpathcon -V / /homeLook for rw and seclabel in the mount options. New or nested subvolumes may need separate attention. The first command below previews label changes at the mount point, while the second applies them:
sudo restorecon -nRv /path/to/new/mountsudo restorecon -Rv /path/to/new/mountTroubleshoot Application Access
Section titled “Troubleshoot Application Access”When an application fails, check whether auditing is running and look for recent denials:
sudo systemctl status auditd --no-pagersudo auditctl -ssudo ausearch -m AVC,USER_AVC -ts recent | audit2whyIf auditing fails, check sudo journalctl -b -u auditd. Try sudo setenforce 0 to see whether permissive mode resolves the problem. Return to enforcing afterwards only if that was the original mode.
Before changing the policy, check for incorrect labels and repair only the affected directory:
ls -Z /path/to/filesudo restorecon -nRv /path/to/directorysudo restorecon -Rv /path/to/directoryCreate a Local Policy Module
Section titled “Create a Local Policy Module”When existing rules and booleans are insufficient, collect events for a local module. Replace 12345 with the process PID and mytool_local with a unique name:
sudo ausearch -m AVC,USER_AVC -ts recent -p 12345 --raw > mytool.avcaudit2allow -m mytool_local < mytool.avc > mytool_local.tecat mytool_local.teRead the generated source and remove permissions the application does not need before compiling and installing it:
make -f /usr/share/selinux/devel/Makefile mytool_local.ppsudo semodule -i mytool_local.ppTry security tools in an authorized lab before deciding whether they need custom rules. Use getsebool -a to check available booleans rather than copying settings from RHEL guides.
Optional: Run Firefox in a Separate Domain
Section titled “Optional: Run Firefox in a Separate Domain”This example uses a temporary Firefox profile and dummy SSH data to demonstrate a domain transition. It requires the optional policy tools installed above.
-
Check the mode and existing customizations:
Terminal window getenforceid -Zsudo semodule -lsudo semanage fcontext -l -CThe mode must be
Permissiveand the shell context must containunconfined_r:unconfined_t. Stop if afirefox_confinedmodule or local Firefox label override already exists. -
Create a temporary profile and dummy data:
Terminal window lab_dir=$(mktemp -d "$HOME/selinux-firefox.XXXXXX")cd "$lab_dir"mkdir profile .sshprintf 'SELinux demo: no real credentials\n' > .ssh/demo.txtchcon -R -t ssh_home_t "$lab_dir/.ssh"nano firefox_confined.teSave this policy as
firefox_confined.te:policy_module(firefox_confined, 1.0)require {type unconfined_t;role unconfined_r;class process { transition };class file { getattr open read execute entrypoint };}type firefox_confined_t;type firefox_confined_exec_t;domain_type(firefox_confined_t)domain_entry_file(firefox_confined_t, firefox_confined_exec_t)role unconfined_r types firefox_confined_t;type_transition unconfined_t firefox_confined_exec_t : process firefox_confined_t;allow unconfined_t firefox_confined_t : process transition;allow unconfined_t firefox_confined_exec_t : file { getattr open read execute };allow firefox_confined_t firefox_confined_exec_t : file entrypoint; -
Compile and load the module:
Terminal window make -f /usr/share/selinux/devel/Makefile firefox_confined.ppsudo semodule -i firefox_confined.pp -
Find the real executable and note its current label. Use the resolved path below if it differs:
Terminal window readlink -f /usr/bin/firefox-esrls -Z /usr/lib/firefox-esr/firefox-esrmatchpathcon /usr/lib/firefox-esr/firefox-esrCheck that the current label matches what the policy expects before applying the temporary mapping:
Terminal window sudo semanage fcontext -a -t firefox_confined_exec_t "/usr/lib/firefox-esr/firefox-esr"sudo restorecon -v /usr/lib/firefox-esr/firefox-esr -
Run Firefox without opening a window. Even loading the start page is enough: the minimal module denies routine operations, so any records for the new domain prove the transition.
Terminal window firefox-esr --headless --no-remote --profile "$lab_dir/profile" "file://$lab_dir/.ssh/demo.txt" &sleep 20sudo ausearch -m AVC -ts recent | grep 'scontext=.*:firefox_confined_t:'pkill firefox-esrRecords with
firefox_confined_tas subject andpermissive=1show allowed-and-logged denials. If the page itself loads, you may also see thessh_home_ttarget among them. The policy is not sufficient for normal Firefox use in enforcing mode. -
Restore the original configuration in this order:
Terminal window sudo semanage fcontext -d "/usr/lib/firefox-esr/firefox-esr"sudo restorecon -v /usr/lib/firefox-esr/firefox-esrsudo semodule -r firefox_confinedmatchpathcon -V /usr/lib/firefox-esr/firefox-esrCheck the temporary directory’s path with
printf '%s\n' "$lab_dir"before deleting it. Undo any successful module or label changes even if an earlier step failed.
Disable SELinux
Section titled “Disable SELinux”-
Undo activation and remove the drop-in only if you created it for this guide. Keep any unrelated settings:
Terminal window if [ "$(getenforce)" = "Enforcing" ]; thensudo setenforce 0fisudo selinux-activate disablesudo rm -f /etc/default/grub.d/selinux.cfg /.autorelabelCheck GRUB for leftover SELinux selectors or
apparmor=0. If you changed anlsm=list, restore it to select AppArmor. -
Open
/etc/selinux/configand set:SELINUX=disabled -
Enable AppArmor for the next boot and regenerate GRUB:
Terminal window sudo systemctl enable apparmorsudo update-grubsudo grep -E '^[[:space:]]*linux' /boot/grub/grub.cfgsudo rebootWait until after the reboot to start AppArmor. Until then, SELinux is still the active module.
-
Verify that SELinux is disabled and AppArmor profiles are loaded:
Terminal window sestatuscat /proc/cmdlinecat /sys/kernel/security/lsmsudo aa-status