SeccompBuilder¶
Overview¶
SeccompBuilder builds seccomp BPF filters through a small, high-level rule
interface.
Instead of manually writing BPF instructions, the user enables predefined syscall groups by name:
builder.allow("io");
builder.allow("file_system");
The resulting filter is represented by a SeccompRule. The rule can then be
applied to the current process through SeccompRuleView::apply().
Synopsis¶
class SeccompBuilder
{
public:
[[nodiscard]] static std::expected<SeccompBuilder, int> init() noexcept;
[[nodiscard]] static std::expected<SeccompBuilder, int> init_no_defaults() noexcept;
[[nodiscard]] std::expected<void, int>
allow(std::string_view what) noexcept;
[[nodiscard]] std::expected<SeccompRule, int>
build(bool kill_entire_process = true) noexcept;
[[nodiscard]] std::expected<SeccompRuleView, int>
build_static(bool kill_entire_process = true) noexcept;
};
Initialization¶
[[nodiscard]] static std::expected<SeccompBuilder, int> init() noexcept;
Creates a new builder with the library’s default syscall groups enabled.
This is the recommended constructor for most programs, because dynamically linked C++ programs usually require a small set of runtime-related syscalls before application-specific operations are considered.
Returns a SeccompBuilder on success, or a positive errno value on failure.
[[nodiscard]] static std::expected<SeccompBuilder, int> init_no_defaults() noexcept;
Creates a new builder without enabling any default syscall groups.
This is useful for stricter configurations or tests where every allowed syscall group should be specified explicitly.
Returns a SeccompBuilder on success, or a positive errno value on failure.
allow¶
[[nodiscard]] std::expected<void, int>
allow(std::string_view what) noexcept;
Enables a predefined syscall group.
The exact groups are defined by the library. Typical examples include groups for basic I/O, filesystem access, memory management, process control, or IPC-related operations.
Parameters¶
what— name of the syscall group to enable.
Returns¶
Returns an empty std::expected on success, or a positive errno value on
failure.
Notes¶
Calling allow() does not apply any restrictions immediately. It only changes
the builder state. The seccomp filter is generated later by build() or
build_static().
build¶
[[nodiscard]] std::expected<SeccompRule, int>
build(bool kill_entire_process = true) noexcept;
Builds an owning SeccompRule from the currently enabled syscall groups.
The returned rule owns the generated BPF program and can be applied through its view:
auto rule = unwrap_or_die(builder.build());
unwrap_or_die(rule.view().apply());
Parameters¶
kill_entire_process— controls the terminal seccomp action used when a disallowed syscall is reached. Whentrue, the process is killed. Whenfalse, only the offending thread is killed.
Returns¶
Returns a SeccompRule on success, or a positive errno value on failure.
build_static¶
[[nodiscard]] std::expected<SeccompRuleView, int>
build_static(bool kill_entire_process = true) noexcept;
Builds a non-owning SeccompRuleView.
This variant is intended for cases where the generated filter storage is managed
elsewhere or has static lifetime. For ordinary user code, prefer build().
Parameters¶
kill_entire_process— controls the terminal seccomp action used when a disallowed syscall is reached. Whentrue, the process is killed. Whenfalse, only the offending thread is killed.
Returns¶
Returns a SeccompRuleView on success, or a positive errno value on failure.
Example¶
The following example creates a seccomp filter, enables a small set of syscall groups, builds the final rule, and applies it to the current process.
#include <mylib/no_new_privs.h>
#include <mylib/seccomp.h>
#include <cstdlib>
#include <cstring>
#include <expected>
#include <iostream>
#include <utility>
[[noreturn]] void die(int why) noexcept
{
std::cerr << "error: " << std::strerror(why) << '\n';
std::exit(1);
}
template <class T>
T unwrap_or_die(std::expected<T, int>&& result)
{
if (!result) {
die(result.error());
}
return std::move(result).value();
}
inline void unwrap_or_die(std::expected<void, int>&& result)
{
if (!result) {
die(result.error());
}
}
int main()
{
unwrap_or_die(mylib::set_no_new_privs());
auto builder = unwrap_or_die(mylib::SeccompBuilder::init());
unwrap_or_die(builder.allow("io"));
unwrap_or_die(builder.allow("file_system"));
auto rule = unwrap_or_die(builder.build());
unwrap_or_die(rule.view().apply());
// Disallowed syscalls are blocked from this point onward.
return 0;
}