SELinux

Activating and deactivating SELinux

A Linux kernel which supports SELinux can assume three modes: enforcing, where the kernel enforces the SELinux policy; permissive, where the kernel loads the policy but does not enforce its constraints; and disabled, where the kernel completely disables SELinux. Avoid the disabled mode because it can result in a mislabeled system which will not function if SELinux is reactivated. You can deactivate or activate enforcing mode temporarily by running the following commands:

setenforce 0
setenforce 1

The command getenforce will print the current enforcing status.

You can configure the SELinux mode which the kernel will adopt upon booting by editing /etc/syslinux/selinux.

SELinux labels

Under SELinux, system objects bear labels. You can use the standard Linux utilities to inspect these labels. Here are some examples:

Display the labels of filesystem nodes:

ls -Z

Recursively modify the label of part of the filesystem, and update the policy to retain the labels through a relabel:

chcon -v -R --type=mytype_file_t /path/to/branch
semanage fcontext -a -t mytype_file_t "/path/to/branch(/.*)?"

Restore the label of a filesystem node to the path’s SELinux policy default:

restorecon -v myfile.txt

Relabel the entire filesystem according to the SELinux policy:

touch /.autorelabel
reboot

Display the labels of TCP and UDP ports:

semanage port -l

Modify the label of a port:

semanage port -a -t mytype_port_t -p tcp 8080

Display the domains of running processes:

ps auxZ

Note that the domain a running process adopts is a function of the parent process’s domain, the label of the process’s program on disk, and the SELinux policy. One of these must be changes to modify the domain a process will run in.

SELinux booleans

The kernel permits the customization of many details about its SELinux policy through the use of boolean flags. To list the available booleans, along with their current status, run:

getsebool -a

You can modify a boolean by running statements such as:

setsebool -P httpd_can_network_connect_db on

Writing SELinux policy modules

Booleans only help tailor a policy to do things the original policy authors intended. When installing an uncommon program, an administrator might need to write an entirely new policy module. Here is a sample program in C, setoy.c, which we would like to constrain using a custom SELinux policy module:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
        int val;
        FILE *f = NULL;
        char buf[BUFSIZ];
        char *ptr = NULL;

        f = fopen ("setoy.txt", "r+");
        if (NULL == f) {
                perror("Could not open setoy.txt");
                exit(EXIT_FAILURE);
        }

        ptr = fgets(buf, BUFSIZ, f);
        if (NULL == ptr) {
                perror("Could not read setoy.txt");
                exit(EXIT_FAILURE);
        }

        val = fprintf(f, "%s\n", "Goodbye, cruel world!");
        if (val < 0) {
                perror("Could not write setoy.txt");
                exit(EXIT_FAILURE);
        }

        val = fclose(f);
        if (val != 0) {
                perror("Could not close setoy.txt");
                exit(EXIT_FAILURE);
        }

        f = fopen ("setoy2.txt", "w");
        if (NULL == f) {
                perror("Could not open setoy2.txt");
                exit(EXIT_FAILURE);
        }

        val = fprintf(f, "%s\n", "Goodbye, cruel world!");
        if (val < 0) {
                perror("Could not write setoy2.txt");
                exit(EXIT_FAILURE);
        }

        val = fclose(f);
        if (val != 0) {
                perror("Could not close setoy2.txt");
                exit(EXIT_FAILURE);
        }

        printf("All system calls succeeded: success (or failure?)\n");
        printf("Press enter to exit ");

        getchar();

        exit(EXIT_SUCCESS);
}

Here is a policy which constrains the program, mysetoy.te:

policy_module(mysetoy, 1.0.0)

# Must require any core policy definitions you use. This is similar to
# an import in Java or #include in C.
require {
        attribute file_type;
        type unconfined_t;
        role unconfined_r;
        type user_devpts_t;
        type user_home_t;
        type fs_t;
        class dir search;
        class chr_file { read write append getattr };
        class filesystem associate;
}

# ==============================================================================
# | Declare a number of types                                                  |
# ==============================================================================
type mysetoy_t;                 # The type we will assign to mysetoy processes.
type mysetoy_file_t, file_type; # Will assign to files mysetoy can read/write.
type mysetoy_exec_t;            # Will assign to the mysetoy program on disk.

# ==============================================================================
# | Allow/cause unconfined_t-domain processes to run mysetoy in mysetoy_t      |
# | domain.                                                                    |
# ==============================================================================
domain_type(mysetoy_t)
domain_entry_file(mysetoy_t, mysetoy_exec_t)
role unconfined_r types mysetoy_t;
type_transition unconfined_t mysetoy_exec_t:process mysetoy_t;

# ==============================================================================
# | Now we decide what SELinux will permit mysetoy to do.                      |
# ==============================================================================
# Allow mysetoy_t domain to read and write file objects labeled with mysetoy_file_t.
allow mysetoy_t mysetoy_file_t:file { open read write };

# Allow mysetoy_t domain to read and write the console.
allow mysetoy_t user_devpts_t:chr_file { read write append getattr };

# Allow mysetoy_t domain to enumerate contents of a directory in ~.
allow mysetoy_t user_home_t:dir search;

# Allow mysetoy_t domain to create a file in ~ ...
allow mysetoy_t user_home_t:dir { write add_name create };
allow mysetoy_t mysetoy_file_t:file { create };

# ... and ensure it bears the label mysetoy_t.
allow mysetoy_t fs_t:filesystem associate;
filetrans_pattern(mysetoy_t, user_home_t, mysetoy_file_t, file)

You can compile an SELinux policy with make -f /usr/share/selinux/devel/Makefile mysenettoy.pp, and you can install the compiled policy using semodule -i mysetoy.pp.

Properly running setoy will also require:

echo Hello, world\! >setoy.txt
chcon -v --type=mysetoy_exec_t setoy
chcon -v --type=mysetoy_file_t setoy.txt

SELinux logging and machine-assisted policy modules

SELinux logs policy violations to /var/log/audit/audit.log. The command audit2allow can help turn the logs which result from a policy being overly cautious into a new, more appropriate policy module for a program. This should be done with care, because most of the time the enforcement of the policy is precisely what ought to happen. Thus you should carefully review the results from audit2allow before loading it into the running policy. Sometimes it is helpful to avoid ignoring common failures (i.e., do-not-audit rules) using:

semodule -DB

Restore the do-not-audit rules with:

semodule -B

Other resources