{"id":46557634,"url":"https://github.com/linux-application-whitelisting/fapolicyd","last_synced_at":"2026-03-07T05:04:42.713Z","repository":{"id":37483972,"uuid":"59055298","full_name":"linux-application-whitelisting/fapolicyd","owner":"linux-application-whitelisting","description":"File Access Policy Daemon","archived":false,"fork":false,"pushed_at":"2026-02-06T14:03:21.000Z","size":1792,"stargazers_count":231,"open_issues_count":27,"forks_count":70,"subscribers_count":20,"default_branch":"main","last_synced_at":"2026-02-06T21:50:08.005Z","etag":null,"topics":["access-control","linux","security","whitelisting"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linux-application-whitelisting.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2016-05-17T20:12:13.000Z","updated_at":"2026-02-06T14:03:25.000Z","dependencies_parsed_at":"2023-11-17T20:27:53.165Z","dependency_job_id":"db400a3d-30fe-4066-a26a-40cb900a1186","html_url":"https://github.com/linux-application-whitelisting/fapolicyd","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/linux-application-whitelisting/fapolicyd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-application-whitelisting%2Ffapolicyd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-application-whitelisting%2Ffapolicyd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-application-whitelisting%2Ffapolicyd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-application-whitelisting%2Ffapolicyd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linux-application-whitelisting","download_url":"https://codeload.github.com/linux-application-whitelisting/fapolicyd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-application-whitelisting%2Ffapolicyd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30208730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T03:24:23.086Z","status":"ssl_error","status_checked_at":"2026-03-07T03:23:11.444Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-control","linux","security","whitelisting"],"created_at":"2026-03-07T05:04:41.862Z","updated_at":"2026-03-07T05:04:42.697Z","avatar_url":"https://github.com/linux-application-whitelisting.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"File Access Policy Daemon\n=========================\n\n[![Build Status](https://travis-ci.com/linux-application-whitelisting/fapolicyd.svg?branch=master)](https://travis-ci.com/linux-application-whitelisting/fapolicyd)\n\nThis is a simple application whitelisting daemon for Linux.\n\nRUNTIME DEPENDENCIES\n--------------------\n* kernel \u003e= 4.20 (Must support FANOTIFY_OPEN_EXEC_PERM. See [1] below.)\n\nBUILDING\n--------\n\nSee [BUILD.md](./BUILD.md) for build-time dependencies and instructions for building.\n\nPOLICIES\n--------\nThe current design for policy is that it is split up into units of rules\nthat are designed to work together. They are copied into /etc/fapolicyd/rules.d/\nWhen the service starts, the systemd service file runs fagenrules which\nassembles the units of rules into a comprehensive policy. The policy is\nevaluated from top to bottom with the first match winning. You can see the\nassembled policy by running \n\n```\nfapolicyd-cli --list\n```\nOriginally, there were 2 policies shipped, known-libs and restrictive.\n\nThe restrictive policy was designed with these goals in mind:\n\n1. No bypass of security by executing programs via ld.so.\n2. Anything requesting execution must be trusted.\n3. Elf binaries, python, and shell scripts are enabled for trusted\n   applications/libraries.\n4. Other languages are not allowed or must be enabled.\n\nIt can be recreated by copying the following policy units into rules.d.\nThe optional ones are not included unless they are needed:\n\n20-dracut.rules\n21-updaters.rules\n30-patterns.rules\n40-bad-elf.rules\n41-shared-obj.rules\n43-known-elf.rules\n71-known-python.rules\n72-shell.rules\noptional: 73-known-perl.rules\noptional: 74-known-ocaml.rules\noptional: 75-known-php.rules\noptional: 76-known-ruby.rules\noptional: 77-known-lua.rules\n90-deny-execute.rules\n95-allow-open.rules\n\nThe known-libs policy (default) was designed with these goals in mind:\n\n1. No bypass of security by executing programs via ld.so.\n2. Anything requesting execution must be trusted.\n3. Any library or interpreted application or module must be trusted.\n4. Everything else is not allowed.\n\nIt can be created by copying the following policy units into rules.d:\n\n10-languages.rules\n20-dracut.rules\n21-updaters.rules\n30-patterns.rules\n40-bad-elf.rules\n41-shared-obj.rules\n42-trusted-elf.rules\n70-trusted-lang.rules\n72-shell.rules\n90-deny-execute.rules\n95-allow-open.rules\n\nEXPERIMENTING\n-------------\nYou can test by starting the daemon from the command line. Before starting\nthe daemon, cp /usr/bin/ls /usr/bin/my-ls just to setup for testing. When\ntesting new policy, its highly recommended to use the permissive mode to\nmake sure nothing bad happens. It really is not too hard to deadlock your\nsystem. Continuing on with the tutorial, as root start the daemon as follows:\n\n```\n/usr/sbin/fapolicyd --permissive --debug\n```\nThen in another window do the following:\n\n1. /usr/lib64/ld-2.29.so /usr/bin/ls\n2. my-ls\n3. run a python file in your home directory.\n4. run a program from /tmp\n\nIn permissive + debug mode you will see dec=deny which means\n\"decision is to deny\". But the program will actually be allowed to run.\n\nYou can run the daemon from the command line with --debug-deny command\nline option. This culls the event notification to only print the denials.\nIf this is running cleanly, then you can remove the --permissive option\nand get true denials. Now retest above steps and see the difference.\n\nDEBUG MODE\n----------\nIn debug mode, you will see events such as this:\n\n```\nrule:9 dec=deny_audit perm=execute auid=1001 pid=14137 exe=/usr/bin/bash : file=/home/joe/my-ls ftype=application/x-executable\n```\n\nWhat this is saying is rule 9 made the ultimate Decision that was followed.\nThe Decision is to deny access and create an audit event. The subject is the\nuser that logged in as user id 1001. The subject's process id that is trying\nto perform an action is 14137. The current executable that the subject is\nusing is bash. Bash wanted permission to execute /home/joe/my-ls which is the\nobject. And the object is an ELF executable.\n\nSometimes you want to list out the rules to see what rule 9 might be. You can\neasily do that by running:\n\n```\nfapolicyd-cli --list\n```\n\nAlso, in fapolicyd.conf, there is a configuration option, syslog_format, which\ncan be modified to output information the way you want to see it. So, if you\nthink auid in uninteresting you can delete it. If you want to see the device\ninformation for the file being accessed, you can add it. You can also enable\nthis information to go to syslog by changing the rules to not say audit, but\ninstead have syslog or log appended to the allow or deny decision.\n\nOVERRIDE MOUNTS WHILE DEBUGGING\n-------------------------------\nWhen debugging you can specify an alternative mounts file to the deamon\nto watch for event notifications. This allows for finer level of control\nthan is achievable by filtering by filesystem type.\n\nThe alternative mounts file will expect the same format as `/proc/mounts`,\nwhich allows us to select entries from `/proc/mounts` into a new file which\nfapolicyd will use as the mount source.\n\nFor example, use grep to select a single mount point:\n```\nmount -t tmpfs tmpfs /tmp/my-test-dir \ngrep my-test-dir /proc/mounts \u003e /tmp/my-test-mounts\nfapolicyd --debug --mounts=/tmp/my-test-mounts\n```\n\nHere we mount a tmpfs for testing in `/tmp`, and grep it from `/proc/mounts`\ninto the overriding mounts file, then run fapolicyd in debug mode while\nspecifying the override file. The result is fapolicyd only receives events\nthat occur in `/tmp/my-test-dir`.\n\nWRITING RULES\n-------------\nThe authoritative source is the fapolicyd.rules man page.\n\nIt is suggested that people use the known-libs set of rules. This set of\nrules is designed to allow anything that is trusted to execute. It's\ndesign is to stay out of your way as much as possible. All that you need\nto do is add unpackaged but trusted files to the trust database. See the\n\"Managing Trust\" section for more.\n\nBut if you had to write rules, they follow a simple\n\"decision permission subject : object\" recipe. The idea is to write a\ncouple things that you want to allow, and then deny everything else. For\nexample, this is how shared libraries are handled:\n\n```\nallow perm=open all : ftype=application/x-sharedlib trust=1\ndeny_audit perm=open all : ftype=application/x-sharedlib\n```\n\nWhat this says is let any program open shared libraries if the library\nbeing opened is trusted. Otherwise, deny with an audit event any open of\nuntrusted libraries.\n\nFirst and foremost, fapolicyd rules are based on trust relationships.\nIt is not meant to be an access control system of Mandatory Access Control\nPolicy. But you can do that. It is not recommended to do this except when\nnecessary. Every rule that is added has to potentially be evaluated - which\ndelays the decision.\n\nIf you needed to allow admins access to ping, but deny it to everyone \nelse, you could do that with the following rules:\n\n```\nallow perm=any gid=wheel : trust=1 path=/usr/bin/ping\ndeny_audit perm=execute all : trust=1 path=/usr/bin/ping\n```\n\nYou can similarly do this for trusted users that have to execute things in\nthe home dir. You can create a trusted_user group, add them the group,\nand then write a rule allowing them to execute from their home dir.\n\nWhen you want to use user or group name (as a string). You have to guarantee\nthat these names were correctly resolved. In case of systemd, you need to add\na new after target 'After=nss-user-lookup.target'.\nTo achieve that you can use `systemctl edit --full fapolicyd`,\nuncomment the respective line and save the change.\n\n```\nallow perm=any gid=trusted_user : ftype=%languages dir=/home\ndeny_audit perm=any all : ftype=%languages dir=/home\n```\n\nOne thing to point out, if you have lists of things that you would like to\nallow, use the macro set support as illustrated in this last example. This puts\nthe list into a sorted AVL tree so that searching is cut to a minimum number\nof compares.\n\nOne last note, the rule engine is a first match wins system. If you are adding\nrules to allow something but it gets denied by a rule higher up, then move\nyour rule above the thing that denies it. But again, if you are writing rules\nto allow execution, you should reconsider if adding the programs to the trust\ndatabase is better.\n\nRULE ORDERING\n-------------\nStarting with 1.1, the rules should be placed in a rules.d directory under\nthe fapolicyd configuration directory. There is a new utility, fagenrules,\nwhich will compile the rules into a single file, compiled.rules, and place the\nresulting file in the main config directory.\n\nIf you want to migrate your existing rules, just move them as is to the rules.d\ndirectory. You cannot have both compiled.rules and fapolicyd.rules. The\nfagenrules will notice this and put a warning in syslog. If you use fapolicyd-cli --list, it will also notice and warn. If you do have both files, the old rules\nfile will be used instead of the new one.\n\nThis new rules.d directory is intended to make it easier to develop application\nspecific rules that can be dropped off by automation / orchestration. This\nshould make managing the configuration easier.\n\nThe files in the rules.d directory are processed in a specific order. See the\n[rules.d README](rules.d/README-rules) file for more information.\n\n\nREPORT\n------\nOn shutdown the daemon will write an object access report to\n/var/log/fapolicyd-access.log. The report is from oldest access to newest.\nTimestamps are not included because that would be a severe performance hit.\nThe report gives some basic forensic information about what was being accessed.\n\nPERFORMANCE\n-----------\nWhen a program opens a file or calls execve, that thread has to wait for \nfapolicyd to make a decision. To make a decision, fapolicyd has to lookup\ninformation about the process and the file being accessed. Each system call\nfapolicyd has to make slows down the system.  \n\nTo speed things up, fapolicyd caches everything it looks up so that\nsubsequent access uses the cache rather than looking things up from\nscratch. But the cache is only so big. You are in control of it, though.\nYou can make both subject and object caches bigger. When the program ends,\nit will output some performance statistic like this into\n/var/log/fapolicyd-access.log or the screen:\n\n```\nPermissive: false\nq_size: 640\nInter-thread max queue depth 7\nAllowed accesses: 70397\nDenied accesses: 4\nTrust database max pages: 14848\nTrust database pages in use: 10792 (72%)\n\nSubject cache size: 1549\nSubject slots in use: 369 (23%)\nSubject hits: 70032\nSubject misses: 455\nSubject evictions: 86 (0%)\n\nObject cache size: 8191\nObject slots in use: 6936 (84%)\nObject hits: 63465\nObject misses: 17964\nObject evictions: 11028 (17%)\n\n```\n\nIn this report, you can see that the internal request queue maxed out at 7.\nThis means that the daemon had at most 7 threads/processes waiting. This\nshows that it got a little backed up but was handling requests pretty quick.\nIf this number were big, like more than 200, then increasing the q_size may\nbe necessary.\n\nAnother statistic worth looking at is the hits to evictions ratio. When a\nrequest has nowhere to put information, it has to evict something to make\nroom. This is done by a LRU cache which naturally determines what's not\ngetting used and makes it's memory available for re-use.\n\nIn the above statistics, the subject hit ratio was 95%. The object cache was\nnot quite as lucky. For it, we get a hit ration of 79%. This is still good,\nbut could be better. This would suggest that for the workload on that system,\nthe cache could be a little bigger. If the number used for the cache size is\na prime number, you will get less cache churn due to collisions than if it\nhad a common denominator. Some primes you might consider for cache size are:\n2039, 4099, 6143, 8191, 10243, 12281, 16381, 20483, 24571, 28669, 32687,\n40961, 49157, 57347, 65353, etc.\n\nThis report can be scheduled to be written periodically by setting the\nconfiguration option `report_interval`. This option is set to `0` by default\nwhich disables the reporting interval. A positive value for this option\nspecifies the number of seconds to wait between reports.\n\nAlso, it should be mentioned that the more rules in the policy, the more\nrules it will have to iterate over to make a decision. As for the system\nperformance impact, this is very workload dependent. For a typical desktop\nscenario, you won't notice it's running. A system that opens lots of random\nfiles for short periods of time will have more impact.\n\nAnother configuration option that can affect performance is the integrity\nsetting. If this is set to sha256, then every miss in the object cache will\ncause a hash to be calculated on the file being accessed. One trade-off would\nbe to use size checking rather than sha256. This is not as secure, but it is\nan option if performance is problematic.\n\n## Use ignore_mounts with great care\n\nStarting with fapolicyd-1.3.8, there is a new performance option, ignore_mounts. ignore_mounts removes selected mount points from fanotify monitoring to reduce overhead on very busy filesystems (for example, cache or logging partitions). This improves performance **at the cost of visibility**: when a mount is ignored, fapolicyd does not see opens/reads from that tree and cannot apply policy decisions there.\n\n### When to consider it\n\n+ High-churn **data-only** mounts where monitoring provides little value (e.g. cache directories, file/content serving directories, or dedicated logging partitions).\n\n+ Workloads that are **well understood and controlled**, with correct ownership/permissions/SELinux labels and no expectation that content will be treated as code.\n\n### Risks\n\n+ **Interpreter and plugin gaps**: Even with noexec, trusted interpreters (shell, Python, Java, Node.js, etc.) and applications that load plugins/bytecode may read and act on files from the ignored mount. Those accesses bypass fapolicyd because the mount is not watched.\n\n+ **Policy blind spots**: Content copied into the ignored tree won’t be evaluated while it resides there and may only be detected after it moves to a monitored location.\n\n+ **Coverage assumptions**: The root filesystem / is always monitored. Do not use ignore_mounts to work around denials for native ELF binaries; that is not its purpose.\n\n### Required guardrails\n\n+ Each ignored mount **must** be mounted with noexec. This prevents direct ELF execve() from that mount. If noexec is missing, / is still monitored and the first observed event will be the runtime linker which will trigger the ld_so pattern detection which will deny access. Due to this certain denial, fapolicyd refuses to ignore mount points not mounted with noexec. Mounting with noexec does not mitigate interpreter/JIT/plugin scenarios.\n\n+ **Advisory pre-check** before changing configuration:\n\n```\n    fapolicyd-cli --check-ignore_mounts[=MOUNT] [--verbose]\n```\n\n This verifies the mount exists, confirms noexec, scans for files matching the %languages macro (interpreter-consumable content), reports findings, and returns non-zero when suspicious files are found so automation can gate configuration changes.\n\n+ Add entries exactly as shown in the second column of /proc/mounts. Whitespace around comma-separated entries is ignored.\n\n### Conflicts and notes\n\n+ / is always monitored.\n\n+ Do not combine this option with allow_filesystem_mark=1; the daemon will refuse the configuration.\n\n\nMEMORY USAGE\n------------\nFapolicyd uses lmdb as its trust database. The database has very fast\nperformance because it uses the kernel virtual memory system to put the\nwhole database in memory. If the database is sized wrongly, then fapolicyd\nwill reserve too much memory. Don't worry too much about this. The kernel is\nvery smart and doesn't actually allocate the memory unless its used. However,\nwe'd like to get it right sized.\n\nStarting with the 0.9.3 version of fapolicyd, statistics about the database\nis output when the program shuts down. On my system, it looks like this:\n\n```\nDatabase max pages: 9728\nDatabase pages in use: 7314 (75%)\n```\n\nThis also correlates to the following setting in the fapolicyd.conf file:\n\n```\ndb_max_size = 38\n```\n\nThis size is in megabytes. So, if you take that and multiply by 1024 * 1024,\nwe get 39845888. A page of memory is defined as 4096. So, if we divide\nmax_size by the page size, we get 9728 which matches the setting. Each entry\nin the lmdb database is 512 bytes. So, for each 4k page, we can have data on\n8 trusted files.\n\nAn ideal size for the database is for the statistics to come up around 75% in\ncase you decide to install new software some day. The formula is \n\n```\n (db_max_size x percentage in use) / desired percentage = new db_max_size\n```\n\nSo, working with example numbers, suppose max_size is 160 and it says it was\n68% occupied. That is wasting a little space. Putting the numbers in the\nformula, we get  (160 x 68) / 75 = 145.\n\nIf you have an embedded system and are not using rpm. But instead use the file\ntrust source and you have a list of files, then your calculation is very\ndifferent. Suppose for the sake of discussion, you have 317 files that are\ntrusted. We take that number and divide by 8. We'll round that up to 40. Take\nthat number and multiply by 100 and divide by 75. We come up with 53.33. So,\nlet's call it 54. This is how many pages is needed. Turning that into real\nmemory, it's 216K. One megabyte is the smallest allocation, so you would set\n```\ndb_max_size = 1\n```\n\nStarting with the 0.9.4 release, the rpm backend filters most files in the\n /usr/share directory. It keeps anything with a with a python extension or\na libexec directory. It also keeps /usr/src/kernel so that Akmod can still\nbuild drivers on a kernel update.\n\nTROUBLESHOOTING\n---------------\nWhatever you do, DO NOT TRY TO ATTACH WITH PTRACE. Ptrace attachment sends\na SIGSTOP which cannot be blocked. Since your whole system depends on\nfapolicyd approving access to glibc and various critical libraries, that\nwill not happen until SIGCONT is sent. The system can deadlock if the\ncontinue signal is not sent. Using gdb will have the same results. With\nthat in mind, let's talk about troubleshooting steps...\n\nIf you are using deny_audit and you are not getting any audit events, the\nfix is to add 1 audit rule. It can be a rule about anything. Watches tend\nto be the highest performance, so maybe just add a watch for writes to\netc shadow and restart the audit daemon so the rule gets loaded.\n\n```\n-w /etc/shadow -p w\n```\n\nWhen fapolicyd blocks something, it will generate an audit event if the\nDecision is deny_audit and it has been compiled with the auditing option.\nThe audit system must have at least 1 audit rule loaded to create the full\nFANOTIFY event. It doesn't matter what rule. To see if you have any denials,\nyou can run:\n\n```\nausearch --start today -m fanotify --raw | aureport --file --summary\n\nFile Summary Report\n===========================\ntotal  file\n===========================\n16  /sbin/ldconfig\n1  /home/joe/./my-ls\n```\n\nYou can also see which executables are involved like this:\n\n```\nausearch --start today -m fanotify -f /sbin/ldconfig --raw | aureport -x --summary\n\nExecutable Summary Report\n=================================\ntotal  file\n=================================\n16  /usr/bin/python3.7\n```\n\nHowever, you probably want to know the rule that is blocking it. Unfortunately\nthe audit system cannot tell you this unless you are using the 6.3 kernel or\nlater. What you can do is change the decisions to deny_log. This will write\nthe event to syslog as well as the audit log. In syslog, you will have the\nsame output as the debug mode.\n\nThe shipped rules expect that everything installed is in the trust database.\nIf you have installed anything by unzipping it or untarring it, then you need\nto add the executables, libraries, and modules to the trust database. See the\nMANAGING THE FILE TRUST SOURCE section for instructions on how to do this.\n\nYou can ask fapolicyd to include the trust information by adding trust to the\nend of the syslog_format configuration option. The things that you need to know\nto debug the policy is:\n\n* The rule triggering\n* The executable accessing the file\n* The object file type\n* The trust value\n\nLook at the rule that triggered and see if it makes sense that it triggered. If\nthe rule is a catch all denial, then check if the file is in the trust db. To see the rule that is being triggered, either reproduce the problem with the daemon running in debug-deny mode or change the rules from deny_audit to deny_syslog. If you choose this method, the denials will go into syslog. To see them run:\n```\njournalctl -b -u fapolicyd.service\n```\nto list out any events since boot by the fapolicyd service.\n\nStarting with 1.1, fapolicyd-cli includes some diagnostic capabilities.\n\n|         Option         |              What it does                  |\n|------------------------|--------------------------------------------|\n| --check-config         | Opens fapolicyd.conf and parses it to see if there are any syntax errors in the file.                     |\n| --check-path           | Check that every file in $PATH is in the trustdb. (New in 1.1.5)                                          |\n| --check-status         | Output internal metrics kept by the daemon. (New in 1.1.4)                                                |\n| --check-trustdb        | Check the trustdb against the files on disk to look for mismatches that will cause problems at run time.  |\n| --check-watch_fs       | Check the mounted file systems against the watch_fs daemon config entry to determine if any file systems need to be added to the configuration.                                           |\n| --check-ignore_mounts  | Check the configured mounts that are ignored to see that they are mounted noexec and there are no suspicious files in the partition. (New in 1.4)                                       |\n| --test-filter          | Test a path to a file against the filter rules to determine if a file will be trusted. (New in 1.3.7)     |\n\n\n\nMANAGING TRUST\n--------------\nFapolicyd use lmdb as a backend database for its trusted software list. You\ncan find this database in /var/lib/fapolicyd/. This list gets updated\nwhenever packages are installed by dnf or rpm by a rpm plugin.\n\nThe files that go into the trust database from rpm go through a filter to\neliminate as many unimportant files as possible so that the trust database\nis concise. To see what kinds of files are in the trust database, you can try this:\n\n```\nfapolicyd-cli -D  | awk '{print $2}'  | awk -F/ '{\n     base=$NF\n     ext=\"*\"\n     if (base !~ /^\\./ \u0026\u0026 base ~ /\\./) {\n       n=split(base,a,\".\"); ext=\"*.\"a[n]\n     }\n     path=\"\"\n     for(i=1;i\u003cNF;i++) if($i!=\"\") path=path\"/\"$i\n     print path\"/\"ext\n   }'  | sort | uniq -c | sort -nr | less\n\n```\nThis will show you which directories and file extensions are present like this:\n\n```\n   4913 /usr/bin/*\n   2028 /usr/lib/python3.13/site-packages/yt_dlp/extractor/__pycache__/*.pyc\n   1937 /usr/lib64/R/library/Matrix/help/*.html\n   1622 /usr/lib64/R/library/base/help/*.html\n```\n\nAnother view that you may find handy is an aggregate roll up of the trust database:\n\n```\nfapolicyd-cli -D  | \\\nawk '{split($2, a, \".\"); print a[length(a)]}' | \\\nsort | uniq -c | sort -nr | less\n```\n\nWhich gives a summary by type:\n\n```\n  17426 xz\n  13571 h\n  11734 html\n   7873 go\n   5598 json\n```\n\nThis could give you the idea to get rid of the html files since there are a lot\nand they do not need to be considered trusted. Files that are in the trusted\ndatabase should be known files that will get executed. See the fapolicyd-filter.conf\nman page for more information about writing filter rules.\n\nOne last thing about the trustdb, lmdb is a very fast database. Normally it\nworks fine. But it does not tolerate malformed databases. When this happens,\nit can segfault fapolicyd. The fix is to delete the database and restart\nthe daemon. It will then rebuild the database and work as it should. To do\nthis, run the following command:\n\n```\nfapolicyd-cli --delete-db\n```\n\nMANAGING THE FILE TRUST SOURCE\n------------------------------\nStarting with 0.9.4, the fapolicyd command line utility can help you manage\nthe file trust database. For example, suppose you have an application and\nits files over in /opt, you can add them all with the following command:\n\n```\nfapolicyd-cli --file add /opt/my-app/\n```\n\nThe command line utility will walk the directory tree and add all files to\nfapolicyd.trust. To do this, it opens each one and calculates the sha256 hash\nof the file and write that information to the new entry. Later if you decide\nto uninstall that app and you want to cleanup the list, then simply run:\n\n```\nfapolicyd-cli --file delete /opt/my-app/\n```\n\nThe command line utility will remove all files that match that directory from\nfapolicyd.trust. There is also a --file update extension that can update the\nsize and hash information with what is currently on disk.\n\nIf files are added or deleted into the file trust database, fapolicyd\ndoes not get a notification. In that case, you would also need to tell the\ndaemon that it needs to update the trust database. This is done by running\nfapolicyd-cli and passing along the --update option.\n\nSometimes you want to see what is stored in the combined file and rpm\ntrust database. In this case you can use the dump command\n\n```\nfapolicyd-cli --dump-db\n```\n\nwhich will dump which database the entry came from, path, size, and hash value.\n\nGUI\n---\nIf you need a GUI to create policy, manage trust, analyze policy, test policy, and deploy rules, you might want to checkout the [fapolicy-analyzer](https://github.com/ctc-oss/fapolicy-analyzer) project. RPM packages are in Fedora and EPEL.\n\nMore Information\n----------------\nThere are documents and unsupported tools that can help you understand fapolicyd and the fanotify API it depends on over in the [fapolicyd-extras repo](https://github.com/linux-application-whitelisting/fapolicyd-extras).\n\nFAQ\n---\n1) Can this work with other distributions?\n\nAbsolutely! There is a backend API that any trust source has to implement.\nThis API is located in fapolicyd-backend.h. A new backend needs an init, load,\nand destroy function. So, someone who knows the debian package database,\nfor example, could implement a new backend and send a pull request. We are\nlooking for collaborators.\n\nAn initial implementation for Debian distributions has been added.\nRun:\n```\ncd deb\n./build_deb.sh\n```\n\nTo build the `.deb` package that uses the `debdb` backend.\nYou must add rules to `/etc/fapolicyd/rules.d/` and change configuration\nin `/etc/fapolicyd/fapolicyd.conf` to use `trust=debdb` after installation.\n\nAlso, if the distribution is very small, you can use the file trust database\nfile. Just add the places where libraries and applications are stored.\n\n2) Can SE Linux or AppArmor do this instead?\n\nSE Linux is modeling how an application behaves. It is not concerned about\nwhere the application came from or whether it's known to the system. Basically,\nanything in /bin gets bin_t type by default which is not a very restrictive\nlabel. MAC systems serve a different purpose. Fapolicyd by design cares solely\nabout if this is a known application/library. These are complimentary security\nsubsystems. There is more information about application whitelisting use cases\nat the following NIST website:\n\nhttps://www.nist.gov/publications/guide-application-whitelisting\n\n3) Does the daemon check file integrity?\n\nVersion 0.9.5 and later supports 3 modes of integrity checking. The first is\nbased on file size. In this mode, fapolicyd will take the size information\nfrom the trust db and compare it with the measured file size. This test\nincurs no overhead since the file size is collected when establishing\nuniqueness for caching purposes. It is intended to detect accidental overwrites\nas opposed to malicious activity where the attacker can make the file size\nmatch.\n\nThe second mode is based on using IMA to calculate sha256 hashes and make them\navailable through extended attributes. This incurs only the overhead of calling\nfgetxattr which is fast since there is no path name resolution. The file system\nmust support i_version. For XFS, this is enabled by default. For other file\nsystems, this means you need to add the iversion mount option. In either\ncase, IMA must be setup appropriately.\n\nThe third mode is where fapolicyd calculates a SHA256 hash of the file itself\nand compares that with what is stored in the trust db.\n\n4) This is only looking at location. Can't this be defeated by simply moving\nthe files to another location?\n\nYes, this is checking to see if this is a known file. Known files have a known\nlocation. The shipped policy prevents execution from /tmp, /var/tmp, and $HOME\nbased on the fact that no rpm package puts anything there. Also, moving a file\nmeans it's no longer \"known\" and will be blocked from executing. And if\nsomething were moved to overwrite it, then the hash is no longer the same and\nthat will make it no longer trusted.\n\n5) Does this protect against root modifications?\n\nIf you are root, you can change the fapolicyd rules or simply turn off the\ndaemon. So, this is not designed to prevent root from doing things. None of\nthe integrity subsystems on Linux are designed to prevent root from doing\nthings. There has to be a way of doing updates or disabling something for\ntroubleshooting. For example, you can change IMA to ima_appraise=fix in\n/etc/default/grub. You can run setenforce 0 to turn off SELinux. You can also\nset selinux=0 or enforcing=0 for the boot prompt. The IPE integrity subsystem\ncan be turned off via \n\n```\necho -n 0 \u003e \"/sys/kernel/security/ipe/Ex Policy/active\"\n```\n\nand so on. Since they can all be disabled, the fact that an admin can issue a\nservice stop command is not a unique weakness.\n\n6) How do you prevent race conditions on startup? Can something execute before\nthe daemon takes control?\n\nOne of the design goals is to take control before users can login. Users are\nthe main problem being addressed. They can pip install apps to the home dir\nor do other things an admin may wish to prevent. Only root can install things\nthat run before login. And again, root can change the rules or turn off the\ndaemon.\n\nAnother design goal is to prevent malicious apps from running. Suppose someone\nguesses your password and they login to your account. Perhaps they wish to\nransomware your home dir. The app they try to run is not known to the system\nand will be stopped. Or suppose there is an exploitable service on your system.\nThe attacker is lucky enough to pop a shell. Now they want to download\nprivilege escalation tools or perhaps an LD_PRELOAD key logger. Since neither\nof these are in the trust database, they won't be allowed to run.\n\nThis is really about stopping escalation or exploitation before the attacker\ncan gain any advantage to install root kits. If we can do that, UEFI secure\nboot can make sure no other problems exist during boot.\n\nWrt to the second question being asked, fapolicyd starts very early in the\nboot process and startup is very fast. It's running well before other login\ndaemons.\n\nNOTES\n-----\n* It's highly recommended to run in permissive mode while you are testing the\ndaemon's policy.\n\n* Stracing the fapolicyd daemon WILL DEADLOCK THE SYSTEM.\n\n* About shell script restrictions...there's not much difference between\nrunning a script or someone typing things in by hand. The aim at this\npoint is to check that any program it calls meets the policy.\n\n* Some interpreters do not immediately read all lines of input. Rather, they\nread content as needed until they get to end of file. This means that if they\ndo stuff like networking or sleeping or anything that takes time, someone with\nthe privileges to modify the file can add to it after the file's integrity has\nbeen checked. This is not unique to fapolicyd, it's simply how things work.\nMake sure that trusted file permissions are not excessive so that no unexpected\nfile content modifications can occur.\n\n* If for some reason rpm database errors are detected, you may need to do\nthe following:\n\n```\n1. db_verify /var/lib/rpm/Packages\nif OK, then\n2. rm -f /var/lib/rpm/__db*\n3. rpm --rebuilddb\n```\n\n[1] - https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git/commit/?id=66917a3130f218dcef9eeab4fd11a71cd00cd7c9\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinux-application-whitelisting%2Ffapolicyd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinux-application-whitelisting%2Ffapolicyd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinux-application-whitelisting%2Ffapolicyd/lists"}