1. Introduction
From fitness tracking watches to tire pressure monitoring sensors, the world is getting smarter one device at a time. But these devices also bring a myriad of new security threats that cannot be addressed by simply deploying your watch behind a Web Application Firewall (WAF). When discussing multi-tiered enterprise architecture, file system permissions and access control are the last line of defense. However, for embedded devices and the Internet of Things, Linux access controls may indeed be the only line of defense. In light of this renewed relevancy, this article revisits the current state of the various access control frameworks and explains their different philosophies and methods of configuration.
2. Discretionary Access Control (DAC)
Historically, because Linux originated as an open source alternative to UNIX, it inherited UNIX’s Discretionary Access Control (DAC) security mechanism, which governs access based on user ownership and file permissions. File permissions can be set to allow the owner, members of a group, or anyone to read (r), write (w), or execute (x) and are concisely referred to by a numeric mode. The most restrictive permission DAC is capable of setting is 0400 which marks a file as readable by only the owner (and any process run by the owner). However, the root user is particularly powerful and is allowed to bypass the permission policy completely.
-r-------- 400 owner can read
-rw------- 600 owner can read and write
-rwx------ 700 owner can read, write, and execute
----rwx--- 070 group can read, write, and execute
-rw-rw---- 660 owner and group can read and write
-rwxr-xr-x 755 owner can read, write, and execute;
everyone else can read and execute
-rwxrwxrwx 777 anyone can read, write, and execute
DAC was never really designed to limit the impact of modern attacks and exploitation techniques such as remote code execution (RCE) or command injection vulnerabilities. On a typical Linux system all of the executables in /bin (and /sbin, /usr/bin, ...) can be run by any user (with the permissions of 0755). This means that the www-data user (the default account used by Apache and Ngnix) can execute vim, tcpdump, or any other program on the system even if there is no legitimate reason for that user to do so. Because processes inherit the rights of the effective user, there is no concept of giving various processes (running as the same user) different permissions. At the same time, the discretionary nature of DAC means that access rights can be relinquished freely by the owner of a file. In other words, it’s really easy to shoot yourself in the foot. The all-or-nothing style elevation of privilege to root is also very risky, especially for networked services which need access to RAW network sockets but really shouldn’t have all of the privileges of the superuser.
3. Linux Security Modules (LSM)
Over the years the need for more granular security controls resulted in the creation of several different security extensions to the kernel, most notably, the Linux Security Modules (LSM). LSM is an API that provides a set of hooks into the kernel at every security-critical point. For backwards compatibility, the LSM hooks operate in addition to DAC. When access to an object is requested, the DAC security checks are performed first. If DAC allows the operation, the LSM hooks are then invoked which can also allow or deny the operation.
As a kernel API, LSM makes it possible for authors to create any kind of access control mechanism they want. That means, however, that working with LSM is not as simple as editing configuration files. To bridge this gap, there are now many different security frameworks, built on top of the LSM kernel API, each with its own philosophy and means of policy definition. The most notable frameworks are those built to provide Mandatory Access Control (MAC).
4. Mandatory Access Control (MAC)
In the nomenclature of access control philosophies, DAC is considered discretionary because permission is chosen by the owner of an object. Users can grant permission to other users by setting the permission mode of a file. In contrast, Mandatory Access Control (MAC) systems have a central policy that users cannot override (at their discretion). The exact configuration mechanism varies depending on the implementation, but all MAC frameworks provide the means to allowlist what a process, not just a user, can access.
Without MAC, a remote code execution (RCE) exploit can cause the Apache process to spawn a shell because /bin/bash is executable by all users, including www-data, even though the Apache process may never legitimately need to execute a shell. To prevent this, a MAC policy could be defined to allowlist exactly which shared libraries, files, and other executables Apache is allowed to access. Hence, not only would the Apache process not be able to launch the /bin/bash executable, it would also not be able to read any file, load any shared library, or list the contents of any directory not explicitly permitted by a restrictive policy. The overall security improvement is significant.
Security Enhanced Linux (SELinux) is a MAC framework based on the principle of least privilege which was released by the National Security Agency (NSA) shortly after the Linux kernel introduced support for LSMs. SELinux has a reputation for being difficult to configure, but the management tools have improved in recent years. SELinux policy enforcement will restrict every executable on the system but can also be configured to only enforce security policies for targeted processes only. Policy definitions are based on the concept of labeling and type enforcement. Labels are stored in extended file attributes (similar to ownership and permissions with DAC) and provide a way to group objects for the purpose of defining the policy. Overly simplifying for the sake of illustration, suppose the label X was set on a file and the label Y on a process, then a policy could be created to only allow sources with label Y to access target files with label X. Unfortunately, at the present time, the tools for SELinux configuration management seem to only be supported in the Redhat and Centos distributions.
AppArmor was designed to simplify configuration of MAC and will only enforce policies for selected processes. Instead of using labels stored as file attributes, AppArmor policy definitions are based on file paths which, in practice, is significantly easier to maintain. A process, identified by its path, can have a policy defined to only allow it to read, write, or execute other files based on their path. AppArmor policies also support globbing and can specify whether or not child processes inherit the policy. AppArmor is particularly effective when used to sandbox network services and is supported on a wide variety of Linux distributions including Ubuntu.
Grsecurity is a collection of security enhancements to the kernel that also add support for Role Based Access Control (RBAC). RBAC is a more flexible alternative to MAC that uses fine-grained roles (analogous to groups) to create a system of least privilege. Grsecurity also includes other security improvements such as an improved chroot.
Smack is another MAC framework that is very similar to SELinux but designed with embedded devices in mind. Like SELinux, security labels are stored in extended file attributes and access control policies are defined in terms of what subjects (processes) can access which objects (passive entities).
5. Linux Capabilities
No discussion of access control would be complete without acknowledging the fact that not every operation involves file permissions. Opening a network socket to listen on a port, accessing raw network sockets, or using ptrace to debug another process are a few examples of actions that can be performed via the Linux system call interface not governed by file permissions.
Prior to Linux kernel version 2.2 the kernel permission checks for these actions were based on the effective UID of the process and access was all-or-nothing. Processes running as root (UID 0) could perform any action and all other users were considered unprivileged. This is why it used to be necessary mark certain executables such as tcpdump and Wireshark as SETUID 0. However, this was very dangerous (especially at Defcon) where packets were frequently crafted to target vulnerable Wireshark dissectors giving the attacker root.
However, since Linux version 2.2 the privileges of the root user have been partitioned into distinct "capabilities" which can be individually attributed to the process itself (as opposed to the effective user). Instead of setting the permission mode of a binary to be SETUID, granular capabilities can now be set on a process binary and stored in extended file attributes which enable it to perform selective administrative actions without granting it all of the privileges of root.
For example, to enable a process like tcpdump to access raw networking sockets without having to run it as root, one could grant it just the CAP_NET_RAW capability (using the setcap command). Administrators can also fine-tune whether or not child processes inherit the capabilities. However, it’s important to realize that adding capabilities to a process can inadvertently elevate the privileges of every user on the system. In the above example, before the capability was added to tcpdump only the root user could capture traffic. Because the tcpdump binary is executable by every user on the system (DAC), if the capability is added, then every user can now use tcpdump to monitor network traffic. Hence, it's recommended that execution be restricted to a specific group of users.
6. Conclusion
As shown above, Discretionary Access Controls, which are still used by the majority of systems today, have intrinsic weaknesses that cannot be overlooked. On the other hand, there are now several viable Mandatory Access Control frameworks to choose from each with it’s own flavor of configuration. MAC is especially relevant in the embedded world because users rarely need direct access to the file system; let alone the discretionary ability to grant other users permission. In conclusion, whether you are designing systems big or small, MAC is extremely effective at protecting against code execution vulnerabilities and should be leveraged.