A condition is a boolean expression related to a single event that has been detected by Falco. You can use fields related to every supported event, but this document focuses on syscalls as they're currently the most common. The language supports boolean operators and parentheses as you'd expect. For example a condition like:
evt.type = execve and evt.dir = < and (proc.name = cat or proc.name = grep)
This will trigger for each execution of
grep. Below you can take a closer look at what is the meaning of those fields such as
evt.dir, how to discover the types of events available, and which fields are present with which event type.
Syscall event types, direction and args
Every syscall event will present the
evt field class. Each condition that you write for those events will normally start with a
evt.type expression or macro; this makes a lot of sense since security rules normally consider one syscall type at a time. For instance, you may want to consider
openat to catch suspicious activity when opening files,
execve to inspect spawned processes, and so forth. You don't have to guess the syscall name, as you can see the complete list of supported system calls events and understand which ones you can use.
Every syscall has an entry event and an exit event which is shown in the
evt.dir field, also known as the "direction" of the system call. A value of
> indicates entry, which fires when the syscall is invoked, while
< marks exit, meaning that the call has returned. In fact, by looking at the supported system call list you can see that our events have both entries. For example:
> setuid(UID uid) < setuid(ERRNO res)
Most of the time the engine informs you about exit events as you want to understand what happened after the event execution is complete. You can see by using the events associated with opening files.
> open() < open(FD fd, FSPATH name, FLAGS32 flags, UINT32 mode, UINT32 dev) > openat() < openat(FD fd, FD dirfd, FSRELPATH name, FLAGS32 flags, UINT32 mode, UINT32 dev)
As you can see, each event has a list of arguments associated with it that you can access by using
evt.arg.<argname>. For example, to identify when a process opens a file to overwrite it, you need to check if the list of flags contains
O_TRUNC. You can use the
evt.arg.flags field of the
openat exit events shown above and the rule will then look like this:
evt.type in (open, openat) and evt.dir = < and evt.arg.flags contains O_TRUNC
Note that the arguments do not necessarily match the raw parameters that are used in the Linux kernel, but are parsed by Falco to make it easier to write rules. By using the
evt fields we can inspect many more aspects that are common across events.
Syscall event context and metadata
evt fields allow you to write pretty expressive conditions, arguments and common fields are usually not enough to write full security rules. Many times you want to add conditions based on the process context the event happens in, or whether or not something is happening inside a container or even correlate each event with the relevant Kubernetes metadata for the cluster, pods, and more. For this reason, Falco enriches many events with other field classes. Not all the classes are available for all the events and the list can grow. The documentation for each clarifies when those are expected to be available, but some are so common that you often rely on them.
proc field class gives you the context about the process and thread that is generating a specific syscall. This information is usually very important. The most basic piece of information you can get out of it is
proc.pid, but you can even traverse the process hierarchy by using
proc.apid[<n>]. Likewise, you may be interested in which user performs a specific action via the
user field class.
The documentation gives you an example of how to catch executions of
bash within containers:
if evt.type = execve and evt.dir = < and container.id != host and proc.name = bash
Note that you don't even have to look at the
execve args. That is because once
execve has returned the process context recorded by Falco is updated, meaning that the
proc. fields will already refer to all information, including the command line, executable, arguments, related to the new process that was just spawned.
Rule Condition Best Practices
To allow for grouping rules by event type, which improves performance, Falco prefers rule conditions that have at least one
evt.type= operator, at the beginning of the condition, before any negative operators (i.e.
!=). If a condition does not have any
evt.type= operator, Falco logs a warning like:
Rule no_evttype: warning (no-evttype): proc.name=foo did not contain any evt.type restriction, meaning that it will run for all event types. This has a significant performance penalty. Consider adding an evt.type restriction if possible.
If a rule has an
evt.type operator in the latter portion of the condition, Falco logs a warning like this:
Rule evttype_not_equals: warning (trailing-evttype): evt.type!=execve does not have all evt.type restrictions at the beginning of the condition, or uses a negative match (i.e. "not"/"!=") for some evt.type restriction. This has a performance penalty, as the rule can not be limited to specific event types. Consider moving all evt.type restrictions to the beginning of the rule and/or replacing negative matches with positive matches if possible.
You can use the following operators in conditions:
|Equality and inequality operators.|
|Comparison operators for numeric values.|
|For strings will evaluate to true if a string contains another, and |
|Check prefix or suffix of strings.|
|Evaluate standard glob patterns. Example: |
|Compare a file path against a set of file or directory prefixes. Example: |
|Check if a field is set. Example: |
|These operators work similarly to |
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.