DEV Community

Mahesh Bhatiya
Mahesh Bhatiya

Posted on

From Security Policy to eBPF: Why I Building a DSL Instead of Using C or Rust

Linux security tools increasingly rely on eBPF for things like packet filtering, traffic accounting, intrusion detection, and policy enforcement. eBPF is extremely powerful—but writing correct and verifier-friendly eBPF programs is still harder than it should be.

At first glance, we already have two solid options: C and Rust. So why build a new language at all?

This post explains the motivation behind building a domain-specific language (DSL) for security policies that compiles to eBPF.


What Makes eBPF Different

eBPF programs run inside the Linux kernel, which means they must pass a strict verifier before they can be loaded. The verifier enforces rules such as:

  • All loops must be bounded
  • Memory access must be provably safe
  • Pointer arithmetic is heavily restricted
  • No panics, unwinding, or dynamic allocation

Many errors are discovered after compilation, when the verifier rejects the program—often with cryptic messages.


Writing eBPF in C: Flexible but Fragile

C is the native language for eBPF and gives full control, but that control comes with sharp edges:

  • Manual bounds checks everywhere
  • Easy to write code that compiles but fails verification
  • Verifier errors are often hard to map back to source logic

In practice, development becomes a loop of compile → load → verifier error → retry.


Rust for eBPF: Safer, But Not a Perfect Fit

Rust improves safety significantly at the type and memory level, but eBPF breaks some of Rust’s assumptions:

  • panic is considered safe in Rust, but not supported in eBPF
  • Large parts of the standard library are unavailable
  • Some safety guarantees exist at a level eBPF simply doesn’t allow

Rust remains a great language, but when targeting eBPF it still requires working around a general-purpose model that wasn’t designed for verifier-driven execution.


The Core Problem

The real issue isn’t C or Rust—it’s the mismatch between general-purpose language semantics and eBPF verifier constraints.

Security policies are usually:

  • Bounded
  • Predictable
  • Declarative in nature

Yet we express them using languages that allow unbounded and unverifiable behavior by default.


Why a DSL Makes Sense for Security Policy

Instead of fighting the verifier after writing code, a DSL can encode verifier constraints directly into the language:

  • Only bounded loops are allowed
  • Memory access patterns are restricted by design
  • Ranges and limits can be explicit
  • Unsafe constructs simply don’t exist

This shifts feedback from runtime verifier errors to compile-time language errors.


Introducing Solnix (Briefly)

Solnix is an experimental, security-policy-focused DSL designed specifically for eBPF use cases.

Key ideas:

  • Verifier-aware semantics
  • Restricted memory and control flow
  • Compiler generates strict, verifier-friendly eBPF C code

It’s not meant to replace Rust or C—only to specialize for a domain where constraints are unavoidable.


Benefits of This Approach

  • Fewer verifier rejections
  • Faster iteration cycles
  • Clearer compile-time errors
  • Security guarantees by construction
  • Less trial-and-error in kernel space

Closing Thoughts

eBPF has changed how we build Linux security systems, but the tooling gap is still real. For highly constrained domains like security policy enforcement, a verifier-aware DSL can reduce complexity and improve reliability.

If you’re curious or want to share feedback, you can find more here:

https://solnix-lang.org

I’d love to hear your thoughts—should this kind of problem be solved with better libraries, compiler extensions, or purpose-built languages?

Top comments (0)