New SELinux Feature: File Name Transitions

In Red Hat Enterprise Linux 7, we have fixed one of the biggest issues with SELinux where initial creation of content by users and administrators can sometimes get the wrong label.

The new feature makes labeling files easier for users and administrators. The goal is to prevent the accidental mislabeling of file objects.

Accidental Mislabeling

Users and administrators often create files or directories that do not have the same label as the parent directory, and then they forget to fix the label. One example of this would be an administrator going into the /root directory and creating the .ssh directory. In previous versions of Red Hat Enterprise Linux, the directory would get created with a label of admin_home_t, even though the policy requires it to be labeled ssh_home_t. Later when the admin tries to use the content of the .ssh directory to log in without a password, sshd (sshd_t) fails to read the directory’s contents because sshd is not allowed to read files labeled admin_home_t. The administrator would need to run restorecon -R -v /home/.ssh to fix the labels, and often they forget to do so.

Another example would be a user creating the public_html directory in his home directory. The default label for content in the home directory is user_home_t, but SELinux requires the public_html directory to be labeled http_user_content_t, which allows the Apache process (httpd_t) to read the content. We block the Apache process from reading user_home_t as valuable information like user secrets and credit-card data could be in the user’s home directory.

File Transitions Policy

Policy writers have always be able to write a file transition rule that includes the type of the processes creating the file object (NetworkManger_t), the type of the directory that will contain the file object (etc_t), and the class of the file object (file). They can also specify the type of the created object (net_conf_t):

filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t)

This policy line says that a process running as NetworkManager_t creating any file in a directory labeled etc_t will create it with the label net_conf_t.

Named File Transitions Policy

Eric Paris added a cool feature to the kernel that allows the kernel to label a file based on four characteristics instead of just three. He added the base file name (not the path).

Now policy writers can write policy rules that state:

  • If the unconfined_t user process creates the .ssh directory in a directory labeled admin_home_t, then it will get created with the label ssh_home_t: `filetrans_pattern(unconfined_t, admin_home_t, dir, ssh_home_t, “.ssh”)
  • If the staff_t user process creates a directory named public_html in a directory labeled user_home_dir_t, it will get labeled http_user_content_t: `filetrans_pattern(staff_t, user_home_dir_t, dir, http_user_content_t, “public_html”)

Additionally, we have added rules to make sure that if the kernel creates content in /dev, it will label it correctly rather than waiting for udev to fix the label.

filetrans_pattern(kernel_t, device_t, chr_file, wireless_device_t, "rfkill")

Better Security

This can also be considered a security enhancement, since in Red Hat Enterprise Linux 6, policy writers could only write rules based on the the destination directory label. Consider the example above using NetworkManager_t. In Red Hat Enterprise Linux 6, a policy writer would write filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t), which means the networkmanager process could create any file in an etc_t directory (/etc) that did not exist. If for some reason the /etc/passwd file did not exist, SELinux policy would not block NetworkManager_t from creating /etc/passwd. In Red Hat Enterprise Linux 7, we can write a tighter policy like this:

filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t, "resolv.conf")

This states that NetworkManger can only create files named resolv.conf in directories labeled etc_t. If it tries to create the passwd file in an etc_t directory, the policy would check if NetworkManager_t is allowed to create an etc_t file, which is not allowed.

Bottom Line

This feature should result in less occurrences of accidental mislabels by users and hopefully a more secure and better-running SELinux system.

New Red Hat Enterprise Linux 7 Security Feature: systemd-journald

A lot has already been written about systemd-journald. For example, this article describes the security benefits of the journal.

I would argue that systemd-journal is not a full replacement for syslog. The syslog format is ubiquitous, and I don’t see it going away. On all Red Hat Enterprise Linux 7 machines, syslog will still be on by default. This is because it’s still the defacto mechanism for centralizing your logging data, and most tools that analyze log data read syslog data. The journald actually makes syslog better, as syslog gathers its data from the journal, and because the journal runs from bootup to shutdown, it can feed more data to syslog, saving it until the syslog process starts.

When journald was first being created, many people who were working on Structured Logging got all up in arms over it because Lennart Poettering and Kay Sievers did not work with them. Despite that problem, I still like it.

When it comes to launching system apps, systemd has become the central point. It can be thought of as the systems process manager. It knows more about what is going on in the system then any other process, save for the kernel.

Years ago when the audit system was being built, Karl MacMillan of Tresys believed that some of the problems that the audit system was trying to fix could be handled by extending syslog to record all information about the sending process. You see syslog records very little metadata about who sent the syslog message. The audit subsystem was created to record all of the critical identity data, such as all of the UIDs associated with a process as well as the SELinux context; journald now collects all of data.

Let me give an example of where systemd-journal could be used to increase security.

SELinux controls what a process is allowed to do based on what it was designed to do. Sometimes even less, depending on the security goals of the policy writer. This means SELinux would prevent a hacked ntpd process from doing anything other then handling Network Time. SELinux would prevent the hacked ntpd from reading MySQL databases or credit-card data from a user’s home directory, even if the ntpd process was running as root. However, as the ntpd process sends syslog messages, SELinux would allow the hacked process to continue to send syslog messages.

The hacked ntpd could format syslog messages to match other daemons and potentially trick an administrator or (even better) a tool that reads the syslog file (like intrusion detection tools) into doing something bad. If all messages were verified with the systemd-journal, then the administrator or syslog analysis tool could see that ntpd_t was sending messages forged as if they were coming from the sshd daemon. The intrusion detection tools, realizing the ntpd daemon had been hacked, could then be coded to recognize those bad messages.

.cursor=s=f328cc4b2615417189ab76b00c7ae041;i=2;b=4c3d0faf6b774fb7930972c1a4a5f87
.realtime=1329940273078467
...skipping...
SYSLOG_IDENTIFIER=sshd
SYSLOG_PID=2302
MESSAGE=sshd Fake message from sshd.
_PID=2302
_UID=0
_GID=0
_COMM=ntpd
_EXE=/usr/sbin/ntpd
_CMDLINE=/usr/sbin/ntpd -n -u ntp:ntp -g
_SYSTEMD_CGROUP=/system/ntpd.service
_SYSTEMD_UNIT=ntpd.service
_SELINUX_CONTEXT=system_u:system_r:ntpd_t:s0
_SOURCE_REALTIME_TIMESTAMP=1330527027590337
_BOOT_ID=4c3d0faf6b774fb7930972c1a4a5f870
_MACHINE_ID=432d8198a8fc421caf2dca48ccde1cf2\
_HOSTNAME=x.example.com

New SELinux Feature: File Name Transitions

In Red Hat Enterprise Linux 7, we have fixed one of the biggest issues with SELinux where initial creation of content by users and administrators can sometimes get the wrong label.

The new feature makes labeling files easier for users and administrators. The goal is to prevent the accidental mislabeling of file objects.

Accidental Mislabeling

Users and administrators often create files or directories that do not have the same label as the parent directory, and then they forget to fix the label. One example of this would be an administrator going into the /root directory and creating the .ssh directory. In previous versions of Red Hat Enterprise Linux, the directory would get created with a label of admin_home_t, even though the policy requires it to be labeled ssh_home_t. Later when the admin tries to use the content of the .ssh directory to log in without a password, sshd (sshd_t) fails to read the directory’s contents because sshd is not allowed to read files labeled admin_home_t. The administrator would need to run restorecon -R -v /home/.ssh to fix the labels, and often they forget to do so.

Another example would be a user creating the public_html directory in his home directory. The default label for content in the home directory is user_home_t, but SELinux requires the public_html directory to be labeled http_user_content_t, which allows the Apache process (httpd_t) to read the content. We block the Apache process from reading user_home_t as valuable information like user secrets and credit-card data could be in the user’s home directory.

File Transitions Policy

Policy writers have always be able to write a file transition rule that includes the type of the processes creating the file object (NetworkManger_t), the type of the directory that will contain the file object (etc_t), and the class of the file object (file). They can also specify the type of the created object (net_conf_t):

filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t)

This policy line says that a process running as NetworkManager_t creating any file in a directory labeled etc_t will create it with the label net_conf_t.

Named File Transitions Policy

Eric Paris added a cool feature to the kernel that allows the kernel to label a file based on four characteristics instead of just three. He added the base file name (not the path).

Now policy writers can write policy rules that state:

  • If the unconfined_t user process creates the .ssh directory in a directory labeled admin_home_t, then it will get created with the label ssh_home_t: `filetrans_pattern(unconfined_t, admin_home_t, dir, ssh_home_t, “.ssh”)
  • If the staff_t user process creates a directory named public_html in a directory labeled user_home_dir_t, it will get labeled http_user_content_t: `filetrans_pattern(staff_t, user_home_dir_t, dir, http_user_content_t, “public_html”)

Additionally, we have added rules to make sure that if the kernel creates content in /dev, it will label it correctly rather than waiting for udev to fix the label.

filetrans_pattern(kernel_t, device_t, chr_file, wireless_device_t, "rfkill")

Better Security

This can also be considered a security enhancement, since in Red Hat Enterprise Linux 6, policy writers could only write rules based on the the destination directory label. Consider the example above using NetworkManager_t. In Red Hat Enterprise Linux 6, a policy writer would write filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t), which means the networkmanager process could create any file in an etc_t directory (/etc) that did not exist. If for some reason the /etc/passwd file did not exist, SELinux policy would not block NetworkManager_t from creating /etc/passwd. In Red Hat Enterprise Linux 7, we can write a tighter policy like this:

filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t, "resolv.conf")

This states that NetworkManger can only create files named resolv.conf in directories labeled etc_t. If it tries to create the passwd file in an etc_t directory, the policy would check if NetworkManager_t is allowed to create an etc_t file, which is not allowed.

Bottom Line

This feature should result in less occurrences of accidental mislabels by users and hopefully a more secure and better-running SELinux system.

New Red Hat Enterprise Linux 7 Security Feature: PrivateTmp

One of the reasons I am really excited about Red Hat Enterprise Linux 7 is the amount of new security features we have added, and not all of them involve SELinux.

Today, I want to talk about PrivateTmp.

One of my goals over the years has been to stop system services from using /tmp. I blogged about this back in 2007.

Anytime I have discovered a daemon using /tmp, I have tried to convince the packager to move the temporary content and FIFO files to the /run directory. If the content was permanent, then it should be in /var/lib. All users on your system are able to write to /tmp, so if an application creates content in /tmp that is guessable (i.e., has a well-known name), a user could create a link file with that name in /tmp and fool the privileged app to unlink or overwrite the destination of the link. Not only would you have to worry about users doing this, but you would also have to worry about any application that the user runs and any service that you have running on your system. They are all allowed to write to /tmp based on permissions.

Over the years, there have been several vulnerabilities (CVEs) about this. For example, CVE-2011-2722 covered a case where hplib actually included code like this:

fp = fopen ("/tmp/hpcupsfax.out", "w"); // <- VULN
system ("chmod 666 /tmp/hpcupsfax.out"); // <- "

This means that if you set up a machine running the cups daemon, a malicious user or an application that a user ran could attack your system.

I have convinced a lot of packages to stop using /tmp, but I can’t get them all. And in some cases, services like Apache need to use /tmp. Apache runs lots of other packages that might store content in /tmp.

Well, systemd has added a lot of new security features (more on these later).

PrivateTmp, which showed up in Fedora 16, is an option in systemd unit configuration files.

> man system.unit
  ...
  A unit configuration file encodes information about a service, 
  a socket, a device, a mount point, an automount point, a  swap
  file or partition, a start-up target, a file system path or a
  timer controlled and supervised by systemd(1).

> man systemd.exec
  NAME
    systemd.exec - systemd execution environment configuration
  SYNOPSIS
    systemd.service, systemd.socket, systemd.mount, systemd.swap
  DESCRIPTION
    Unit configuration files for services, sockets, mount points
    and swap devices share a subset of configuration options which
    define the execution environment of spawned processes.
  ...
  PrivateTmp=
    Takes a boolean argument. If true sets up a new file system
    namespace for the executed processes and mounts a private /tmp
    directory inside it, that is not shared by processes outside of
    the namespace. This is useful to secure access to temporary files
    of the process, but makes sharing between processes via /tmp
    impossible. Defaults to false.

PrivateTmp tells systemd to do the following anytime it starts a service with this option turned on:

   Allocate a private "tmp" directory
   Create a new file system namespace 
   Bind mount this private "tmp" directory within the namespace over
   /tmp
   Start the service. 

This means that processes running with this flag would see a different and unique /tmp from the one users and other daemons sees or can access.

NOTE: We have found bugs using PrivateTmp in Fedora 16, so make sure you test this well before turning it on in production.

For Fedora 17, I opened a feature page that requested all daemons that were using systemd unit files and /tmp to turn this feature on by default.

Several daemons, including Apache and cups, now have PrivateTmp turned on by default in Red Hat Enterprise Linux 7.

Given the three options as a developer of system service, I still believe that you should not use /tmp. You should instead use /run or /var/lib. But if you have to use /tmp and do not communicate with other users, then use PrivateTmp. If you need to communicate with users, be careful….