Skip to content

Commit

Permalink
Use pledge(2) on OpenBSD to restrict system calls
Browse files Browse the repository at this point in the history
Limit the attack surface of spotifyd, an internet facing network daemon with
read/write filesystem access and options to execute arbitrary commands.

Most importantly, prevent fork(2)/execve(2) unless `onevent` is used.

While the set of runtime promises retains full read/write filesystem as well
as network access (for now), it does exclude a number of groups of unused
system calls -- the manual[0] for details.

OpenBSD's official package has been shipping this patch for a month by now
without any regressions or reports of breakage.

0: https://man.openbsd.org/pledge.2
  • Loading branch information
klemensn committed Feb 4, 2024
1 parent 663d067 commit 269e625
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ syslog = "6"
[target."cfg(target_os = \"macos\")".dependencies]
whoami = "1"

[target."cfg(target_os = \"openbsd\")".dependencies]
pledge = "0.4.2"

[dev-dependencies]
env_logger = "0.10"

Expand Down
33 changes: 33 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use log::{info, trace, LevelFilter};
use std::fs;
use structopt::StructOpt;
use tokio::runtime::Runtime;
#[cfg(target_os = "openbsd")]
use pledge::pledge;

#[cfg(feature = "alsa_backend")]
mod alsa_mixer;
Expand Down Expand Up @@ -85,6 +87,11 @@ fn setup_logger(log_target: LogTarget, verbose: bool) -> eyre::Result<()> {
}

fn main() -> eyre::Result<()> {
// Start with superset of all potentially required promises.
// Drop later after CLI arguments and configuration files were parsed.
#[cfg(target_os = "openbsd")]
pledge("stdio rpath wpath cpath inet mcast flock chown unix dns proc exec audio", None).unwrap();

color_eyre::install().wrap_err("Couldn't initialize error reporting")?;

let mut cli_config: CliConfig = CliConfig::from_args();
Expand Down Expand Up @@ -166,6 +173,32 @@ fn main() -> eyre::Result<()> {
}
}

#[cfg(target_os = "openbsd")]
{
// At this point:
// * --username-cmd, --password-cmd were handled
// > no "proc exec"
// * --pid, daemon(3) were handled
// > no "cpath flock chown" for PID file
// > no "proc" for double-fork(2)
//
// Required runtime promises:
// stdout/err, syslog(3) "stdio"
// ${TMPDIR}/.tmp*, cache "[rwc]path"
// Spotify API/Connect "inet dns"
// D-Bus, MPRIS "unix"
// Zeroconf Discovery "mcast"
// PortAudio, sio_open(3) ("[rwc]path unix inet audio")
// > after sndio(7) cookie "audio"

// --on-song-change-hook aka. "onevent", run via --shell aka. "shell"
if internal_config.onevent.is_some() {
pledge("stdio rpath wpath cpath inet mcast unix dns proc exec audio", None).unwrap();
} else {
pledge("stdio rpath wpath cpath inet mcast unix dns audio", None).unwrap();
}
}

let runtime = Runtime::new().unwrap();
runtime.block_on(async {
let mut initial_state = setup::initial_state(internal_config);
Expand Down

0 comments on commit 269e625

Please sign in to comment.