Skip to main content

Crate audio_plugin_bsd

Crate audio_plugin_bsd 

Source
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 equal AUDIO_PLUGIN_ABI_MAGIC (0x41504C47, ASCII "APLG").
  • audio_plugin_abi_version() -> u32 — encoded via encode_abi_version; the host accepts any plugin whose major version matches its own (see is_abi_compatible).
  • audio_plugin_metadata() and audio_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 Result alias.
isolation
Per-plugin process isolation runtime.
loader
Dynamic plugin loader: PluginLoader, LoadedPlugin, and PluginId.
metadata
Static metadata describing a loaded plugin (name, version, description, …).
plugin
The host-side Plugin trait, the [HostPlugin] adapter that bridges the C ABI to it, and the [AudioNodeAdapter] that wraps an opaque plugin handle behind audio_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 by audio_plugin_metadata.