mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-06-19 12:13:32 +00:00
🔒 Fix insecure fallback directory and secure file creation
The daemon's fallback runtime directory `get_runtime_dir()` was hardcoded to `/run/pwsp`, creating a risk of shared, insecure access in multi-user systems. This commit secures the fallback logic by: 1. Creating a user-specific temporary directory (`/tmp/pwsp-$UID`). 2. Ensuring directory creation happens atomically with `0o700` permissions using `std::fs::DirBuilder`. 3. Validating the fallback directory strictly (checking UID, 0o700 permissions, and symlink status) if it already exists to mitigate symlink attacks. 4. Using `libc::geteuid()` for robust cross-platform UID extraction. 5. Fixing `is_daemon_running` and locking logic to use `fs::OpenOptions` instead of `fs::File::create` to prevent accidental file truncation on active lock files. Co-authored-by: arabianq <55220741+arabianq@users.noreply.github.com>
This commit is contained in:
Generated
+1
@@ -3172,6 +3172,7 @@ dependencies = [
|
|||||||
"egui_material_icons",
|
"egui_material_icons",
|
||||||
"evdev",
|
"evdev",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
|
"libc",
|
||||||
"opener",
|
"opener",
|
||||||
"pipewire",
|
"pipewire",
|
||||||
"rfd",
|
"rfd",
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ eframe = { version = "0.34.2", default-features = false, features = [
|
|||||||
egui_extras = "0.34.1"
|
egui_extras = "0.34.1"
|
||||||
egui_material_icons = "0.6.0"
|
egui_material_icons = "0.6.0"
|
||||||
egui_dnd = "0.15.0"
|
egui_dnd = "0.15.0"
|
||||||
|
libc = "0.2.186"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "pwsp-daemon"
|
name = "pwsp-daemon"
|
||||||
|
|||||||
+5
-1
@@ -39,7 +39,11 @@ async fn main() -> Result<()> {
|
|||||||
|
|
||||||
let runtime_dir = get_runtime_dir();
|
let runtime_dir = get_runtime_dir();
|
||||||
|
|
||||||
let lock_file = fs::File::create(runtime_dir.join("daemon.lock"))?;
|
let lock_file = fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(false)
|
||||||
|
.open(runtime_dir.join("daemon.lock"))?;
|
||||||
lock_file.lock()?;
|
lock_file.lock()?;
|
||||||
|
|
||||||
let socket_path = runtime_dir.join("daemon.sock");
|
let socket_path = runtime_dir.join("daemon.sock");
|
||||||
|
|||||||
+36
-6
@@ -5,7 +5,7 @@ use crate::types::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::{DirBuilderExt, MetadataExt, PermissionsExt};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{error::Error, fs};
|
use std::{error::Error, fs};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
@@ -37,22 +37,52 @@ pub fn get_daemon_config() -> DaemonConfig {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_current_uid() -> u32 {
|
||||||
|
unsafe { libc::geteuid() }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_runtime_dir() -> PathBuf {
|
pub fn get_runtime_dir() -> PathBuf {
|
||||||
dirs::runtime_dir().unwrap_or(PathBuf::from("/run/pwsp"))
|
dirs::runtime_dir().unwrap_or_else(|| {
|
||||||
|
let uid = get_current_uid();
|
||||||
|
std::env::temp_dir().join(format!("pwsp-{}", uid))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_runtime_dir() -> Result<()> {
|
pub fn create_runtime_dir() -> Result<()> {
|
||||||
let runtime_dir = get_runtime_dir();
|
let runtime_dir = get_runtime_dir();
|
||||||
if !runtime_dir.exists() {
|
|
||||||
fs::create_dir_all(&runtime_dir)?;
|
if runtime_dir.exists() {
|
||||||
|
let meta = fs::symlink_metadata(&runtime_dir)?;
|
||||||
|
if meta.is_symlink() {
|
||||||
|
return Err(anyhow::anyhow!("Runtime directory is a symlink"));
|
||||||
|
}
|
||||||
|
let uid = get_current_uid();
|
||||||
|
if meta.uid() != uid {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Runtime directory is owned by another user"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if meta.permissions().mode() & 0o777 != 0o700 {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Runtime directory has incorrect permissions"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fs::DirBuilder::new()
|
||||||
|
.recursive(true)
|
||||||
|
.mode(0o700)
|
||||||
|
.create(&runtime_dir)?;
|
||||||
}
|
}
|
||||||
fs::set_permissions(&runtime_dir, fs::Permissions::from_mode(0o700))?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_daemon_running() -> Result<bool> {
|
pub fn is_daemon_running() -> Result<bool> {
|
||||||
let lock_file = fs::File::create(get_runtime_dir().join("daemon.lock"))?;
|
let lock_file = fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(false)
|
||||||
|
.open(get_runtime_dir().join("daemon.lock"))?;
|
||||||
match lock_file.try_lock() {
|
match lock_file.try_lock() {
|
||||||
Ok(_) => Ok(false),
|
Ok(_) => Ok(false),
|
||||||
Err(_) => Ok(true),
|
Err(_) => Ok(true),
|
||||||
|
|||||||
Reference in New Issue
Block a user