Ordered early exit match=verdirct decision lists
While updating an old hacky audit-follow script to do more long-term monitoring recently, found that I wanted to add a filtering mini-language/DSL there, and after trying a couple options with having blacklist/whitelist and such, quickly arrived at using a seemingly unnamed but somewhat popular list type for this again.
Something that looks like this:
- apparmor=DENIED && profile~!/^chromium(-.*)?/ # drop common noise + uid=myuser # include everything with this parameter - auid=myuser && uid=root - e/type=LOGIN .* res=yes/ && proctitle="/usr/bin/cron -f"
Ignoring actual matching syntax after initial +/-, this seem to be a rather common structure for filtering rules, similar to firewall rules or rsync filters, and often simplest, most intuitive and easy to work with.
Idea is that for every filtered entity, e.g. auditing event in this case (or packet in case of firewall, file/dir path in rsync), you go over all rules top-to-bottom, and stop at first one that matches, issuing verdict according to that rule.
This effectively combines whitelist/blacklist rules into one list, with very obvious rule precedence (top to bottom) and "early return/exit" idea from programming.
Early exit here seems especially powerful, as usually you'd write those rules in blocks that do something specific, e.g. a group of rules under "# Filter noisy PAM subsystem" will include anything relevant from there using "+ ..." rules, and disregard everything else related to it ("- ..." rules), so that when editing such list, you don't need to keep any context beyond that block/group in mind when considering "PAM subsystem" rules - it's all handled there and doesn't make it anywhere beyond that block.
And yet this isn't a hierarchical list, so that when needing some early global filter, like "drop different stuff that has <something> in it", you'd just put a block to that effect at the top, and however long/complicated that block is, you're now free of having to worry about that <something> for the rest of the config conceptually. Or if something important needs to be included, you put a rule matching it near the top, and can forget about it too.
Having explicit flat ordering can also be useful for manual optimization - can easily put high-hit-rate filters at the top, and let few remaining things flow through the bulk of the list.
But maybe best thing here is how simple and self-describing a concept it seem to be - to me at least - compared to even starting to document any kind of "rule precedence" or "what is an allow list" logic. For example, audisp-filter manpage has "In allowlist mode, the plugin forwards everything except for events that match the specified ausearch expressions in the configuration" - which seems error-prone to even parse, and inverted to my intuition, while an ordered list of rules explicitly saying "drop this" or "allow this" on every line is much harder to misread. And then you often can have inverted "NOT ..." rules in there, and how "not blacklist" is not at all same as "whitelist", despite somewhat intuitive dichotomy between the two.
So it was an odd realization that there doesn't seem to be a common "functional" name to call this kind of list, one which would immediately describe how it works, similar to how e.g. "whitelist" or "blacklist" words work for simpler "list of rules with same verdict/action" concept (as opposed to binary yes-or-no verdict/action here).
To be fair, often these lists get extended beyond boolean result like "allow or block" - e.g. in same firewalls or rsync examples, you have dozens if not hundreds of different rule actions, often arranged into "substacks" or "chains", but still with same basic binary logic probably applying throughout 95%+ of the ruleset.
Words tend to make it easier to quickly bring up concepts in mind, like shortcuts, so lacking one here makes it more difficult to start with this type of filter when adding any kind of -f/--filter-file option to a tool/script, even though odds are you'll end up there anyway, same as something like simplest ini file (there's a name) for any key=value parameter configuration.