feat: added mounts to sandboxing

This commit is contained in:
Observer KRypt0n_ 2023-04-16 14:09:53 +02:00
parent 2bc1a89f9f
commit 6d7080fbde
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
3 changed files with 108 additions and 6 deletions

View file

@ -24,5 +24,5 @@ pub mod prelude {
pub use super::gamescope::prelude::*;
#[cfg(feature = "sandbox")]
pub use super::sandbox::Sandbox;
pub use super::sandbox::*;
}

View file

@ -1,6 +1,10 @@
use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue;
mod mounts;
pub use mounts::Mounts;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Sandbox {
/// Use `bwrap` to run the game. Default is `true`
@ -9,8 +13,14 @@ pub struct Sandbox {
/// Mount tmpfs to `/home`, `/var/home/$USER` and `$HOME`. Default is `true`
pub isolate_home: bool,
/// Spoof original hostname. Default is `None`
pub hostname: Option<String>,
/// List of paths to which tmpfs will be mounted. Default is empty
pub private: Vec<String>
pub private: Vec<String>,
/// Maps of directories mounts
pub mounts: Mounts
}
impl Default for Sandbox {
@ -19,7 +29,9 @@ impl Default for Sandbox {
Self {
enabled: false,
isolate_home: true,
private: vec![]
hostname: None,
private: vec![],
mounts: Mounts::default()
}
}
}
@ -39,6 +51,20 @@ impl From<&JsonValue> for Sandbox {
None => default.isolate_home
},
hostname: match value.get("hostname") {
Some(value) => {
if value.is_null() {
None
} else {
match value.as_str() {
Some(value) => Some(value.to_string()),
None => default.hostname
}
}
},
None => default.hostname
},
private: match value.get("private") {
Some(value) => match value.as_array() {
Some(values) => {
@ -55,6 +81,11 @@ impl From<&JsonValue> for Sandbox {
None => default.private
},
None => default.private
},
mounts: match value.get("mounts") {
Some(value) => Mounts::from(value),
None => default.mounts
}
}
}
@ -75,9 +106,15 @@ impl Sandbox {
/// | `wine_dir` | `/tmp/sandbox/wine` | bind | false |
/// | `prefix_dir` | `/tmp/sandbox/prefix` | bind | false |
/// | `game_dir` | `/tmp/sandbox/game` | bind | false |
/// | <mounts/read_only> | <mounts/read_only> | read-only bind | true |
/// | <mounts/binds> | <mounts/binds> | bind | true |
pub fn get_command(&self, wine_dir: impl AsRef<str>, prefix_dir: impl AsRef<str>, game_dir: impl AsRef<str>) -> String {
let mut command = String::from("bwrap --ro-bind / /");
if let Some(hostname) = &self.hostname {
command += &format!(" --hostname '{hostname}'");
}
if self.isolate_home {
command.push_str(" --tmpfs /home");
command.push_str(" --tmpfs /var/home");
@ -97,9 +134,17 @@ impl Sandbox {
command.push_str(" --tmpfs /tmp");
command.push_str(&format!(" --bind '{}' /tmp/sandbox/wine", wine_dir.as_ref()));
command.push_str(&format!(" --bind '{}' /tmp/sandbox/prefix", prefix_dir.as_ref()));
command.push_str(&format!(" --bind '{}' /tmp/sandbox/game", game_dir.as_ref()));
for (from, to) in &self.mounts.read_only {
command += &format!(" --ro-bind '{}' '{}'", from.trim(), to.trim());
}
for (from, to) in &self.mounts.bind {
command += &format!(" --bind '{}' '{}'", from.trim(), to.trim());
}
command += &format!(" --bind '{}' /tmp/sandbox/wine", wine_dir.as_ref());
command += &format!(" --bind '{}' /tmp/sandbox/prefix", prefix_dir.as_ref());
command += &format!(" --bind '{}' /tmp/sandbox/game", game_dir.as_ref());
command.push_str(" --chdir /");
command.push_str(" --die-with-parent");

View file

@ -0,0 +1,57 @@
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue;
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Mounts {
/// Bind original directory into the sandbox in read-only state
pub read_only: HashMap<String, String>,
/// Bind original directory into the sandbox with writing access
pub bind: HashMap<String, String>
}
impl From<&JsonValue> for Mounts {
fn from(value: &JsonValue) -> Self {
let default = Self::default();
Self {
read_only: match value.get("read_only") {
Some(value) => match value.as_object() {
Some(values) => {
let mut vars = HashMap::new();
for (name, value) in values {
if let Some(value) = value.as_str() {
vars.insert(name.clone(), value.to_string());
}
}
vars
},
None => default.read_only
},
None => default.read_only
},
bind: match value.get("bind") {
Some(value) => match value.as_object() {
Some(values) => {
let mut vars = HashMap::new();
for (name, value) in values {
if let Some(value) = value.as_str() {
vars.insert(name.clone(), value.to_string());
}
}
vars
},
None => default.bind
},
None => default.bind
}
}
}
}