Skip to content
Search Fedora

    Browse this documentation

    SELinux on Fedora: modes, contexts, booleans and troubleshooting

    Fedora is the distribution that ships SELinux enforcing by default. It is not “an extra security plugin” but a second layer on top of permission bits: even as root, an action the policy forbids is refused.

    Below is the measured state on F45.

    Measured in a GNOME terminal: getenforce returns Enforcing, sestatus shows policy targeted with the runtime mode matching the config, and ls -Zd shows home_root_t for /home and tmp_t for /tmp

    Terminal window
    getenforce
    sestatus
    Enforcing
    SELinux status: enabled
    SELinuxfs mount: /sys/fs/selinux
    SELinux root directory: /etc/selinux
    Loaded policy name: targeted
    Current mode: enforcing
    Mode from config file: enforcing
    Policy MLS status: enabled
    Policy deny_unknown status: allowed
    Memory protection checking: actual (secure)
    Max kernel policy version: 35

    Three fields are worth remembering:

    FieldMeaningWhen to look
    Loaded policy nametargeted, constraining only specific processesto tell whether it is a full policy
    Current moderuntime modefirst thing to check when debugging
    Mode from config fileconfigured modea mismatch means someone toggled it
    Terminal window
    cat /etc/selinux/config | grep -E "^SELINUX="
    SELINUX=enforcing
    • enforcing: the policy is enforced, violations are refused;
    • permissive: log only, no blocking — for confirming “was it SELinux”;
    • disabled: policy not loaded at all, needs a reboot and a relabel; the most expensive choice.
    Terminal window
    sudo setenforce 0 # switch to permissive until reboot
    getenforce # Permissive
    sudo setenforce 1 # back to enforcing
    Terminal window
    ls -Zd /home /root /tmp /usr/bin/passwd
    system_u:object_r:home_root_t:s0 /home
    system_u:object_r:admin_home_t:s0 /root
    system_u:object_r:tmp_t:s0 /tmp
    system_u:object_r:passwd_exec_t:s0 /usr/bin/passwd

    Of the four fields user:role:type:level, what actually matters is the third, type.

    The classic trap: move a file elsewhere and the type does not follow, so the service fails to start.

    Terminal window
    sudo restorecon -Rv /var/www # restore default labels from policy
    sudo chcon -t httpd_sys_content_t /srv/site/index.html # temporary, not persistent
    sudo semanage fcontext -a -t httpd_sys_content_t '/srv/site(/.*)?' # persistent rule
    sudo restorecon -Rv /srv/site

    Ports and booleans: allow things without writing policy

    Section titled “Ports and booleans: allow things without writing policy”

    Ports — when a service needs a non-standard port, first see what the policy allows:

    Terminal window
    sudo semanage port -l | grep -E "^http_port_t|^ssh_port_t"
    http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000

    To let httpd listen on 8080, add the port first:

    Terminal window
    sudo semanage port -a -t http_port_t -p tcp 8080

    Booleans — built-in switches in the policy, much cheaper than writing custom policy:

    Terminal window
    sudo semanage boolean -l | grep httpd_can_network_connect
    httpd_can_network_connect (off , off) Allow httpd to can network connect

    The two values are “current / boot default”. Turn it on persistently:

    Terminal window
    sudo setsebool -P httpd_can_network_connect on
    getsebool httpd_can_network_connect
    httpd_can_network_connect --> on

    SELinux decision order: DAC permission bits first, then the policy check; a denial produces an AVC, and troubleshooting follows five steps

    Terminal window
    getenforce # 1) is it enforcing
    sudo ausearch -m AVC -ts recent # 2) any denials
    ls -Zd <path> # 3) are the labels right
    sudo semanage port -l | grep <port> # 4) port type
    sudo semanage boolean -l | grep <term> # 5) is there a switch

    ausearch printing <no matches> has two meanings: genuinely no denial, or auditd is not running. Confirm the latter:

    Terminal window
    systemctl status auditd --no-pager

    Disabling SELinux makes the problem go away immediately, and you lose:

    • the enforced isolation between containers and the host (mentioned repeatedly in containers);
    • the lateral limits after a service is compromised;
    • the only source of evidence when something breaks.

    The correct order is: switch to permissive to confirm it is SELinux, fix it with the five steps above, switch back to enforcing. Treating disabled as the default answer turns one problem into three.