4.2. Policy Types - dhcpd

This section discusses the types associated with the dhcpd policy.

NoteNote
 

SELinux policy uses a number of macros written in the m4 macro language to make policy writing easier. In a type enforcement file such as dhcpd.te, macros are used extensively to call common capabilities for subjects and targets. These are discussed in Section 2.9 Policy Macros and Section 3.4 Common Macros in the Targeted Policy.

For the purposes of dissecting the dhcpd policy, this section is based on what is found in the policy.conf file. Since this file is created by the build process, the macros have been expanded entirely. It takes some practice, but soon you can find and understand the macros and the associated rulesets in the TE files from $SELINUX_SRC/domain/programs/.

dhcpd_t

This is the main, top-level domain for the dhcpd daemon. Nearly every rule in $SELINUX_SRC/domain/programs/dhcpd.te deals with this type, most notably the macros that expand into numerous rules. A complete list can be obtained using the apol tool. This is discussed further in Chapter 6 Tools for Manipulating and Analyzing SELinux. Some highlighted rules are:

  • Various specific manipulations of the dhcpd_*_t domains, as explained below in further examples under each context..

  • Network rules necessary for dhcpd to do its work, such as tcp_recv, udp_recv, and rawip_recv to network interfaces. Some examples are:

    allow dhcpd_t netif_type : netif { tcp_send udp_send 
      rawip_send }; 
    allow dhcpd_t node_type : node { tcp_recv udp_recv \
      rawip_recv }; 
  • Socket rules needed by dhcpd to create, listen, connect, accept, bind, read, write, control input and output (ioctl), get (getattr) and set (setattr) attributes, send (send_msg) and receive (recv_msg) messages, get (getopt) and set (setopt) command options, and so forth. Socket objects controlled are tcp_socket, udp_socket, netlink_route_socket, rawip_socket, unix_dgram_socket, unix_stream_socket, and reserved_port_socket. These are all object classes that SELinux controls the access to. Some examples are:

    allow dhcpd_t node_type : { tcp_socket udp_socket } \
      node_bind ; 
    allow dhcpd_t port_type : { tcp_socket udp_socket } \
      { send_msg recv_msg };
    allow dhcpd_t port_type : { tcp_socket udp_socket } \
      { send_msg recv_msg };
    allow dhcpd_t self : rawip_socket { create ioctl read \
      getattr write setattr append bind connect getopt \
      setopt shutdown }; 
    allow dhcpd_t self : tcp_socket { create ioctl read \
      getattr write setattr append bind connect getopt \
      setopt shutdown listen accept };
    allow dhcpd_t self : udp_socket { create ioctl read \
      getattr write setattr append bind connect getopt \
      setopt shutdown }; 
    allow dhcpd_t self : unix_dgram_socket { create \
      ioctl read getattr write setattr append bind \
      connect getopt setopt shutdown }; 
    allow dhcpd_t self : unix_stream_socket { create \
      ioctl read getattr write setattr append bind \
      connect getopt setopt shutdown }; 
  • As a network service, dhcpd is allowed to open a TCP or UDP socket to send and receive messages from any port. The attribute port_type covers a long list of ports: dns_port_t, dhcpd_port_t, http_cache_port_t, port_t, reserved_port_t, http_port_t, pxe_port_t, smtp_port_t, mysqld_port_t, rndc_port_t, ntp_port_t, portmap_port_t, postgresql_port_t, snmp_port_t, syslogd_port_t. The rule looks like this:

    allow dhcpd_t port_type:{ tcp_socket udp_socket } \
      { send_msg recv_msg };
  • This rule allows dhcpd to control the dhcpd_t type, that is, itself, for process signaling:

    allow dhcpd_t self : process { sigchld sigkill sigstop \
      signull signal fork };
dhcpd_exec_t

This is the file type for the dhcpd executable. This type is the entry point for the dhcpd_t domain.

dhcpd_port_t

The dhcpd_port_t type has one direct rule governing it:

allow dhcpd_t dhcpd_port_t : udp_socket name_bind;

The daemon with the domain of dhcpd_t, that is, dhcpd, has the permission to bind to the object class of udp_socket, which opens a UDP port. Policy states that UDP port 67 is created with the domain of dhcpd_port_t:

grep dhcpd_port_t $SELINUX_SRC/net_contexts
ifdef(`use_dhcpd', `portcon udp 67 system_u:object_r:\
  dhcpd_port_t')

SELinux has controls for port binding, meaning it is able to allow or deny port binding requests based on security labels. However, SELinux only controls attempts to bind to reserved ports, which are ports less than 1024, and to ports outside of the local port range, which is set in /proc/sys/net/ipv4/ip_local_port_range.

If dhcpd tries to bind to any port other than 67 port that is reserved or outside of the local range, the daemon is denied. This is because dhcpd_t is only allowed to bind to a port with the type of dhcpd_port_t, and only one port has that type, port 67.

dhcpd_state_t

This type dhcpd_state_t is the file type for the dhcpd lease file located at /var/lib/dhcp/dhcpd.leases. The dhcpd daemon is allowed to create, read, write, etc. a file with the context of dhcpd_state_t:

allow dhcpd_t dhcpd_state_t : file { create ioctl read \
  getattr lock write setattr append link unlink rename };
type_transition dhcpd_t dhcp_state_t : file dhcpd_state_t;

The second rule is a type_transition rule that comes from a macro defined in $SELINUX_SRC/macros/core_macros.te and used in the dhcpd.te file, file_type_auto_trans(dhcpd_t, dhcp_state_t, dhcpd_state_t, file).

This rule ensures that unless explicitly overwritten by the dhcpd daemon, when the daemon creates a regular file (object class file) in a directory with the type dhcpd_state_t, the file is automatically assigned the file context of dhcp_state_t. This allows the dhcpd daemon to fully control just the DHCP lease files in /var/lib/dhcp/ and not, for example, the dhclient files in the same directory.

This shows a case where the policy explicitly does not want a file to gain the default label from the parent directory. To prevent this, a type_transition is put into place to guide the context when the file is created.

dhcpd_tmp_t

There are several direct rules and transitions for dhcpd_tmp_t, and multiple indirect rules through the attribute file_type.

These rules describe how dhcpd_t can act upon an object of the type dhcpd_tmp_t, which is the type of the dhcpd temporary files in /tmp/. For example, dhcpd_t can create, read, and get and set file attributes on files, socket files, and FIFO files that have the type dhcpd_tmp_t. Similar actions can be done with directories (dir) and file linking (lnk_file):

allow dhcpd_t dhcpd_tmp_t : { file sock_file fifo_file } \
  { create ioctl read getattr lock write setattr append link \
  unlink rename };
allow dhcpd_t dhcpd_tmp_t : lnk_file { create read getattr \
  setattr link unlink rename };
allow dhcpd_t dhcpd_tmp_t : dir { create read getattr lock \
  setattr ioctl link unlink rename search add_name \
  remove_name reparent write rmdir };

Having this separate derived type isolates the dhcpd temporary files to ensure that only dhcpd can read and write these files, and not any other daemon. Similarly, other temporary files are protected by being in their own type that dhcpd cannot access. For example, this protects the daemon from using a malicious symlink in /tmp/.

These rules enable the dhcpd daemon to create its files and directories in /tmp. The first rule specifies that when the dhcpd_t domain creates a file in a directory with the type tmp_t, the new subdirectory should be labeled with the dhcpd_tmp_t type. Similarly, the second rule specifics the same transition for a file, file link, socket file, or FIFO (named pipe):

type_transition dhcpd_t tmp_t : dir dhcpd_tmp_t;
type_transition dhcpd_t tmp_t : { file lnk_file sock_file \
  fifo_file } dhcpd_tmp_t;

The indirect rules are derived from rules associated with the file_type attribute. These deal with allowing file systems to associate default file types, and the manipulation of file_type objects such as dhcpd_tmp_t by the unconfined_t domain:

allow { file_type device_type }  fs_t : filesystem associate;
allow file_type removable_t : filesystem associate;
allow file_type nfs_t : filesystem associate;
allow unconfined_t file_type : filesystem  *;
allow unconfined_t file_type : { dir file lnk_file sock_file \
  fifo_file chr_file blk_file } *;
allow unconfined_t file_type : { unix_stream_socket \
  unix_dgram_socket } name_bind;

The dhcpd_tmp_t type is also influenced by two generic neverallow assertions. Assertions are discussed in Section 2.8 TE Rules - Access Vectors.

dhcpd_var_run_t

This security context is also part of the file_type attribute and shares those rules with dhcpd_tmp_t and others. The direct rules that govern dhcpd_var_run_t allow the dhcpd_t domain to manipulate files and directories with the dhcpd_var_run_t type in the /var/run/ file system. This is the directory where process IDs exist, and this rule allows for the creation and manipulation of /var/run/dhcpd.pid :

allow dhcpd_t dhcpd_var_run_t : file  { create ioctl read \
  getattr lock write setattr append link unlink rename };
allow dhcpd_t dhcpd_var_run_t : dir  { read getattr lock \
  search ioctl add_name remove_name write };
type_transition dhcpd_t var_run_t : file dhcpd_var_run_t; 
dhcp_etc_t

The two direct rules using this type allow the dhcpd_t domain to read and get attributes on files of the type dhcp_etc_t, as well as search directories of the same type. This means the daemon cannot overwrite the configuration file. Indirect rules derive from the dhcp_etc_t type being part of the file_type attribute set, along with dhcpd_tmp_t, dhcpd_var_run_t, and others:

allow dhcpd_t dhcp_etc_t : file { read getattr };
allow dhcpd_t dhcp_etc_t : dir search; 
dhcp_state_t

In addition to being covered by the rules governing the file_type attribute, this file type has two direct policy rules. The first allows the dhcpd_t domain to perform standard file system functions, such as read, write, and lock on directories, with the type dhcp_state_t. This directory is defined as /var/lib/dhcp/ in $SELINUX_SRC/file_contexts/program/dhcpc.fc, and is where dhcpd stores its lease files. The second rule is the transition rule stating when the dhcpd_t domain creates a file in a directory labeled dhcp_state_t, this file gets a security type of dhcpd_state_t:

allow dhcpd_t dhcp_state_t : dir { read getattr lock search \
 ioctl add_name remove_name write };
type_transition dhcpd_t dhcp_state_t : file dhcpd_state_t;

NoteNote
 

There are two distinct security contexts being discussed here: dhcp_state_t and dhcpd_state_t.

dhcp_state_t is the type of the directory /var/lib/dhcp where both dhcpd and other clients and daemons store DHCP lease information.

dhcpd_state_t is the type in the security label of a DHCP lease file created in /var/lib/dhcp by the dhcpd daemon, running in the domain of dhcpd_t.

The dhcpd_state_t type is a derivative type, the way dhcpc_state_t derives from the dhcpc_t domain in a stricter policy.

In the /var/lib/dhcp directory, the only allowed actions of the dhcpd_t domain are a series of directory-level operations. The domain cannot affect the files within unless those files are of the type dhcpd_state_t:

allow dhcpd_t dhcpd_state_t:file { create ioctl read getattr lock \
  write setattr append link unlink rename };

This separation allows the different DHCP applications to keep lease information in the same, traditional directory, yet not be able to affect other DHCP program files.