Expand description
Dynamic .so audio-plugin loader with ABI verification and FreeBSD
Capsicum/pdfork per-process sandboxing for real-time audio in Rust.
This crate loads third-party audio plugins compiled as cdylib
(.so / .dylib / .dll) shared objects, verifies their ABI against the
host, instantiates them behind a stable extern "C" entry point, and — on
FreeBSD — confines each plugin to a Capsicum capability sandbox
(optionally one isolated child process per plugin via pdfork).
§Wire ABI
Plugins do not cross the .so boundary as Rust trait objects
(Box<dyn AudioNode>). A Rust trait object’s layout and vtable are defined
by the compiling toolchain and are not ABI-stable across different
rustc or dependency versions; casting a foreign .so’s pointer to a Rust
trait object is undefined behaviour. Instead, every plugin exposes plain
extern "C" entry symbols:
audio_plugin_abi_magic() -> u32— must equalAUDIO_PLUGIN_ABI_MAGIC(0x41504C47, ASCII"APLG").audio_plugin_abi_version() -> u32— encoded viaencode_abi_version; the host accepts any plugin whose major version matches its own (seeis_abi_compatible).audio_plugin_metadata()andaudio_plugin_create()— identity and an opaque handle consumed by the loader (follow-up task).
The host never reinterpret-casts the returned pointer as a Rust trait
object; it only calls further extern "C" functions on it. See abi
for the version-encoding and compatibility rules.
§Security warning — untrusted shared objects
Loading a .so executes its initialisation code in the host process.
Never load a plugin you do not fully trust unless it is confined. On
FreeBSD this crate confines plugins with Capsicum; on other platforms the
sandbox is a no-op and untrusted plugins must not be loaded at all.
§Platform notes
The capsicum and pdfork dependencies are gated behind
cfg(target_os = "freebsd") and are not compiled on Linux, macOS, or
Windows. On non-FreeBSD targets this crate still compiles and exposes the
ABI / error / metadata types, but the loader’s sandboxing is inactive.
§IPC protocol
Host↔plugin communication uses a simple binary protocol defined in
proto. Every message is a single tag byte followed by a fixed-layout
payload (u32 little-endian integers and length-prefixed UTF-8 strings).
All decode functions are panic-free; malformed input returns
PluginError::Sandbox.
§Sandbox configuration
sandbox exposes IsolationLevel and SandboxConfig
for controlling per-plugin confinement. On non-FreeBSD platforms only
IsolationLevel::None is available.
§Per-plugin process isolation
On FreeBSD, isolation exposes spawn_isolated, which runs
each plugin in a dedicated pdfork child process confined to a Capsicum
capability sandbox (cap_enter). Host↔plugin communication uses the
length-prefixed proto messages over a Unix-domain socketpair. On
non-FreeBSD targets spawn_isolated always returns
PluginError::Sandbox. See isolation for the 0.1.0 control-loop
scope and the real-time audio follow-up.
§Real-time safety boundary
The loader, ABI check, sandbox setup, and plugin instantiation all run on a
non-RT (setup) thread. Code on the RT audio thread must only call into
an already-instantiated plugin’s process path (provided by the adapter in
a follow-up task) and must obey the RT contract documented in
audio-core-bsd.
Re-exports§
pub use abi::abi_major;pub use abi::abi_minor;pub use abi::encode_abi_version;pub use abi::is_abi_compatible;pub use abi::AbiVersion;pub use abi::AUDIO_PLUGIN_ABI_MAGIC;pub use abi::AUDIO_PLUGIN_ABI_VERSION;pub use error::PluginError;pub use error::Result;pub use isolation::spawn_isolated;pub use isolation::SandboxedProcess;pub use loader::LoadedPlugin;pub use loader::PluginId;pub use loader::PluginLoader;pub use metadata::PluginMetadata;pub use plugin::Plugin;pub use proto::decode_request;pub use proto::decode_response;pub use proto::encode_request;pub use proto::encode_response;pub use proto::PluginMetadataPayload;pub use proto::Request;pub use proto::Response;pub use sandbox::IsolationLevel;pub use sandbox::SandboxConfig;pub use symbols::AbiMagicFn;pub use symbols::AbiVersionFn;pub use symbols::CreateFn;pub use symbols::DestroyFn;pub use symbols::MetadataFn;pub use symbols::RawPluginMetadata;pub use symbols::AUDIO_PLUGIN_ABI_MAGIC_SYMBOL;pub use symbols::AUDIO_PLUGIN_ABI_VERSION_SYMBOL;pub use symbols::AUDIO_PLUGIN_CREATE_SYMBOL;pub use symbols::AUDIO_PLUGIN_DESTROY_SYMBOL;pub use symbols::AUDIO_PLUGIN_METADATA_SYMBOL;
Modules§
- abi
- Audio-plugin ABI version encoding and compatibility rules.
- error
- Plugin-loader errors and the crate
Resultalias. - isolation
- Per-plugin process isolation runtime.
- loader
- Dynamic plugin loader:
PluginLoader,LoadedPlugin, andPluginId. - metadata
- Static metadata describing a loaded plugin (name, version, description, …).
- plugin
- The host-side
Plugintrait, the [HostPlugin] adapter that bridges the C ABI to it, and the [AudioNodeAdapter] that wraps an opaque plugin handle behindaudio_core_bsd::AudioNode. - proto
- IPC message protocol for host↔plugin communication.
- sandbox
- Sandbox configuration:
IsolationLevel,SandboxConfig, and platform availability checks. - symbols
- C ABI symbol contract: the entry symbols every plugin must expose, their
function-pointer types, and the
#[repr(C)]metadata struct returned byaudio_plugin_metadata.