Kernel Interface
Every interface the Riptides kernel module exposes to user space, and who is allowed to use each one. If you are reviewing the module’s attack surface, this page is the complete list.
There is no ioctl and no netlink interface. The module is reached through one
character device (two with the pro module), a set of module parameters, sysfs
and procfs entries, kernel tracepoints, a single socket option, and a hook on
every execve, which only acts when env_inject is on.
Authorization
Section titled “Authorization”| Operation | Requirement |
|---|---|
| Load the module | CAP_SYS_MODULE |
Open /dev/riptides or /dev/riptides_pro and command the driver | CAP_SYS_ADMIN |
| Change a module parameter at runtime | CAP_SYS_ADMIN (or CAP_SYS_MODULE) |
| Read the diagnostic entries | file permissions (see below) |
| Read a credential file | the reading process must resolve to the credential’s workload |
| Read the tracepoints | root, or CAP_PERFMON (with CAP_BPF for eBPF) |
| Opt out of environment injection | none: any process, through its own environment |
CAP_SYS_ADMIN is checked inside the module, so file ownership is not the only
gate: a process holding CAP_DAC_OVERRIDE cannot command the driver on the
strength of that capability alone.
On SELinux hosts the optional riptides-selinux package narrows it further, so
that only the daemon’s own SELinux domain, and privileged containers, can open
the devices through /dev, regardless of capabilities. See
Host Hardening. It is not required: the
driver runs without it, and the capability check above is independent of
SELinux.
Character device
Section titled “Character device”| Path | Mode | Purpose |
|---|---|---|
/dev/riptides | 0600 | Daemon IPC: Protocol Buffer messages in both directions |
/dev/riptides_pro | 0600 | Pro module only: the daemon writes the credentials injected into workload traffic |
Each device is exclusive: one holder at a time. A second open returns
EBUSY, so a stray process cannot quietly attach alongside the daemon. They are
the only interfaces that can change policy, identities or credentials. A
CAP_SYS_ADMIN holder can still switch enforcement off as a whole: enabled
set to N stops interception, and force_close kills the daemon, after which
new connections go through unevaluated until it is back.
Module parameters
Section titled “Module parameters”Under /sys/module/riptides/parameters/, mode 0644 — world-readable, and
writable only with CAP_SYS_ADMIN, or CAP_SYS_MODULE, which could load a
module of its own anyway. Values may also be set at load time.
| Parameter | Type | Default | Effect |
|---|---|---|---|
enabled | bool | Y | Enable or disable interception at runtime |
ktls_enabled | bool | Y | Offload the record layer to kTLS where available |
mdx_enabled | bool | Y | Perform the metadata-exchange handshake |
mdx_tcpopt_enabled | bool | Y | Carry MDX hints in a TCP option |
mdx_dscp_enabled | bool | N | Carry MDX hints in the DSCP field |
trace_all_sockets | bool | Y | Attach a traced socket to every new TCP connection |
eval_fail_closed | bool | N | Reset a connection when a policy evaluation fails, instead of letting it proceed unprotected |
key_type | string | ec | Key type for certificate operations: ec or rsa |
command_timeout | uint | 1 | Seconds to wait for a daemon answer |
augmentation_height | uint | 5 | Process-tree depth used to attribute a connection to a workload |
eval_cache_size | uint | 4096 | Policy evaluation cache capacity |
eval_cache_ttl_sec | uint | 30 | Lifetime of a cached allow decision |
eval_cache_negative_ttl_sec | uint | 5 | Lifetime of a cached deny decision |
intercept_debug | bool | N | Verbose interception logging, including decrypted intercepted traffic; see Kernel log |
env_inject | bool | N | Inject TLS trust-store environment variables at execve |
env_inject_debug | bool | N | Log every environment-injection decision |
All read-only except force_close, which takes the same capability as the
device itself.
| Path | Mode | Contents |
|---|---|---|
/sys/module/riptides/config | 0444 | Effective configuration |
/sys/module/riptides/health | 0444 | Module health and daemon connection state |
/sys/module/riptides/self | 0444 | The reading process’s workload UID, or EACCES if it has none |
/sys/module/riptides/self_spiffe | 0444 | The reading process’s SPIFFE ID, or EACCES if it has none |
/sys/module/riptides/certs/ca-certificates.crt | 0444 | Full CA bundle, for applications that verify TLS themselves |
/sys/module/riptides/certs/ca-spiffe.crt | 0444 | SPIFFE trust anchor |
/sys/module/riptides/certs/ca-intercept.crt | 0444 | Intercept CA |
/sys/module/riptides/credentials/<workload-uid>/<binding>/<file> | 0444 | Credential files delivered to workloads, replaced when the credential is refreshed; pro module only. <workload-uid> is the value self returns to that workload |
/sys/class/riptides/force_close | 0200 | Write-only: writing 1 sends SIGKILL to the process holding /dev/riptides, normally the daemon. Requires CAP_SYS_ADMIN |
The certificate files hold only public certificates and trust anchors, and any local process can read them.
Credential files are mode 0444, but the mode is not what protects them. On
every read the module resolves the reading process to a workload identity and
returns EACCES unless it is the workload the credential belongs to. Any process
that resolves to that workload can read it, so the boundary is the workload’s
identity selectors, not the Unix user. The files hold the credential itself,
secrets included: an OCI credential delivers the workload’s RSA private key as
private_key.pem.
Procfs
Section titled “Procfs”Read-only, mode 0440, so root only.
| Path | Contents |
|---|---|
/proc/riptides/certificates | Loaded certificates as JSON: type, subject, issuer, serial, SANs, expiry, chain length, trust status |
/proc/riptides/trust_anchors | Trust anchors currently in force |
/proc/riptides/connections | Every tracked TCP connection — all of them with trace_all_sockets on — with addresses, process identity, SPIFFE IDs, hostname, ALPN, negotiated TLS version and key-exchange group. riptides_managed marks the ones Riptides handles |
connections lists live sockets only — sample it while traffic is flowing.
Tracepoints
Section titled “Tracepoints”The module defines kernel tracepoints under the riptides system
(/sys/kernel/tracing/events/riptides/): connection open and close, sendmsg
and recvmsg, credential injection, and its own structured trace events. The
daemon reads its telemetry through them with eBPF.
They are read-only and carry connection metadata — addresses, ports, hostnames,
ALPNs, process and workload identities, credential names and IDs. No credential
values and no payload. Reading them takes what any tracepoint does: root, or
CAP_PERFMON for perf and CAP_BPF with CAP_PERFMON for eBPF.
Kernel log
Section titled “Kernel log”Normal operation logs connection events and errors, not payload or credential values. Two debug switches go further, and both should stay off in production, since the kernel log is readable by root and usually persisted by journald:
intercept_debugwrites each decrypted chunk an intercepted connection receives, in hex.- Dynamic debug, enabled with
dyndbg=at load time or through/sys/kernel/debug/dynamic_debug/control(root only), turns on debug statements that dump HTTP/2 requests after credential injection, and any message on either device that fails to decode, credential updates included.
Socket option
Section titled “Socket option”An application can ask the kernel about one of its own sockets:
#define SOL_RIPTIDES 7891#define RIPTIDES_TLS_INFO 1It returns whether policy allowed the connection (riptides_enabled), the mTLS
mode, the negotiated ALPN, and the local and peer SPIFFE IDs. It reports on the
calling process’s own file descriptor and exposes nothing about other processes’
connections, so it needs no privilege. On a socket Riptides does not handle the
kernel answers EOPNOTSUPP (IPv4) or ENOPROTOOPT (IPv6); on one whose
handshake has not finished, ENOPROTOOPT. See
Kernel Module
for a worked example.
Exec-time environment injection
Section titled “Exec-time environment injection”The module registers a binary-format handler ahead of the ELF loader whenever it
loads, so every execve on the host passes through it. With env_inject off,
the default, the handler returns at once; setting it takes effect from the next
execve, without a reload. With it on, the handler reads the new program’s
environment and adds these variables, each pointing at
/sys/module/riptides/certs/ca-certificates.crt, so unmodified programs trust
the intercept CA:
SSL_CERT_FILE, CURL_CA_BUNDLE, REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS,
AWS_CA_BUNDLE, GIT_SSL_CAINFO, GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
It injects only once the daemon has published the bundle, and only when that path resolves in the program’s mount namespace, so a container that cannot see the file gets nothing. It adds every missing variable or none. A variable already set to this path is left alone; one set to a different path gets a second entry ahead of it, which most runtimes read first.
A program started with RIPTIDES_NO_ENV_INJECT set to anything but 0 gets
nothing injected, and variables an earlier injection left in its environment
are disabled. Its children inherit the opt-out.
For review: with env_inject on, this is kernel code parsing input that any
unprivileged process controls, its own environment, and it rewrites the argument
block of every new program. It resolves one unexported kernel symbol,
expand_downwards, through kallsyms to grow that block; without it, injection
is limited to space already mapped. env_inject_debug logs each decision,
including the program name, to the kernel log.