Magazine

Controlling Process Communications Using SELinux

Posted on the 12 June 2021 by Satish Kumar @satish_kumar86

Linux applications communicate with each other either directly or over a network. But the difference between direct communication and networked communication, from an application programmer’s point of view, is not always that big. Let’s look at the various communication methods that Linux supports and how SELinux aligns with them.

Using shared memory

The leastnetwork-like method is the use of shared memory. Applications can share certain parts of the memory with each other and use those shared segments to communicate between two (or more) processes. To governaccess to the shared memory, application programmers can usemutual exclusions(mutexes) orsemaphores. A semaphore is an atomicallyincremented or decremented integer (ensuring that two applications do not overwrite each other’s values without knowing about the value change), whereas a mutex can be interpreted as a special semaphore that only takes the values 0 or 1.

On Linux, two implementations exist for shared memory access and control: SysV-style and POSIX-style. We will not dwell on the advantages and disadvantages of each, but rather look at how SELinux governs access to these implementations.

SELinux controls the SysV-style primitives through specific classes:semfor semaphores andshmfor shared memory. The semaphores, mutexes, and shared memory segments inherit the context of the first process that creates them.

Administrators who want to control the SysV-style primitives can use the variousipc*commands:ipcs(to list),ipcrm(to remove), andipcmk(to create).

For instance, let’s first list the resources and then remove the listed shared memory:

# ipcs
...
------ Shared Memory Segments ------
key		shmid	owner		perms	bytes	nattch	status
0x0052e2c1	0	postgres	600	56	6
# ipcrm -m 0

When POSIX-style semaphores, mutexes, and shared memory segments are used, SELinux controls those operations through the file-based access controls. The POSIX-style approach uses regular files in /dev/shm, which is simpler for administrators to control and manage.

Communicating locally through pipes

A secondlarge family of communication methods in operating systems is the use of pipes. As the name implies, pipes are generally one-way communication tunnels, with information flowing from one (or more) senders to one receiver (there are exceptions to this, such as Solaris pipes, which act as bidirectional channels, butthose are not supported on Linux). Another name for a pipe isfirst-in, first-out(FIFO).

We have twotypes of pipes in Linux:anonymous pipes(also known asunnamed pipes) andnamed pipes. Thedifference is that a named pipe uses a file in theregular filesystem as its identification, whereas anonymous pipes are constructed through the applications with no representation in the regular filesystem.

In bothcases, SELinux will see the pipes as files of thefifo_fileclass. Named pipes will have their path associated with the regular filesystem and are created using themknodormkfifocommands (or through themkfifo()function when handled within applications). Anonymous pipes, however, will be shown as part of thepipefsfilesystem. This is a pseudo filesystem, not accessible to users, but still represented as
a filesystem through Linux’svirtual file system(VFS) abstraction.

From an SELinux policy point of view, the FIFO file is the target for which the access controls apply: two domains that both have the correct set of privileges toward the context of the FIFO file will be able to communicate with each other.

Administrators can find out which process is communicating over FIFOs with other processes through tools such aslsof, or by querying the/procfilesystem (as part of the/proc/<pid>/fdlistings). Thelsoftool supports the-Zoption to show the SELinux context of the process, and even supports wildcards:

# lsof -Z *:postfix_*

In this example, lsof displays information about all processes that use a postfix_* label.

Conversing over UNIX domain sockets

Withpipes supporting one-way communication only, any conversation between two processes would require two pipes. Also, true client/server-like communication with pipes is challenging to implement. To accomplish the more advanced communication flows, processes will use sockets.

Most administrators are aware that TCP and UDP communication occurs over sockets. Applications can bind to a socket and listen for incoming communications or use the socket to connect to other, remote services. But even on a single Linux system, sockets can be used to facilitate the communication flows. There are two socket types that can be used for process communication: UNIXdomain sockets and netlink sockets.Netlink socketsare specific to the Linux operating system and are quite low-level, resembling theioctl()system call usage.UNIX domain sockets, on the other hand, are higher-level and more directly accessible by administrators, which is why we explain them here in more detail.

We can distinguish between two UNIX domain socket definitions, as with pipes: unnamed socketsand named sockets. And like pipes, the distinction is in the path used to identify a socket. Named sockets are created on the regular filesystem, while unnamed sockets are part of thesockfspseudo filesystem. Similarly, sockets can be queried through utilities such aslsofor through the/proc/<pid>/fdlistings.

There is another distinction regarding UNIX domain sockets though, namely, the communicationformat that the UNIX domain socket allows. UNIX domain sockets can be created asdatagram sockets(data sent to the socket retains its chunk sizeand format) orstreaming sockets(data sent to the socket can be read in different-sized chunks). This has some repercussions for the SELinux policy rules.

For SELinux, communicating over UNIX domain sockets requires both domains to have the proper communication privileges toward the socket file type (open,read, andwrite), depending on the direction of the communication.

Additionally, the sending (client) domain requires additional privileges toward the receiving (server) domain:

  • Theconnecttoprivilege in theunix_stream_socketclass in the case of stream sockets
  • Thesendtoprivilege in theunix_dgram_socketclass in the case of datagram sockets

As you can see, the privileges depend on the communication type used across the socket.

Understanding netlink sockets

Another sockettype that can be used for process communication is netlink.Netlink socketsare sockets that allow user space applications tocommunicate and interact with kernel processes, and, in special cases (where network management is delegated to a user space process by the Linux kernel), also communicate with another user space application. Unlike the regular UNIX domain sockets, whose target context associates with the owner of that socket, netlink sockets are always local to the SELinux context.

Put differently, when a domain such assysadm_twants to manipulate the kernel’s routing information, it will open and communicate with the kernel through a netlink route socket, identified through thenetlink_route_socketclass:

$ sesearch -s sysadm_t -t sysadm_t -c netlink_route_socket -A
allow sysadm_t domain:netlink_route_socket getattr;
allow sysadm_t sysadm_t:netlink_route_socket { append bind ... };

As applications gain more features, it might be that some of these features are no longer allowed by the current SELinux policy. Administrators will then need to update the SELinux policy toallow the netlink communication.

An overview of supported netlink sockets can be devised from the netlink information on the manual page (man netlink), from which the SELinux classes can easily be derived. For instance, theNETLINK_XFRMsocket is supported through the SELinuxnetlink_xfrm_socketclass.

Dealing with TCP, UDP, and SCTP sockets

When wego further up the chain, we look atsocket communicationover the network. In this case, rather than communicating directly between processes (and thus in Linux terminology between SELinux domains), the flows are from, and to, TCP, UDP, andStream Control Transmission Protocol(SCTP) sockets.

SELinux willassign types to these ports as well, and these types are then the types to use for socket communication. For SELinux, a client application connecting to the DNS port (TCP port53, which receives thedns_port_ttype in most SELinux policies) uses thename_connectpermission within thetcp_socketclass toward the port type. The SCTP protocol (with thesctp_socketclass) uses the same permission. For UDP services (and thus theudp_socketclass),name_connectis not used. Daemon applications use thename_bindprivileges to bind themselves to their associated port.

Note:

Support for SCTP has only been recently introduced in SELinux, and not all Linux distributions have updated their policies accordingly. To see whether SCTP support is active, check the value of the /sys/fs/selinux/policy_capabilities/extended_socket_class file. A value of 1 means that the policy has SCTP support included, whereas a value of 0 (or an absent file) means that the system does not yet support SCTP.

Administrators can fine-tune which label to assign to which TCP, UDP, or SCTP port. For this, the semanage port command can be used. For instance, to list the current port definitions, you’d use this command:

# semanage port -l
SELinux Port Type	Proto	Port Number
afs3_callback_port_t	tcp	7001
...
http_port_t		tcp	80, 81, 443, 488, 8008, 8009, ...

In this example, we see that thehttp_port_tlabel is assigned to a set of TCP ports. Web server domains that can bind tohttp_port_tare, as such, allowed to bind to any of the mentioned ports.

To allow adaemon, such as an SSH server, tobind to other (or additional) ports, we need to tell SELinux to map this port to the appropriate label. For instance, toallow the SSH server to bind to port10122, we first check whether this port already holds a dedicated label. This can be accomplished using thesepolicycommand:

$ sepolicy network -p 10122
10122: udp unreserved_port_t 1024-32767
10122: tcp unreserved_port_t 1024-32767
10122: sctp unreserved_port_t 1024-32767

The unreserved_port_t label is not a dedicated one, so we can assign the ssh_port_t label to it:

# semanage port -a -t ssh_port_t -p tcp 10122

Removing a port definition works similarly:

# semanage port -d -t ssh_port_t -p tcp 10122

When a specific port type is already assigned, then the utility will give the following error:

# semanage port -a -t ssh_port_t -p tcp 80
ValueError: Port tcp/80 already defined

If this is the case and another port cannot be used, then no option exists other than to modify the SELinux policy.

Listing connection contexts

Many of the tools in an administrator’s arsenal can display security context information. As with the core utilities, most of these tools use the -Z option for this. For instance, to list the running network-bound services, netstat can be used:

# netstat -naptZ | grep ':80'
tcp  0  0 0.0.0.0:80  0.0.0.0:* LISTEN 17655/nginx: master system_u:system_r:httpd_t:s0

Even lsof displays the context when asked to:

# lsof -i :80 -Z
COMMAND PID   SECURITY-CONTEXT             USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx   17655 system_u:system_r:httpd_t:s0 root 8u IPv4 31230  0t0      *:http (LISTEN)

Anotheradvanced command for querying connections is thesscommand. Just callingsswill display all the connections of the current system. When adding-Z, it adds the context information as well.

For instance, the following command queries for listening TCP services:

# ss -ltnZ

More advanced queries can be called as well — consult the ss manual page for more information.

Note:

The use of the -Z option to show SELinux context information or consider SELinux context information in the activity that is requested by the user is a general but not mandatory practice amongst application developers. It is recommended to check the manual page of the application to confirm whether, and how, SELinux is supported by a tool. For instance, to get the ss manual page, run man ss

All these interactions are still quite primitive in nature, with the last set (which focuses on sockets) being more network-related than the others. Once we look into interaction between systems, we might not have enough control through just the sockets though. To enable more fine-grained control, we’ll look at firewall capabilities and their SECMARK support next.


Back to Featured Articles on Logo Paperblog