Application allowlisting is the practice of specifying an index of approved applications or executable files that are permitted to run on a system by a specific user. This is often used on a multi-user system or some kind of a shared hosting server, where multiple users exist and they have to be given limited permissions, so that they can only run approved applications on the shared system.
Note: A lot of external documentation uses the term “whitelist” in the place of allowlist and “blacklist” in the place of denylist. Red Hat is trying to be more inclusive by eradicating problematic language.
Red Hat Enterprise Linux (RHEL) and many other distributions have SELinux available, which can be used to effectively block applications which are not explicitly allow listed, and commercial products are also available. However technologies like SELinux are designed to control application behaviour but do not know which applications are trusted. Therefore SELinux is complementary to other technologies because they handle different aspects of system security.
One way to implement application allowlisting is by permitting applications that are known by some reputation source to execute or open certain files. Applications that are unknown by the reputation source are not allowed to execute. Currently, reputation sources could be the RPM databases, or an admin defined list of trusted files. Red Hat Enterprise Linux 8 ships the File Access Policy Daemon (fapolicyd) application allowlisting daemon.
Configuring fapolicyd
There are two policy files which are shipped by default in RHEL 8. The known-libs policy is designed to only block execution of untrusted files while only allowing trusted libraries. This provides good performance while ensuring that there is not much interference by the daemon.
The restrictive policy is designed to be as safe as possible. It’s intended to block execution via the runtime linker and only allow execution by trusted ELF and python programs. It also enforces that only trusted libraries are allowed. It blocks execution by other languages and must be explicitly enabled.
Each of these policies can be tweaked to suit company policy requirements. More details about various configuration options are available on the Red Hat Product Documentation page.
How it actually works
Fapolicyd uses the FAN_OPEN_EXEC_PERM fanotify event from the kernel. The fanotify API provides notification and interception of filesystem events. Events of FAN_OPEN_EXEC_PERM type will be generated when a file has been opened by using either execve(), execveat(), or uselib() system calls.
When a program opens a file or calls execve, that thread has to wait for fapolicyd to make a decision. To make a decision, fapolicyd has to look up information about the process and the file being accessed. Each system call fapolicyd makes will slow down the system. This may introduce some performance issues, especially when the policy file is quite large. Various methods like caching are used to increase performance. This diagram broadly summarizes the way fapolicyd works.
Some other things to consider
Managing trust
Fapolicyd uses lmdb as a backend database for its trusted software list. You can find this database in /var/lib/fapolicyd/
. This list gets updated whenever packages are installed by yum
, by a plugin. If packages are installed by rpm
instead of yum
, fapolicyd does not get a notification. In that case, you would also need to tell the daemon that it needs to update the trust database. This is done by running fapolicyd-cli
and passing along the --update
option. Also, if you add or delete files from the admin defined file trust list, fapolicyd.trust, then you will also have to run the fapolicyd-cli
utility.
How is file integrity check maintained?
Version 0.9.5 and later supports three modes of integrity checking. When integrity checking is enabled, fapolicyd will decide not only if the file is this trusted or not, but also if the file has been tampered with. If that is the case, then it will deny access to the file/executable. The first integrity mode is based on file size. In this mode, fapolicyd will take the size information from the trust db and compare it with the measured file size. This test incurs no overhead since the file size is collected when establishing uniqueness for caching purposes. This mode is intended to detect accidental overwrites as opposed to malicious activity where the attacker can make the file size match.
The second mode is based on using Integrity Measurement Architecture (IMA) to calculate SHA256 hashes and make them available through extended attributes. This incurs only the overhead of calling fgetxattr which is fast since there is no path name resolution. The file system must support i_version. For XFS, this is enabled by default. For other file systems, this means you need to add the i_version mount option. In either case, IMA must be set up appropriately.
The third mode is where fapolicyd calculates a SHA256 hash of the file itself and compares that with what is stored in the trust db.
Why not SELinux for application allowlisting?
SELinux is modeling how an application behaves. It is not concerned about where the application came from or whether it’s known to the system. Basically, anything in /bin
gets bin_t
type by default which is not a very restrictive label. MAC systems serve a different purpose than application allow listing. Fapolicyd by design cares solely about if this is a known application/library. These are complementary security subsystems.
In conclusion fapolicyd can be an effective tool for allowlisting applications. But like any other security technology, it should be used in conjunction with several other options like SELinux, and good system configuration to provide better overall security of systems.