Note:

Use SELinux on Oracle Linux

Introduction

SELinux, or Security-Enhanced Linux, is a set of kernel modifications and user-space tools designed to protect the Linux Operating System. SELinux is a Linux kernel security module that uses a mechanism called mandatory access controls (MAC) to provide another layer of system security, precise access control, system-wide admin-defined policies, and improved mitigation for privilege escalation attacks as defined by the system administrator.

This tutorial guides you through using these user-space tools to help keep your system running in enforcing mode.

Objectives

In this tutorial, you will learn how to:

Prerequisites

Deploy Oracle Linux

Note: If running in your own tenancy, read the linux-virt-labs GitHub project README.md and complete the prerequisites before deploying the lab environment.

  1. Open a terminal on the Luna Desktop.

  2. Clone the linux-virt-labs GitHub project.

    git clone https://github.com/oracle-devrel/linux-virt-labs.git
    
  3. Change into the working directory.

    cd linux-virt-labs/ol
    
  4. Install the required collections.

    ansible-galaxy collection install -r requirements.yml
    
  5. Deploy the lab environment.

    ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6"
    

    The free lab environment requires the extra variable local_python_interpreter, which sets ansible_python_interpreter for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.

    The default deployment shape uses the AMD CPU and Oracle Linux 8. To use an Intel CPU or Oracle Linux 9, add -e instance_shape="VM.Standard3.Flex" or -e os_version="9" to the deployment command.

    Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of Oracle Cloud Native Environment is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.

Create a New Test User

An additional user allows testing the assignment of a SELinux user later in this tutorial.

  1. Open a terminal and connect via SSH to the ol-node-01 instance.

    ssh oracle@<ip_address_of_instance>
    
  2. Create a new user and set a password.

    sudo useradd -u 8000 ralph
    echo "ralph:oracle" | sudo chpasswd
    
  3. Allow SSH connections.

    Copy the SSH key from the oracle user account.

    sudo mkdir /home/ralph/.ssh
    sudo cp /home/oracle/.ssh/authorized_keys /home/ralph/.ssh/authorized_keys
    sudo chown -R ralph:ralph /home/ralph/.ssh
    sudo chmod 700 /home/ralph/.ssh
    sudo chmod 600 /home/ralph/.ssh/authorized_keys
    
  4. Open a new terminal and verify you can connect via SSH using the newly created user.

    ssh ralph@<ip_address_of_instance>
    
  5. Exit the session and close the terminal window.

    exit
    
  6. Switch to the terminal connected to ol-node-01 as the oracle user.

SELinux Mode and Status

Oracle Linux installs SELinux by default and runs in Enforcing mode.

  1. Confirm by checking the SELinux mode.

    getenforce
    

    The status should show as Enforcing.

  2. Check the SELinux states and modes.

    sestatus
    

    The sestatus command output shows the SELinux status, policy, and mode.

    Example Output:

    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:      31
    

SELinux Security Labels

Every process and system resource under SELinux has a security label called a SELinux context. The SELinux context, also called an SELinux label, focuses on the security properties and ensures a consistent way to reference objects in the SELinux policy.

  1. Show the SELinux security label for a file.

    ls -ldZ /etc/passwd
    

    Example Output:

    -rw-r--r--. 1 root root system_u:object_r:passwd_file_t:s0 1892 Apr 13 14:39 /etc/passwd
    

    The ls output with the -Z option displays the four SELinux attribute fields:

    • user: system_u
    • role: object_r
    • type: passwd_file_t
    • security: s0

    The most important of these is the SELinux type, as the majority of SELinux targeted policy rules leverage SELinux types to define the allowed interaction between one object (e.g., process) and another (e.g., file).

  2. List all of the available SELinux types.

    seinfo --type | head
    
    • The head command limits the output to only the first ten lines.

    The full output shows SELinux types exist for many different commands and services, such as ssh and sshd.

  3. List the specific SELinux types.

    The grep will limit the output to only those types containing the word ssh.

    seinfo -t | grep ssh
    
  4. List the security labels for specific processes and configuration files.

    Using ps gets the security labels for the processes.

    ps -efZ | grep sshd
    

    Example Output:

    system_u:system_r:sshd_t:s0-s0:c0.c1023 root 3343      1  0 10:52 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 1 of 10-100 startups
    system_u:system_r:sshd_t:s0-s0:c0.c1023 root 11451  3343  0 11:09 ?        00:00:00 sshd: oracle [priv]
    unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 oracle 11466 11451  0 11:09 ? 00:00:00 sshd: oracle@pts/0
    system_u:system_r:sshd_t:s0-s0:c0.c1023 root 11560  3343  0 11:11 ?        00:00:00 sshd: ralph [priv]
    unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 ralph 11574 11560  0 11:11 ? 00:00:00 sshd: ralph@pts/1
    system_u:system_r:sshd_t:s0-s0:c0.c1023 root 11636  3343  0 11:12 ?        00:00:00 sshd: [accepted]
    system_u:system_r:sshd_net_t:s0-s0:c0.c1023 sshd 11637 11636  0 11:12 ?    00:00:00 sshd: [net]
    unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 oracle 11639 11467  0 11:12 pts/0 00:00:00 grep --color=auto sshd
    

    Different versions of Oracle Linux may provide more or less information when showing the labels of a specific process.

  5. Use the ls command to show the security labels for the configuration files.

    ls -lZ /etc/ssh/
    

    Example Output:

    total 600
    -rw-r--r--. 1 root root     system_u:object_r:etc_t:s0      577388 Oct  9  2021 moduli
    -rw-r--r--. 1 root root     system_u:object_r:etc_t:s0        1770 Oct  9  2021 ssh_config
    drwxr-xr-x. 2 root root     system_u:object_r:etc_t:s0          28 Feb 18 08:51 ssh_config.d
    -rw-------. 1 root root     system_u:object_r:etc_t:s0        4268 Apr 13 14:37 sshd_config
    -rw-r-----. 1 root ssh_keys system_u:object_r:sshd_key_t:s0    537 Apr 13 14:37 ssh_host_ecdsa_key
    -rw-r--r--. 1 root root     system_u:object_r:sshd_key_t:s0    197 Apr 13 14:37 ssh_host_ecdsa_key.pub
    -rw-r-----. 1 root ssh_keys system_u:object_r:sshd_key_t:s0    432 Apr 13 14:37 ssh_host_ed25519_key
    -rw-r--r--. 1 root root     system_u:object_r:sshd_key_t:s0    117 Apr 13 14:37 ssh_host_ed25519_key.pub
    -rw-r-----. 1 root ssh_keys system_u:object_r:sshd_key_t:s0   2635 Apr 13 14:37 ssh_host_rsa_key
    -rw-r--r--. 1 root root     system_u:object_r:sshd_key_t:s0    589 Apr 13 14:37 ssh_host_rsa_key.pub
    
  6. The sshd daemon process uses the sshd_t type. Therefore, in the targeted policy, there is expected a rule for the sshd_t SELinux attribute that states objects with sshd_t can access any objects with the following security attribute:

    • etc_t
    • sshd_key_t

    Similarly, if we examine the ssh command, we can determine a similar mapping between ssh_home_t and ssh_exec_t.

    ls -lZ /usr/bin/ssh
    

    Example Output:

    -rwxr-xr-x. 1 root root system_u:object_r:ssh_exec_t:s0 775720 Oct  9  2021 /usr/bin/ssh
    
    ls -lZ ~/.ssh
    

    Example Output:

    total 4
    -rw-------. 1 oracle oracle unconfined_u:object_r:ssh_home_t:s0 404 Apr 13 14:39 authorized_keys
    
  7. Display the security context of a user.

    The other context type of interest is unconfined_t. Objects with this SELinux type, such as users, have unrestricted access. This level of access means SELinux doesn’t limit what users can do and only inhibits them through DAC permissions. DAC (Discretionary Access Control) is the security policy handled by traditional users, groups, and other permissions.

    For example, show the security attributes for the oracle user.

    whoami
    id -Z
    
    

    Example Output:

    oracle
    unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
    

SELinux and Network Services

SELinux tracks the configurations for the most commonly used network-based software packages within its internal database. This tracking allows SELinux to protect the system from externally-facing services that are prone to attacks.

Therefore, SELinux may prevent a service from working if you configure the software to use a non-standard directory or port.

To show what SELinux knows about a system’s standard ports, we need to use the SELinux utility semanage.

  1. Determine which package provides the utility.

    sudo dnf whatprovides semanage
    

    The results show that /usr/sbin/semanage is part of the policycoreutils-python-utils package.

  2. Install the package and any dependencies.

    sudo dnf install -y policycoreutils-python-utils
    
  3. Check what ports SELinux allows for sshd.

    sudo semanage port -l | grep ssh
    

    Example Output:

    ssh_port_t                     tcp      22
    
  4. Add a new port to the SELinux policy.

    If we were to change the port the SSH daemon listens on to 2222 or where it stores the default configuration; then we would need to inform SELinux that we want those changes. We can again use semanage to allow a custom port by adding a new policy rule.

    sudo semanage port -a -t ssh_port_t -p tcp 2222
    
    • The -a option adds a new policy rule of type -t.
  5. Check what ports SELinux allows now.

    sudo semanage port -l | grep ssh
    

    Example Output:

    ssh_port_t                     tcp      2222, 22
    
  6. Modify a port in the SELinux policy.

    Let’s say we wanted to map the SSH daemon to port 443. Repeat the same command, but it will warn that the port is already in use and indicate that it will modify it instead.

    sudo semanage port -a -t ssh_port_t -p tcp 443
    

    Example Output:

    [oracle@ol-node-01 ~]$ sudo semanage port -a -t ssh_port_t -p tcp 443
    Port tcp/443 already defined, modifying instead
    

    The warning occurred because we were trying to switch port 443 from the http_port_t type to the ssh_port_t type.

    To make this work without returning a warning, use the -m option, which modifies the port object record rather than trying to add it.

    sudo semanage port -m -t ssh_port_t -p tcp 443
    

SELinux Users

Each Linux user is mapped to a SELinux user using an SELinux policy. This approach allows Linux users to inherit restrictions based on their SELinux user mapping. The default mapping in Oracle Linux is the __default__ login, which maps to the SELinux unconfined_u user.

  1. List all the current Linux user mappings.

    sudo semanage login -l
    
    • Notice that our oracle user is not listed and thus maps to the unconfined_u user.
  2. Listing the current SELinux users.

    seinfo -u
    
  3. Restrict a user’s actions.

    Although a default Linux user runs unconstrained, the user’s actions may induce restrictions based on an application’s domain, which is a bunch of objects with the same SELinux type.

    What if we wanted to block users from using the X Window System, sudo, and the network?

    SELinux has a user for that.

    To verify this, we need to have another Linux user. We’ll use the user ralph.

    1. Create the new mapping to guest_u.

      sudo semanage login -a -s guest_u ralph
      
    2. Verify the mapping.

      sudo semanage login -l
      
    3. Test that ralph cannot access the network.

      The restrictions inherited from guest_u only occur after login and not by performing a sudo or su.

      Open a new terminal and connect via SSH to the instance as the ralph user.

      ssh ralph@<ip_address_of_instance>
      
    4. Check the user’s context.

      id; id -Z
      

      Example Output:

      uid=8000(ralph) gid=8000(ralph) groups=8000(ralph) context=guest_u:guest_r:guest_t:s0
      guest_u:guest_r:guest_t:s0
      
    5. Show the security context of the user’s current processes:

      ps axZ
      

      The output shows user ralph mapped to guest_u and can log in. However, ralph should not be able to access the network.

    6. Test network connectivity with ping.

      ping localhost
      

      Example Output:

      ping: socket: Permission denied
      
    7. Additionally, test the network using curl.

      curl ifconfig.me
      

      Example Output:

      curl: (6) Could not resolve host: ifconfig.me
      

      The message indicates that curl cannot resolve the DNS name of ifconfig.me to an IP address. DNS, a Linux network service, requires opening a socket, so the SELinux guest_u user blocks it.

    8. Close the current terminal window.

      We finished testing with the user ralph, so close that terminal window.

      exit
      

SELinux Booleans

SELinux booleans allow specific policy changes at runtime without knowing how to write SELinux policies. Oracle Linux provides many built-in booleans, or administrators familiar with SELinux policies may write their own. Administrators are encouraged to write policies as booleans if the policy implemented is optional.

  1. Return a list of booleans along with their meaning.

    sudo semanage boolean -l
    

    Example Output:

    SELinux boolean                State  Default Description
    
    abrt_anon_write                (off  ,  off)  Allow abrt to anon write
    abrt_handle_event              (off  ,  off)  Allow abrt to handle event
    abrt_upload_watch_anon_write   (on   ,   on)  Allow abrt to upload watch anon write
    antivirus_can_scan_system      (off  ,  off)  Allow antivirus to can scan system
    antivirus_use_jit              (off  ,  off)  Allow antivirus to use jit
    auditadm_exec_content          (on   ,   on)  Allow auditadm to exec content
    authlogin_nsswitch_use_ldap    (off  ,  off)  Allow authlogin to nsswitch use ldap
    authlogin_radius               (off  ,  off)  Allow authlogin to radius
    ...
    

    The output explains what each boolean does and whether it is enabled (on) or disabled (off).

  2. Get a list of just the booleans and their status.

    sudo getsebool -a
    

    Example Output:

    abrt_anon_write --> off
    abrt_handle_event --> off
    abrt_upload_watch_anon_write --> on
    antivirus_can_scan_system --> off
    antivirus_use_jit --> off
    auditadm_exec_content --> on
    authlogin_nsswitch_use_ldap --> off
    authlogin_radius --> off
    authlogin_yubikey --> off
    ...
    
  3. Get the status of a single boolean.

    If the boolean name is known, pass the name as an argument to get that specific boolean’s status.

    sudo getsebool virt_use_nfs
    
  4. Query the SELinux policy for a boolean.

    Ever wonder what a boolean triggers within the SELinux policy? SELinux provides a utility to query those rules.

    sesearch -b virt_use_nfs -A
    

    Example Output:

    allow fsdaemon_t autofs_t:dir { getattr open search }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:dir { getattr ioctl lock open read search }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:dir { getattr ioctl lock open read search }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:dir { getattr ioctl lock open read search }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:dir { getattr open search }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:dir { getattr open search }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:file { getattr ioctl lock open read }; [ virt_use_nfs ]:True
    allow fsdaemon_t nfs_t:lnk_file { getattr read }; [ virt_use_nfs ]:True
    ...
    
  5. Query if a boolean allows access.

    What about if particular access is allowed based on a conditional boolean? Answer the question: Does user ping permit the transition from a user domain (user_t) to the ping domain (ping_t)?

    sesearch -s user_t -t ping_t -c process -p transition -AT
    

    Example Output:

    allow user_t ping_t:process transition; [ selinuxuser_ping ]:True
    

    The transition is allowed if the user_ping SELinux boolean is enabled.

  6. Enable a boolean.

    Suppose we want to allow KVM to store images on a Samba share. There’s a boolean for that too.

    1. Find the boolean.

      sudo semanage boolean -l | grep virt | grep samba
      

      Example Output:

      virt_use_samba                 (off  ,  off)  Allow virt to use samba
      
    2. Change the boolean to enabled.

      sudo setsebool virt_use_samba on
      

      or

      sudo semanage boolean -m --on virt_use_samba
      
    3. Check the current status.

      getsebool virt_use_samba
      
    4. Ensure the change survives a reboot.

      sudo setsebool -P virt_use_samba on
      
  7. Show local SELinux policy customizations.

    Knowing that we have changed the default settings, we can show those local customizations.

    sudo semanage boolean -l -C
    

    Example Output:

    SELinux boolean                State  Default Description
    
    virt_use_samba                 (on   ,   on)  Allow virt to use samba
    

    The output shows that the default value is now on. The default value changed after the switch was made permanent and the pending values were written to the policy file on disk.

SELinux File Context

All files and directories are labeled with an SELinux context when running SELinux. We’ll examine a few commands for managing the file system labeling.

One familiar example is creating a new directory for Nginx’s document root.

  1. Create the new directory along with three files.

    sudo mkdir -p /web
    sudo touch /web/file{1,2,3}
    
  2. Check the new directory and file labeling.

    ls -lZ /web
    

    Example Output:

    total 0
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file1
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file2
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file3
    
    • The new directory’s context type and the files are default_t.

    Note: Newly created files and directories inherit the SELinux type of their parent directories.

  3. Make temporary label changes.

    As part of troubleshooting or testing, we can temporarily change the context.

    sudo chcon -R -t httpd_sys_content_t /web/
    
    ls -lZ /web
    
  4. Return labels to default settings.

    Switch the context back to the default context type.

    sudo restorecon -R -v /web/
    

    Example Output:

    Relabeled /web from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:default_t:s0
    Relabeled /web/file1 from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:default_t:s0
    Relabeled /web/file2 from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:default_t:s0
    Relabeled /web/file3 from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:default_t:s0
    
  5. Verify the change.

    ls -lZ /web
    

    Example Output:

    total 0
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file1
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file2
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file3
    
  6. Make label changes permanent.

    To make the changes permanent and survive a reboot, use the semanage fcontext command. The -a adds a record to the file /etc/selinux/targeted/contexts/files/file_contexts.local, and -t defines the type.

    sudo semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
    

    Note: When changing the SELinux context with semanage fcontext, using the full path to the file or directory is recommended to avoid mislabeling files after a file system relabeling or running restorecon.

  7. Check the context.

    ls -ldZ /web; ls -lZ /web
    

    Example Output:

    drwxr-xr-x. 2 root root unconfined_u:object_r:default_t:s0 45 Apr 14 19:00 /web
    total 0
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file1
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file2
    -rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 0 Apr 14 19:00 file3
    

    Notice the context did not change, which we expected.

  8. Show the context of the newly created files and directories.

    sudo semanage fcontext -C -l
    

    Example Output:

    SELinux fcontext                                   type               Context
    
    /var/oled/pcp(/.*)?                                all files          system_u:object_r:pcp_log_t:s0 
    /web(/.*)?                                         all files          system_u:object_r:httpd_sys_content_t:s0 
    
    SELinux Local fcontext Equivalence 
    
    /opt/rh/gcc-toolset-11/root = /
    /opt/rh/gcc-toolset-13/root = /
    
  9. Apply the changes to the context.

    sudo restorecon -R -v /web
    

    Example Output:

    Relabeled /web from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
    Relabeled /web/file1 from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
    Relabeled /web/file2 from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
    Relabeled /web/file3 from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
    
  10. Remove the new SELinux context.

    sudo semanage fcontext -d "/web(/.*)?"
    

    This example passes the regular expression used when creating the context and places it at the beginning of the context record on file. Since it’s a regular expression, enclose it within quotes.

  11. Apply the changes and verify the context returned to default_t.

    sudo restorecon -R -v /web; ls -ldZ /web; ls -lZ /web
    

Summary

This concludes the walkthrough demonstrating how to use these user-space tools. Check out the man pages for the utilities shown. Then, use what you learned to keep SELinux in Enforcing mode.

For More Information

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.