Chapter 13. Blocking and allowing applications by using fapolicyd
Setting and enforcing a policy that either allows or denies application execution based on a rule set efficiently prevents the execution of unknown and potentially malicious software.
13.1. Introduction to fapolicyd
The fapolicyd
software framework controls the execution of applications based on a user-defined policy. This is one of the most efficient ways to prevent running untrusted and possibly malicious applications on the system.
The fapolicyd
framework provides the following components:
-
fapolicyd
service -
fapolicyd
command-line utilities -
fapolicyd
RPM plugin -
fapolicyd
rule language -
fagenrules
script
The administrator can define the allow
and deny
execution rules for any application with the possibility of auditing based on a path, hash, MIME type, or trust.
The fapolicyd
framework introduces the concept of trust. An application is trusted when it is properly installed by the system package manager, and therefore it is registered in the system RPM database. The fapolicyd
daemon uses the RPM database as a list of trusted binaries and scripts. The fapolicyd
RPM plugin registers any system update that is handled by either the DNF package manager or the RPM Package Manager. The plugin notifies the fapolicyd
daemon about changes in this database. Other ways of adding applications require the creation of custom rules and restarting the fapolicyd
service.
The fapolicyd
service configuration is located in the /etc/fapolicyd/
directory with the following structure:
-
The
/etc/fapolicyd/fapolicyd.trust
file contains a list of trusted files. You can also use multiple trust files in the/etc/fapolicyd/trust.d/
directory. -
The
/etc/fapolicyd/rules.d/
directory for files containingallow
anddeny
execution rules. Thefagenrules
script merges these component rules files to the/etc/fapolicyd/compiled.rules
file. -
The
fapolicyd.conf
file contains the daemon’s configuration options. This file is useful primarily for performance-tuning purposes.
Rules in /etc/fapolicyd/rules.d/
are organized in several files, each representing a different policy goal. The numbers at the beginning of the corresponding file names determine the order in /etc/fapolicyd/compiled.rules
:
- 10
- Language rules.
- 20
- Dracut-related Rules.
- 21
- rules for updaters.
- 30
- Patterns.
- 40
- ELF rules.
- 41
- Shared objects rules.
- 42
- Trusted ELF rules.
- 70
- Trusted language rules.
- 72
- Shell rules.
- 90
- Deny execute rules.
- 95
- Allow open rules.
You can use one of the following ways for fapolicyd
integrity checking:
- File-size checking
- Comparing SHA-256 hashes
- Integrity Measurement Architecture (IMA) subsystem
By default, fapolicyd
does no integrity checking. Integrity checking based on the file size is fast, but an attacker can replace the content of the file and preserve its byte size. Computing and checking SHA-256 checksums is more secure, but it affects the performance of the system. The integrity = ima
option in fapolicyd.conf
requires support for files extended attributes (also known as xattr
) on all file systems containing executable files.
Additional resources
-
fapolicyd(8)
,fapolicyd.rules(5)
,fapolicyd.conf(5)
,fapolicyd.trust(13)
,fagenrules(8)
, andfapolicyd-cli(1)
man pages. - The Enhancing security with the kernel integrity subsystem chapter in the Managing, monitoring, and updating the kernel document.
-
The documentation installed with the
fapolicyd
package in the/usr/share/doc/fapolicyd/
directory and the/usr/share/fapolicyd/sample-rules/README-rules
file.
13.2. Deploying fapolicyd
To deploy the fapolicyd
framework in RHEL:
Procedure
Install the
fapolicyd
package:# dnf install fapolicyd
Enable and start the
fapolicyd
service:# systemctl enable --now fapolicyd
Verification
Verify that the
fapolicyd
service is running correctly:# systemctl status fapolicyd ● fapolicyd.service - File Access Policy Daemon Loaded: loaded (/usr/lib/systemd/system/fapolicyd.service; enabled; vendor p> Active: active (running) since Tue 2019-10-15 18:02:35 CEST; 55s ago Process: 8818 ExecStart=/usr/sbin/fapolicyd (code=exited, status=0/SUCCESS) Main PID: 8819 (fapolicyd) Tasks: 4 (limit: 11500) Memory: 78.2M CGroup: /system.slice/fapolicyd.service └─8819 /usr/sbin/fapolicyd Oct 15 18:02:35 localhost.localdomain systemd[1]: Starting File Access Policy D> Oct 15 18:02:35 localhost.localdomain fapolicyd[8819]: Initialization of the da> Oct 15 18:02:35 localhost.localdomain fapolicyd[8819]: Reading RPMDB into memory Oct 15 18:02:35 localhost.localdomain systemd[1]: Started File Access Policy Da> Oct 15 18:02:36 localhost.localdomain fapolicyd[8819]: Creating database
Log in as a user without root privileges, and check that
fapolicyd
is working, for example:$ cp /bin/ls /tmp $ /tmp/ls bash: /tmp/ls: Operation not permitted
13.3. Marking files as trusted using an additional source of trust
The fapolicyd
framework trusts files contained in the RPM database. You can mark additional files as trusted by adding the corresponding entries to the /etc/fapolicyd/fapolicyd.trust
plain-text file or the /etc/fapolicyd/trust.d/
directory, which supports separating a list of trusted files into more files. You can modify fapolicyd.trust
or the files in /etc/fapolicyd/trust.d
either directly using a text editor or through fapolicyd-cli
commands.
Marking files as trusted using fapolicyd.trust
or trust.d/
is better than writing custom fapolicyd
rules due to performance reasons.
Prerequisites
-
The
fapolicyd
framework is deployed on your system.
Procedure
Copy your custom binary to the required directory, for example:
$ cp /bin/ls /tmp $ /tmp/ls bash: /tmp/ls: Operation not permitted
Mark your custom binary as trusted, and store the corresponding entry to the
myapp
file in/etc/fapolicyd/trust.d/
:# fapolicyd-cli --file add /tmp/ls --trust-file myapp
-
If you skip the
--trust-file
option, then the previous command adds the corresponding line to/etc/fapolicyd/fapolicyd.trust
. -
To mark all existing files in a directory as trusted, provide the directory path as an argument of the
--file
option, for example:fapolicyd-cli --file add /tmp/my_bin_dir/ --trust-file myapp
.
-
If you skip the
Update the
fapolicyd
database:# fapolicyd-cli --update
Changing the content of a trusted file or directory changes their checksum, and therefore fapolicyd
no longer considers them trusted.
To make the new content trusted again, refresh the file trust database by using the fapolicyd-cli --file update
command. If you do not provide any argument, the entire database refreshes. Alternatively, you can specify a path to a specific file or directory. Then, update the database by using fapolicyd-cli --update
.
Verification
Check that your custom binary can be now executed, for example:
$ /tmp/ls ls
Additional resources
-
fapolicyd.trust(13)
man page.
13.4. Adding custom allow and deny rules for fapolicyd
The default set of rules in the fapolicyd
package does not affect system functions. For custom scenarios, such as storing binaries and scripts in a non-standard directory or adding applications without the dnf
or rpm
installers, you must either mark additional files as trusted or add new custom rules.
For basic scenarios, prefer Marking files as trusted using an additional source of trust. In more advanced scenarios such as allowing to execute a custom binary only for specific user and group identifiers, add new custom rules to the /etc/fapolicyd/rules.d/
directory.
The following steps demonstrate adding a new rule to allow a custom binary.
Prerequisites
-
The
fapolicyd
framework is deployed on your system.
Procedure
Copy your custom binary to the required directory, for example:
$ cp /bin/ls /tmp $ /tmp/ls bash: /tmp/ls: Operation not permitted
Stop the
fapolicyd
service:# systemctl stop fapolicyd
Use debug mode to identify a corresponding rule. Because the output of the
fapolicyd --debug
command is verbose and you can stop it only by pressing Ctrl+C or killing the corresponding process, redirect the error output to a file. In this case, you can limit the output only to access denials by using the--debug-deny
option instead of--debug
:# fapolicyd --debug-deny 2> fapolicy.output & [1] 51341
Alternatively, you can run
fapolicyd
debug mode in another terminal.Repeat the command that
fapolicyd
denied:$ /tmp/ls bash: /tmp/ls: Operation not permitted
Stop debug mode by resuming it in the foreground and pressing Ctrl+C:
# fg fapolicyd --debug 2> fapolicy.output ^C ...
Alternatively, kill the process of
fapolicyd
debug mode:# kill 51341
Find a rule that denies the execution of your application:
# cat fapolicy.output | grep 'deny_audit' ... rule=13 dec=deny_audit perm=execute auid=0 pid=6855 exe=/usr/bin/bash : path=/tmp/ls ftype=application/x-executable trust=0
Locate the file that contains a rule that prevented the execution of your custom binary. In this case, the
deny_audit perm=execute
rule belongs to the90-deny-execute.rules
file:# ls /etc/fapolicyd/rules.d/ 10-languages.rules 40-bad-elf.rules 72-shell.rules 20-dracut.rules 41-shared-obj.rules 90-deny-execute.rules 21-updaters.rules 42-trusted-elf.rules 95-allow-open.rules 30-patterns.rules 70-trusted-lang.rules # cat /etc/fapolicyd/rules.d/90-deny-execute.rules # Deny execution for anything untrusted deny_audit perm=execute all : all
Add a new
allow
rule to the file that lexically precedes the rule file that contains the rule that denied the execution of your custom binary in the/etc/fapolicyd/rules.d/
directory:# touch /etc/fapolicyd/rules.d/80-myapps.rules # vi /etc/fapolicyd/rules.d/80-myapps.rules
Insert the following rule to the
80-myapps.rules
file:allow perm=execute exe=/usr/bin/bash trust=1 : path=/tmp/ls ftype=application/x-executable trust=0
Alternatively, you can allow executions of all binaries in the
/tmp
directory by adding the following rule to the rule file in/etc/fapolicyd/rules.d/
:allow perm=execute exe=/usr/bin/bash trust=1 : dir=/tmp/ trust=0
- IMPORTANT
-
To make a rule effective recursively on all directories under the specified directory, add a trailing slash to the value of the
dir=
parameter in the rule (/tmp/
in the previous example).
To prevent changes in the content of your custom binary, define the required rule using an SHA-256 checksum:
$ sha256sum /tmp/ls 780b75c90b2d41ea41679fcb358c892b1251b68d1927c80fbc0d9d148b25e836 ls
Change the rule to the following definition:
allow perm=execute exe=/usr/bin/bash trust=1 : sha256hash=780b75c90b2d41ea41679fcb358c892b1251b68d1927c80fbc0d9d148b25e836
Check that the list of compiled differs from the rule set in
/etc/fapolicyd/rules.d/
, and update the list, which is stored in the/etc/fapolicyd/compiled.rules
file:# fagenrules --check /usr/sbin/fagenrules: Rules have changed and should be updated # fagenrules --load
Check that your custom rule is in the list of
fapolicyd
rules before the rule that prevented the execution:# fapolicyd-cli --list ... 13. allow perm=execute exe=/usr/bin/bash trust=1 : path=/tmp/ls ftype=application/x-executable trust=0 14. deny_audit perm=execute all : all ...
Start the
fapolicyd
service:# systemctl start fapolicyd
Verification
Check that your custom binary can be now executed, for example:
$ /tmp/ls ls
Additional resources
-
fapolicyd.rules(5)
andfapolicyd-cli(1)
man pages. -
The documentation installed with the
fapolicyd
package in the/usr/share/fapolicyd/sample-rules/README-rules
file.
13.5. Enabling fapolicyd integrity checks
By default, fapolicyd
does not perform integrity checking. You can configure fapolicyd
to perform integrity checks by comparing either file sizes or SHA-256 hashes. You can also set integrity checks by using the Integrity Measurement Architecture (IMA) subsystem.
Prerequisites
-
The
fapolicyd
framework is deployed on your system.
Procedure
Open the
/etc/fapolicyd/fapolicyd.conf
file in a text editor of your choice, for example:# vi /etc/fapolicyd/fapolicyd.conf
Change the value of the
integrity
option fromnone
tosha256
, save the file, and exit the editor:integrity = sha256
Restart the
fapolicyd
service:# systemctl restart fapolicyd
Verification
Back up the file used for the verification:
# cp /bin/more /bin/more.bak
Change the content of the
/bin/more
binary:# cat /bin/less > /bin/more
Use the changed binary as a regular user:
# su example.user $ /bin/more /etc/redhat-release bash: /bin/more: Operation not permitted
Revert the changes:
# mv -f /bin/more.bak /bin/more
13.6. Troubleshooting problems related to fapolicyd
The following section provides tips for basic troubleshooting of the fapolicyd
application framework and guidance for adding applications using the rpm
command.
Installing applications by using rpm
If you install an application by using the
rpm
command, you have to perform a manual refresh of thefapolicyd
RPM database:Install your application:
# rpm -i application.rpm
Refresh the database:
# fapolicyd-cli --update
If you skip this step, the system can freeze and must be restarted.
Service status
If
fapolicyd
does not work correctly, check the service status:# systemctl status fapolicyd
fapolicyd-cli
checks and listings
The
--check-config
,--check-watch_fs
, and--check-trustdb
options help you find syntax errors, not-yet-watched file systems, and file mismatches, for example:# fapolicyd-cli --check-config Daemon config is OK # fapolicyd-cli --check-trustdb /etc/selinux/targeted/contexts/files/file_contexts miscompares: size sha256 /etc/selinux/targeted/policy/policy.31 miscompares: size sha256
Use the
--list
option to check the current list of rules and their order:# fapolicyd-cli --list ... 9. allow perm=execute all : trust=1 10. allow perm=open all : ftype=%languages trust=1 11. deny_audit perm=any all : ftype=%languages 12. allow perm=any all : ftype=text/x-shellscript 13. deny_audit perm=execute all : all ...
Debug mode
Debug mode provides detailed information about matched rules, database status, and more. To switch
fapolicyd
to debug mode:Stop the
fapolicyd
service:# systemctl stop fapolicyd
Use debug mode to identify a corresponding rule:
# fapolicyd --debug
Because the output of the
fapolicyd --debug
command is verbose, you can redirect the error output to a file:# fapolicyd --debug 2> fapolicy.output
Alternatively, to limit the output only to entries when
fapolicyd
denies access, use the--debug-deny
option:# fapolicyd --debug-deny
Removing the fapolicyd
database
To solve problems related to the
fapolicyd
database, try to remove the database file:# systemctl stop fapolicyd # fapolicyd-cli --delete-db
WarningDo not remove the
/var/lib/fapolicyd/
directory. Thefapolicyd
framework automatically restores only the database file in this directory.
Dumping the fapolicyd
database
The
fapolicyd
contains entries from all enabled trust sources. You can check the entries after dumping the database:# fapolicyd-cli --dump-db
Application pipe
In rare cases, removing the
fapolicyd
pipe file can solve a lockup:# rm -f /var/run/fapolicyd/fapolicyd.fifo
Additional resources
-
fapolicyd-cli(1)
man page.
13.7. Configuring protection against unknown code execution with the fapolicyd
RHEL system role
You can use the fapolicyd
System Role to prevent execution of unknown code by running an Ansible playbook.
Prerequisites
- You have prepared the control node and the managed nodes
- You are logged in to the control node as a user who can run playbooks on the managed nodes.
-
The account you use to connect to the managed nodes has
sudo
permissions on them.
Procedure
Create a playbook file, for example
~/playbook.yml
, with the following content:--- - name: Preventing execution of unknown code hosts: all vars: fapolicyd_setup_integrity: sha256 fapolicyd_setup_trust: rpmdb,file fapolicyd_add_trusted_file: - </usr/bin/my-ls> - </opt/third-party/app1> - </opt/third-party/app2> roles: - rhel-system-roles.fapolicyd
You can further customize the protection by using the following variables of the
linux-system-roles.fapolicyd
RHEL System Role:fapolicyd_setup_integrity
-
You can set one of the following types of integrity:
none
,sha256
, andsize
. fapolicyd_setup_trust
-
You can set trust file types
file
,rpmd
, anddeb
. fapolicyd_add_trusted_file
-
You can list executable files that you trust and that
fapolicyd
does not prevent from executing.
Validate the playbook syntax:
# ansible-playbook ~/playbook.yml --syntax-check
Note that this command only validates the syntax and does not protect against a wrong but valid configuration.
Run the playbook:
# ansible-playbook ~/playbook.yml
Additional resources
-
/usr/share/ansible/roles/rhel-system-roles.fapolicyd/README.md
file
13.8. Additional resources
-
fapolicyd
-related man pages listed by using theman -k fapolicyd
command. - The FOSDEM 2020 fapolicyd presentation.