Rust and Suricata

In the newly released Suricata 4.0, one of the major new features is integration of Rust. In the words of the Rust Language project, “Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.”

For those of you who were at SuriCon DC, the topic of Rust isn’t new. Pierre Chiffliers’  talk ‘Securing Security Tools’ described why switching existing C/C++ tools to partly use Rust language parsers makes sense. See his slides here: pdf. After his talk, we have started looking into the proof of concept proposed by Pierre.

Rust was new to us so the process involved learning the language.

Major Components

  1. rust language: a safe systems programming language that compiles to native code and can be linked into a C program
  2. nom: a rust macro parser generator
  3. suricata – rust layer: connection between the rust code and the Suricata API’s

Rust Usage in Suricata

Rust parsers might be used for many things:

  • simple header parsers where we’d use a rust/nom parser for a header like DNS
  • specific data types, I’m thinking mostly about ASN.1 and mime here as those are notorious for vulnerabilities
  • full application layer parsing and logging in Suricata

Experiment

After the initial testing and playing by Jason Ish and Victor Julien, we have decided to move forward with Rust. However, as the language is young and our understanding of it is even younger, we will consider it experimental at first.

The experimental phase will have to teach us a couple of things:

  1. how does it work wrt stability and performance
  2. what does it take to support Suricata with Rust extensions
  3. how mature is the Rust ecosystem

Depending on our experiences we’re planning to take between 6 and 12 months for this experimental phase. As we’re considering this experimental we’re going to be quite liberal with regards to updates to the Rust code inside our stable branch.

The initial 4.0 code contains the following parts:

  • Re-implementation of the DNS parser, which is mostly stateless.
  • A NFS parser with logging, file extraction and basic detection integration.
  • A NTP parser done by Pierre that for a significant part is an external crate

Some initial thoughts

As predicted by many, the learning curve for Rust is indeed quite steep. It’s not just the Rust language itself, which has some novel but tricky concepts around lifetimes. It’s also the ‘nom’ framework which although generally easy to work with, can emit really cryptic compiler error messages if small mistakes (like a missing comma) are made.

Rust is really nice though. In our testing it performs well, and its really nice to have code that doesn’t segfault. In Rust, if the compiler accepts the code, it usually works. Also, conditions that may lead to undefined state in C are detected by Rust which will cause the program to to abort, instead of continuing, possibly in a condition where exploitation is possible.

Pierre’s ‘Rusticata’ work

In our initial integration we’re not using much of Pierre’s work yet. The main reasons for this are:

  • Pierre is implementing parsers as external modules (Crates in Rust speak) and we want to limit the number of external dependencies we introduce
  • learning the Rust language and ecosystem all but required that we did everything ourselves, even if it meant redoing what Pierre already did (even in less efficient ways sometimes)

However we have added another layer of ‘experimental’ for including Pierre’s work step by step.

By using the –enable-rust-experimental configure flag the parser Pierre has written are enabled.

Timeline

  • Summer 2017: Suricata 4.0 was released with experimental Rust support, implementing DNS, NFS and NTP
  • Late Fall 2017: Suricata 4.1 with still experimental Rust support, likely adding a few protocols
  • Spring 2018: Suricata 5.0 with default non-experimental (and probably mandatory) Rust support

Trying our Rust support

If you want to play with the current support, here is a page with installation instructions.

On a modern distro, it’s really as simple as installing rustc and cargo, followed by passing –enable-rust to configure. Tested on Ubuntu, Fedora and FreeBSD.

Training

In September we’re offering the third edition of our annual Suricata developer training. In this 5-day event we’re teaching how to extend Suricata. We’re planning to spend about one day on covering the Rust integration.

See: https://suricata_events.eventbrite.com/

Common questions

Q: Are you moving to Rust completely?

A: No, not anytime soon. Time will tell how this experiment evolves.

Q: Does it make Suricata harder to use?

A: No, to end-users the Rust support is transparent other than installing the build dependencies rustc and cargo.

Q: Does it make Suricata harder to compile?

A: No, not on modern distributions. All you need is the rust compiler and cargo.

Q: Where can I learn more?

A: We’re offering a developer training at https://suricata_events.eventbrite.com/