fapolicyd icon indicating copy to clipboard operation
fapolicyd copied to clipboard

whitelist automation

Open scholarsmate opened this issue 4 years ago • 2 comments

I'm working on building a tool to automate whitelist generation, but to support this, the rules need to be ordered such that there are 3 rule sets, namely user-specific, group-specific and global. The evaluation of the rules are done such that user-specific rules are all run before group-specific rules which are all run before global rules. In each rule set, all allow rules are run before deny rules. Since this is whitelisting (that which is not explicitly allowed is denied), "no opinion" must evaluate to deny, so the global rule set consists of allow rules and a single deny rule, which denies everything. Ordered this way, an automated system has 5 rule injection zones, namely user-allowed, user-denied, group-allowed, group-denied and global-allowed. The order of the rules within any of these 5 groups is arbitrary meaning that any ordering within the groups will yield the equivalent allow/deny outcome, allowing for reasonable automation of rule generation.

I have taken the fapolicyd.rules.known-libs rules and have attempted to create equivalent rules using the above ordering scheme. I have broken the file down into 3 files for each rule set to enforce the distinction.

User-specific rules:

# fapolicyd-user.rules
##############################################################################
# Lists
##############################################################################

##############################################################################
# Allow Rules
##############################################################################

# Carve out an exception for dracut initramfs building
allow perm=any uid=0 : dir=/var/tmp/
allow perm=any uid=0 trust=1 : all

# Need to carve out an exception for ansible, which uses python
allow perm=any uid=0 : dir=/tmp/ansible
allow perm=any uid=0 : dir=/root/.ansible/tmp/

##############################################################################
# Deny Rules
##############################################################################

Group-specific rules:

# fapolicyd-group.rules
##############################################################################
# Lists
##############################################################################

##############################################################################
# Allow Rules
##############################################################################

##############################################################################
# Deny Rules
##############################################################################

Global rules:

##############################################################################
# Lists
##############################################################################

%languages=application/x-bytecode.ocaml,application/x-bytecode.python,application/java-archive,text/javascript,text/x-awk,text/x-gawk,text/x-java,text/x-lisp,text/x-lua,text/x-m4,text/x-perl,text/x-php,text/x-python,text/x-R,text/x-ruby,text/x-script.guile,text/x-tcl,text/x-luatex,text/x-systemtap

##############################################################################
# Allow Rules
##############################################################################

# We have to carve out an exception for the system updaters
# or things go very bad (deadlock).
allow perm=open exe=/usr/bin/rpm : all
allow perm=open exe=%python3_path% comm=dnf : all

# Only allow known ELF libs - this is ahead of executable because typical
# executable is linked with a dozen or more libraries.
allow perm=open all : ftype=application/x-sharedlib trust=1

# Allow trusted programs to execute
allow perm=execute all : trust=1

# Allow any program to open trusted language files
allow perm=open all : ftype=%languages trust=1

# Allow all shell script execution and sourcing
allow perm=any all : ftype=text/x-shellscript

# Allow everything else to open any file
allow perm=open all : all

##############################################################################
# Deny Everything Rule
##############################################################################

# Deny everything not explicitly allowed otherwise
deny_audit perm=any all : all

To create the final fapolicyd.rules file I simply concatenate the 3 files together starting with the user-specific rules, followed by the group-specific rules and ending with the global rules. The rules now look like this:

$ sudo fapolicyd-cli --list
1. allow perm=any uid=0 : dir=/var/tmp/
2. allow perm=any uid=0 trust=1 : all
3. allow perm=any uid=0 : dir=/tmp/ansible
4. allow perm=any uid=0 : dir=/root/.ansible/tmp/
-> %languages=application/x-bytecode.ocaml,application/x-bytecode.python,application/java-archive,text/javascript,text/x-awk,text/x-gawk,text/x-java,text/x-lisp,text/x-lua,text/x-m4,text/x-perl,text/x-php,text/x-python,text/x-R,text/x-ruby,text/x-script.guile,text/x-tcl,text/x-luatex,text/x-systemtap
5. allow perm=open exe=/usr/bin/rpm : all
6. allow perm=open exe=%python3_path% comm=dnf : all
7. allow perm=open all : ftype=application/x-sharedlib trust=1
8. allow perm=execute all : trust=1
9. allow perm=open all : ftype=%languages trust=1
10. allow perm=any all : ftype=text/x-shellscript
11. allow perm=open all : all
12. deny_audit perm=any all : all

This gets us close to the outcomes of the original fapolicyd.rules.known-libs rules, with the default of denying anything not explicitly allowed (whitelisting)

In debugging, it would be very useful to know which file access pattern (normal, static, or ld_so) was used because the deny_audit perm=any pattern=ld_so : all rule I don't believe has been properly accounted for in this reordering.

If it's possible to get outcome equivalence using this ordering scheme, then rule generation automation becomes a reasonable possibility, paving the way for additional tooling.

scholarsmate avatar Jul 19 '20 20:07 scholarsmate

Patterns have to be first. Everything below them depend on that. (Note that I'm about to merge another pattern.)

stevegrubb avatar Jul 20 '20 18:07 stevegrubb

Understood, but can't there be a way in all the allow rules to give just the normal and static access patterns using a list? For example:

%allowed_patterns=normal,static
...
allow perm=execute all pattern=%allowed_patterns : all
deny_audit perm=any all : all

So if there aren't any rules that explicitly allow the ld_so access pattern, then the request is denied. If there really aren't any legitimate cases where the ld_so access pattern should be used on a normal system, perhaps we can set a variable in the fapolicyd.conf file with permitted or denied file access patterns.

Also in the logging is it possible to emit the pattern detected?

scholarsmate avatar Jul 20 '20 19:07 scholarsmate

I think we should close this issue. So much has changed since this was opened and with the rules.d directory, I think the problems described here have changed. If there is still something to address, please open a new issue. Thanks.

stevegrubb avatar Feb 20 '23 16:02 stevegrubb