Getting started developing Falco

loresuso

Lorenzo Susini

Posted on May 11, 2022

Getting started developing Falco

Hello, Falcoers!
Interested in Falco and want to contribute your ideas? Feeling stuck because you don't know where to start? No worries, we are here to help!
Whether you want Falco to monitor a new system call, add a brand new feature, or solve a problem you ran into, you have to create a development environment. This blog post will walk you through the process of setting up a new one so that you can feel comfortable and ready to contribute!
Now, let's go step by step, showing what is required to get started hacking on Falco. We hope this table of contents will facilitate the use of this post as a future reference.

Setting up the environment

A peculiarity of the Falco project is that you may need to write some kernel-level code. An important consideration to make, even before starting to code, is that the eBPF probe and the kernel module should provide exactly the same features.
For this reason, when developing something on the eBPF probe, you should implement the same functionality on the kernel module and vice versa, with the intent of preserving feature parity across the two drivers.
Writing code at the kernel-level is not an easy task. In particular, the kernel module requires extra care because your code will run with full kernel privileges. Any little mistake may result in a kernel panic, crashing the system.
On the other hand, eBPF programs are much safer than the kernel module, but sometimes you may need to fight against the verifier on different kernel versions.
For these reasons, some of us find using Vagrant extremely helpful. Vagrant is a tool that allows you to easily spawn virtual machines, so that you can test your code against multiple kernel versions and Linux distributions without causing any harm to your system.

Creating a dedicated VM

If you have never used Vagrant before, you first need to download and install Vagrant and a Vagrant VM provider. You may want to install VirtualBox since Vagrant comes with out-of-the-box support. You can follow the Vagrant quickstart to accomplish this.
Once you can spawn VMs with Vagrant, choose a box from Vagrant Cloud containing your favorite distribution for development.
For instance, if you want to launch a Ubuntu Focal Fossa machine, you can issue the following commands:

$ mkdir ubuntu-vm && cd ubuntu-vm
$ vagrant init ubuntu/focal64
$ vagrant up
Enter fullscreen mode Exit fullscreen mode

Vagrant initializes virtual machines so that you can easily access them via SSH. This helps in case you also want to try out remote development, for instance with Visual Studio Code. This way, you will be able to seamlessly code, build, and test on the Vagrant virtual machine!
From now on, the command vagrant ssh will log you into the VM and you could start working right away. However, unless you prefer writing code on older (but very powerful) tools like Vim, you may feel the need to use an IDE, as if you were developing on your local machine.
To do so, we will show you how to extend Visual Studio Code capabilities by downloading the Remote - SSH extension. This extension lets you use any remote machine that allows SSH access as your development environment. This includes the VM you just spawned with Vagrant.
After installing the extension, from inside the Vagrant VM directory, retrieve the SSH configuration:

$ vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/lorenzo.susini/vagrant/official-ubuntu/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL
Enter fullscreen mode Exit fullscreen mode

Copy the output of the last command and paste it into the .ssh/config file in your local home directory. Also, we recommend changing the Host default line with something that helps you remember that this is the VM you use for developing Falco. Something like Host falco-dev would work.
Then, go back to Visual Studio Code. Press Control + P (or Command + P on MacOS) and type > Remote-SSH: Connect to Host. Press Enter and you will see the falco-dev entry in the UI to connect to the VM.
Example of development lifecycle
Your development environment is now up and running. You can open remote folders and projects, and use all the functionalities of Visual Studio Code!

Discovering the Falco code

Now, it's time to have some fun. Falco's source code lives in the Falco organization on GitHub. The two repositories you should take a look at are:

  • falcosecurity/libs, containing both the kernel module and the eBPF probe, and also libscap and libsinsp.
  • falcosecurity/falco, including the rule engine, rules, and support for any kind of output, such as standard output, file output, gRPC, and more. If you're not yet familiar with the overall Falco architecture, you can go into detail by reading the previous blog post.

Building Falco from scratch

Most of the time, the main starting point for developing something is building it from scratch. You can fork falco and libs, and clone them into your development machine. Forking the repositories first is recommended if you want to later push the changes and save your work.
Then, try to follow the steps in our official Falco documentation. Some of the most useful CMake definitions you may want to use are:

  • -DUSE_BUNDLED_DEPS=ON allows you to download and compile all the needed Falco dependencies. This also helps to build Falco independently of the libraries installed in your system. The build process will run trouble-free using this option, although it will be a little bit slower.
  • -DFALCOSECURITY_LIBS_SOURCE_DIR=/path/to/local/libs allows you to compile Falco with a local version of libs. If not specified, CMake will download the libs repository directly from GitHub. This option is extremely handy when you are implementing something that requires modification to both falco and libs repositories so that you can easily test what you coded.
  • -DBUILD_BPF=ON allows compilation of the eBPF probe, crucial when developing something on the eBPF driver.
  • -DCMAKE_BUILD_TYPE=Debug is helpful when you want to debug something. Debug information is printed out and assertions are enabled. The complete sequence of commands you may want to run is:
$ mkdir build && cd build
$ cmake -DUSE_BUNDLED_DEPS=ON \
        -DFALCOSECURITY_LIBS_SOURCE_DIR=/path/to/local/libs \
        -DBUILD_BPF=ON \
        -DCMAKE_BUILD_TYPE=Debug  ..
$ make
Enter fullscreen mode Exit fullscreen mode

Also, note that you can use the -jxxx option of make to spawn multiple parallel jobs, where xxx is the number of jobs.
Create your own Falco feature

Testing your build

Now that you have successfully compiled Falco, try to run it. The default driver is the kernel module. To use it, assuming that you are in the build directory, just type:

$ sudo insmod driver/falco.ko
$ sudo ./userspace/falco/falco -c ../falco.yaml \
       -r ../rules/falco_rules.yaml
Enter fullscreen mode Exit fullscreen mode

To start Falco with the eBPF driver instead, you need to set the FALCO_BPF_PROBE environment variable, like this:

$ sudo FALCO_BPF_PROBE=driver/bpf/probe.o ./userspace/falco/falco \
       -c ../falco.yaml  -r ../rules/falco_rules.yaml
Enter fullscreen mode Exit fullscreen mode

Falco Event-Generator

Now that you built Falco, you may wonder if everything works as expected. A quick and dirty way of testing Falco is using the event-generator.
This is yet another project from the Falcosecurity organization, and it can be used to generate some suspicious actions on the system, therefore, triggering some Falco rules.
All you need to do is to start two terminals. You will launch Falco from one of them and leave it running. From the second terminal, launch the event generator using the following command:

docker run -it --rm falcosecurity/event-generator run syscall
Enter fullscreen mode Exit fullscreen mode

If everything works fine, in the first terminal you opened you will see Falco alerting of some malicious behaviors from the container we started in the second one.

Falco Test Suite

You can also test Falco by using its own test-suite. The Falco test-suite uses the Avocado Framework to launch tests.
All you have to do is the following:

$ cd falco/test
$ ./run_regression_tests.sh -p -v
$ virtualenv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
$ BUILD_DIR="../build" avocado run --mux-yaml falco_traces.yaml \
  --job-results-dir /tmp/job-results -- falco_test.py
$ deactivate
Enter fullscreen mode Exit fullscreen mode

The run_regression_tests.sh script downloads and prepares trace files needed for testing. Falco can consume these files containing some recorded system activity that must trigger rules.
If you want, you can also refer to the documentation to launch other kinds of tests, such as rule engine and k8s audit logs tests, just to name a few.
You can relaunch these tests whenever you add something to the codebase, just to make sure nothing got broken after you played around with it.
You are now ready to put your hands on Falco!

Writing your own test rules

At this point, let's say you have introduced a new syscall. A possible way to effectively test it is to write a custom rule. You can dig deeper on how to write rules by reading the related section in the official documentation.
Falco's rule syntax is very simple and you will be able to write rules down very soon. A rule is made of:

field name field description
rule name a short unique name for the rule
description a longer description of what the rule detects
condition a filtering expression that is applied against events
to see if they match the rule
output a message that should be produced if a matching
event occurs
priority severity associated with the rule

To give you a little taste of writing rules, let's assume you have followed the aforementioned post where we added support for a new syscall. You would like to throw an alert every time a process executes it.
You could create a rule.yaml file having this as content:

- rule: My test rule
  desc: Detects any process executing openat2 and prints its name and pid
  condition: evt.type = openat2
  output: openat2 executed by (process name: %proc.name, pid: %proc.pid)
  priority: NOTICE
Enter fullscreen mode Exit fullscreen mode

Then, you can use the -r option to tell Falco to use this rule file. Of course, you can create much more complex and meaningful rules using many different fields and operators.

Conclusion

You have learned how to set up a development environment with the help of Vagrant and Visual Studio Code, and how to build and run tests on Falco. You are now all set to dig into the source code, hack around, and unleash your creativity! We can't wait to see some of your PRs and build something great together!
You can find us in the Falco community. Please feel free to reach out to us for any questions, suggestions, or just a friendly chat!
If you would like to find out more about Falco:

💖 💪 🙅 🚩
loresuso
Lorenzo Susini

Posted on May 11, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related