Falco watches system calls to catch bad stuff happening on your system.
Let’s say you have a web server running, and suddenly it starts trying to write to /etc/passwd. That’s weird, right? A web server shouldn’t be messing with user accounts. Falco sees that system call – open() for /etc/passwd with write permissions, followed by write() – and flags it as suspicious. It’s like having a security guard watching every single action your programs take.
Here’s how it works under the hood. Falco uses a kernel module (or alternatively, eBPF) to intercept system calls as they happen. Think of it as a tap into the communication channel between a program and the operating system’s kernel. When a program wants to do something like read a file, open a network connection, or execute another program, it makes a system call. Falco is right there, looking at the details of that call.
The magic really happens in Falco’s rules. These rules are written in a declarative language that describes patterns of system call activity. For example, a rule might say: "If a process that isn’t a shell tries to execute a file from /tmp, alert." Or, "If a process tries to open a file in /etc with write permissions, and that process isn’t sshd or systemd, alert." Falco evaluates these rules against the stream of system calls it’s seeing in real-time.
Let’s see this in action. Imagine we have a simple web server running in a container, and we want to make sure it doesn’t try to escape its container and mess with the host.
First, we’d start Falco. If you’re using the kernel module, it might look something like this (assuming you’ve built and loaded it):
sudo falco -c /etc/falco/falco.yaml
The falco.yaml would contain our rules. A basic rule to detect suspicious writes to sensitive files might look like this:
- rule: Suspicious write to sensitive file
desc: A non-system process is trying to write to a sensitive file.
condition: >
openat.flags.w AND
(openat.name = "/etc/passwd" OR
openat.name = "/etc/shadow" OR
openat.name = "/etc/sudoers") AND
proc.name != "sshd" AND
proc.name != "systemd" AND
proc.name != "login"
output: Suspicious write to sensitive file detected (user: %user.name, proc: %proc.name, file: %openat.name)
priority: critical
Now, let’s simulate an attack. We’ll exec into a running container and try to write to /etc/passwd.
First, find your container ID:
docker ps
Let’s say your container ID is abcdef123456. Now exec into it:
docker exec -it abcdef123456 bash
Inside the container, try to write to /etc/passwd (this will likely fail due to permissions within the container, but Falco will still see the attempt):
echo "hacked:x:0:0:root:/root:/bin/bash" >> /etc/passwd
If Falco is running on the host and monitoring this container’s system calls, you’ll see an alert in your Falco output:
10:35:15.890315678: Critical Suspicious write to sensitive file detected (user: root, proc: bash, file: /etc/passwd)
Falco intercepted the openat() system call for /etc/passwd with write flags, saw that the process (bash in this case) wasn’t one of the explicitly allowed system processes, and fired off the alert.
The mental model here is about behavior. Falco doesn’t just look at what files a program is, but what it does. It’s about detecting anomalies. The system calls are the atomic operations that programs use to interact with the OS. By analyzing sequences and properties of these calls, Falco can infer intent and detect malicious actions.
The rules are the core of this. You can define incredibly granular rules. For example, you could create a rule that alerts if a curl process attempts to write to a file in /tmp and that file is then executed. This requires Falco to correlate multiple system calls (openat, write, chmod or execve).
Falco’s power comes from its ability to operate at this fundamental level. It’s not fooled by obfuscated code or simple privilege escalation. If a process performs a suspicious action, Falco will see the underlying system call.
One thing most people don’t realize is how much context Falco can provide. The alerts aren’t just "something bad happened." They include the process name, the user, the file involved, the command line arguments, the parent process, and even container metadata if you’re running in a containerized environment. This rich context is crucial for quickly understanding the scope and impact of a potential threat.
The next step in understanding Falco is exploring its advanced rule writing capabilities, including macros, lists, and event correlation.