From 597252a948305888329044a4db3904681a9cc7ce Mon Sep 17 00:00:00 2001 From: appare45 Date: Fri, 28 Nov 2025 11:58:30 +0900 Subject: [PATCH 1/6] from scratch --- Cargo.lock | 509 +------------------------------------------ Cargo.toml | 10 +- src/config_parser.rs | 35 --- src/container.rs | 65 ------ src/hostname.rs | 21 -- src/lib.rs | 6 - src/main.rs | 37 +--- src/mounts.rs | 85 -------- src/process.rs | 47 ---- src/root.rs | 96 -------- 10 files changed, 3 insertions(+), 908 deletions(-) delete mode 100644 src/config_parser.rs delete mode 100644 src/container.rs delete mode 100644 src/hostname.rs delete mode 100644 src/lib.rs delete mode 100644 src/mounts.rs delete mode 100644 src/process.rs delete mode 100644 src/root.rs diff --git a/Cargo.lock b/Cargo.lock index fe5c281..fe2907d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,514 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon 2.1.0", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstream" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon 3.0.4", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" - -[[package]] -name = "anstyle-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" -dependencies = [ - "anstream 0.5.0", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "env_filter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" -dependencies = [ - "anstream 0.6.15", - "anstyle", - "env_filter", - "humantime", - "log", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", - "memoffset", - "pin-utils", -] - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "serde" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" -dependencies = [ - "itoa", - "ryu", - "serde", -] +version = 4 [[package]] name = "socker" version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "env_logger", - "libc", - "log", - "nix", - "serde", - "serde_json", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "2.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index cffb060..4037c3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,8 @@ [package] name = "socker" version = "0.1.0" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = {version = "4.0", features = ["derive"]} -serde = { version = "1.0", features = ["derive"] } -serde_json = {version = "1.0.104"} -libc = "0.2.158" -nix = { version = "0.26.1", features=["process", "sched", "fs", "mount"]} -anyhow = "1.0.75" -log = "0.4.22" -env_logger = "0.11.5" diff --git a/src/config_parser.rs b/src/config_parser.rs deleted file mode 100644 index f54245e..0000000 --- a/src/config_parser.rs +++ /dev/null @@ -1,35 +0,0 @@ -use anyhow::{Context, Result}; -use serde::Deserialize; - -use crate::hostname::Hostname; -use crate::mounts::Mounts; -use crate::process::Process; -use crate::root::Root; - -#[derive(Deserialize)] -pub struct Config { - #[serde(rename = "ociVersion")] - pub oci_version: String, - pub root: Option, - pub process: Option, - pub hostname: Option, - pub mounts: Option>, -} - -impl TryFrom<&str> for Config { - type Error = anyhow::Error; - - fn try_from(value: &str) -> Result { - let config: Config = serde_json::from_str(value).context("Failed to parse config file")?; - Ok(config) - } -} - -#[test] -fn parser() { - let data = r#"{ - "ociVersion": "1.0.0" - }"#; - let config = Config::try_from(data).unwrap(); - assert_eq!(config.oci_version, "1.0.0"); -} diff --git a/src/container.rs b/src/container.rs deleted file mode 100644 index ddc33ff..0000000 --- a/src/container.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::config_parser::Config; -use anyhow::{bail, Result}; -use log::info; -use nix::{ - sys::wait::waitpid, - unistd::{fork, write, ForkResult, Pid}, -}; - -// not implemented all variantes -enum ContainerStatus { - Created, - Running, -} - -// not implemented all variantes -pub struct Container { - status: ContainerStatus, - config: Config, - pid: Option, -} - -pub trait ContainerTask { - fn run(&self) -> Result<()>; -} - -impl Container { - pub fn new(config: Config) -> Self { - Container { - status: ContainerStatus::Created, - pid: None, - config, - } - } - - pub fn run(&mut self) -> Result<()> { - self.status = ContainerStatus::Running; - match unsafe { fork() } { - Ok(ForkResult::Parent { child, .. }) => { - info!("Container has been started with pid: {}", child); - self.pid = Some(child); - waitpid(child, None).unwrap(); - Ok(()) - } - Ok(ForkResult::Child) => { - write(0, "I'm a container \n".as_bytes()).ok(); - if let Some(ref root) = self.config.root { - root.run()?; - } - if let Some(hostname) = &self.config.hostname { - hostname.run()?; - } - if let Some(mounts) = &self.config.mounts { - for mount in mounts { - mount.run()?; - } - } - if let Some(process) = &self.config.process { - process.run()?; - } - Ok(()) - } - Err(_) => bail!("Failed to fork"), - } - } -} diff --git a/src/hostname.rs b/src/hostname.rs deleted file mode 100644 index 0190ea2..0000000 --- a/src/hostname.rs +++ /dev/null @@ -1,21 +0,0 @@ -use anyhow::{Context, Ok, Result}; - -use nix::{ - sched::{unshare, CloneFlags}, - unistd::sethostname, -}; -use serde::Deserialize; - -use crate::container::ContainerTask; - -#[derive(Deserialize)] -pub struct Hostname(String); - -impl ContainerTask for Hostname { - fn run(&self) -> Result<()> { - unshare(CloneFlags::CLONE_NEWUTS) - .context("Failed to unshare UTS for hostname separation")?; - sethostname(&self.0)?; - Ok(()) - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 0ff6751..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod config_parser; -pub mod container; -pub mod hostname; -pub mod mounts; -pub mod process; -pub mod root; diff --git a/src/main.rs b/src/main.rs index f8d0235..e7a11a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,38 +1,3 @@ -use anyhow::{ensure, Result}; -use clap::Parser; -use std::env; - -use socker::{config_parser::Config, container::Container}; -use std::path::Path; - -/// Simple program to greet a person -#[derive(Parser, Debug)] -#[command(version, about, long_about = None, author="appare45")] -struct Args { - /// The target of config file - name: String, -} - -fn run() -> Result<()> { - let args = Args::parse(); - let config_path = Path::new(&args.name); - ensure!(config_path.exists(), "Config file not found"); - let config_data = std::fs::read_to_string(config_path)?; - let config = Config::try_from(config_data.as_str())?; - let mut container = Container::new(config); - container.run()?; - Ok(()) -} - fn main() { - env::set_var("RUST_LOG", "info"); - env_logger::init(); - #[cfg(not(unix))] - panic!("This program only runs on Unix systems"); - match run() { - Ok(_) => {} - Err(e) => { - log::error!("{:?}", e); - } - } + println!("Hello, world!"); } diff --git a/src/mounts.rs b/src/mounts.rs deleted file mode 100644 index 223de38..0000000 --- a/src/mounts.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::path::{Path, PathBuf}; - -use anyhow::{Context, Result}; -use nix::mount::{mount, MsFlags}; -use serde::Deserialize; - -use crate::container::ContainerTask; - -#[derive(Deserialize)] -pub struct Mounts { - destination: String, - source: Option, - pub options: Option>, - #[serde(rename = "type")] - pub fs_type: Option, -} - -impl Mounts { - pub fn source(&self) -> Option<&Path> { - self.source.as_ref().map(|e| Path::new(e).as_ref()) - } - pub fn destination(&self) -> PathBuf { - PathBuf::from(&self.destination) - } - pub fn fs_type(&self) -> Option<&str> { - self.fs_type.as_deref() - } - pub fn options(&self) -> MsFlags { - let mut flags = MsFlags::empty(); - if let Some(options) = &self.options { - for option in options { - match option.as_str() { - "bind" => flags |= MsFlags::MS_BIND, - "rbind" => flags |= MsFlags::MS_BIND | MsFlags::MS_REC, - "ro" => flags |= MsFlags::MS_RDONLY, - "rro" => flags |= MsFlags::MS_RDONLY, - "nosuid" => flags |= MsFlags::MS_NOSUID, - "rnosuid" => flags |= MsFlags::MS_NOSUID | MsFlags::MS_REC, - "nodev" => flags |= MsFlags::MS_NODEV, - "noexec" => flags |= MsFlags::MS_NOEXEC, - "rnoexec" => flags |= MsFlags::MS_NOEXEC | MsFlags::MS_REC, - "sync" => flags |= MsFlags::MS_SYNCHRONOUS, - "remount" => flags |= MsFlags::MS_REMOUNT, - "dirsync" => flags |= MsFlags::MS_DIRSYNC, - "noatime" => flags |= MsFlags::MS_NOATIME, - "rnoatime" => flags |= MsFlags::MS_NOATIME | MsFlags::MS_REC, - "unbundable" => flags |= MsFlags::MS_UNBINDABLE, - "runbindable" => flags |= MsFlags::MS_UNBINDABLE | MsFlags::MS_REC, - "private" => flags |= MsFlags::MS_PRIVATE, - "rprivate" => flags |= MsFlags::MS_PRIVATE | MsFlags::MS_REC, - "slave" => flags |= MsFlags::MS_SLAVE, - "rslave" => flags |= MsFlags::MS_SLAVE | MsFlags::MS_REC, - "shared" => flags |= MsFlags::MS_SHARED, - "rshared" => flags |= MsFlags::MS_SHARED | MsFlags::MS_REC, - "iversion" => flags |= MsFlags::MS_I_VERSION, - "strictatime" => flags |= MsFlags::MS_STRICTATIME, - "rstictatime" => flags |= MsFlags::MS_STRICTATIME | MsFlags::MS_REC, - "lazytime" => flags |= MsFlags::MS_LAZYTIME, - "nodiratime" => flags |= MsFlags::MS_NODIRATIME, - _ => (), - } - } - } - flags - } -} - -impl ContainerTask for Mounts { - fn run(&self) -> Result<()> { - let source = self.source(); - let destination = self.destination(); - mount::( - source, - &destination, - self.fs_type(), - self.options(), - None, - ) - .context(format!( - "Failed to mount to {}", - destination.as_path().display() - ))?; - Ok(()) - } -} diff --git a/src/process.rs b/src/process.rs deleted file mode 100644 index 7e86f08..0000000 --- a/src/process.rs +++ /dev/null @@ -1,47 +0,0 @@ -use anyhow::{Context, Ok, Result}; -use nix::unistd::execvpe; -use serde::Deserialize; -use std::ffi::CStr; - -use crate::container::ContainerTask; - -// Terminal is not supported -#[derive(Deserialize, Clone)] -pub struct Process { - pub args: Option>, - pub env: Option>, - pub cwd: String, -} - -impl Process { - fn get_cmd(&self) -> &CStr { - match self.args { - Some(ref args) => unsafe { CStr::from_ptr(args[0].as_ptr() as *const i8) }, - None => unsafe { CStr::from_ptr(self.cwd.as_ptr() as *const i8) }, - } - } - fn get_args(&self) -> Vec<&CStr> { - self.args.clone().unwrap_or(Vec::new())[1..] - .iter() - .map(|s| unsafe { CStr::from_ptr(s.as_ptr() as *const i8) }) - .collect::>() - } - fn get_env(&self) -> Vec<&CStr> { - self.env - .clone() - .unwrap_or(Vec::new()) - .iter() - .map(|s| unsafe { CStr::from_ptr(s.as_ptr() as *const i8) }) - .collect::>() - } -} - -impl ContainerTask for Process { - fn run(&self) -> Result<()> { - let cwd = self.get_cmd(); - let args = self.get_args(); - let env = self.get_env(); - execvpe(cwd, args[..].as_ref(), env[..].as_ref()).context("Failed to run process")?; - Ok(()) - } -} diff --git a/src/root.rs b/src/root.rs deleted file mode 100644 index 9d9c82b..0000000 --- a/src/root.rs +++ /dev/null @@ -1,96 +0,0 @@ -use anyhow::{ensure, Context, Result}; -use log::debug; -use nix::{ - mount::{mount, umount2, MntFlags, MsFlags}, - sched::{unshare, CloneFlags}, - unistd::{chdir, pivot_root}, -}; -use serde::Deserialize; -use std::{ - env::temp_dir, - fs::{create_dir, remove_dir, remove_dir_all}, - path::{Path, PathBuf}, -}; - -use crate::container::ContainerTask; - -#[derive(Deserialize)] -pub struct Root { - pub path: String, - pub readonly: bool, -} - -impl Root { - fn tmp_path(&self) -> Box { - Box::new(temp_dir().join(Path::new(&self.path))) - } - fn mount(&self) -> Result<()> { - debug!("Mounting rootfs"); - let root_path = Path::new(&self.path); - ensure!(root_path.exists(), "Rootfs path not found"); - let tmp_path = self.tmp_path(); - if tmp_path.exists() { - debug!("Removing old tmp dir: {:?}", tmp_path); - remove_dir_all(tmp_path.to_path_buf()).context("Removing old tmp dir failed")?; - } - debug!("Creating new tmpfs: {:?}", tmp_path); - create_dir(tmp_path.to_path_buf()).context("Creating temp dir for mounting root failed")?; - debug!("Mounting {} to {}", root_path.display(), tmp_path.display()); - mount::( - Some("none"), - "/", - None, - MsFlags::MS_PRIVATE | MsFlags::MS_REC, - None, - ) - .context("Failed to make rootfs private")?; - mount::( - Some(root_path), - &tmp_path, - None, - if self.readonly { - MsFlags::MS_BIND | MsFlags::MS_REC | MsFlags::MS_RDONLY - } else { - MsFlags::MS_BIND | MsFlags::MS_REC - }, - None, - ) - .context("Root dir mount failed")?; - Ok(()) - } - pub fn pivot(&self) -> Result<()> { - debug!("Root service has been started"); - self.mount()?; - - chdir(&self.tmp_path().to_path_buf()).context("Failed to change root dir")?; - const OLD_ROOT: &str = "old_root"; - let old_root = self.tmp_path().join(OLD_ROOT); - if !old_root.exists() { - create_dir(&old_root).context("Failed to create old root dir")?; - } - unshare(CloneFlags::CLONE_NEWNS).context("Failed to unshare")?; - pivot_root::(&self.tmp_path(), &old_root) - .context("Failed to pivot root")?; - umount2(OLD_ROOT, MntFlags::MNT_DETACH).context("Failed to unmount old root")?; - remove_dir(OLD_ROOT).context("Failed to remove old root dir")?; - Ok(()) - } -} - -impl ContainerTask for Root { - fn run(&self) -> Result<()> { - self.pivot()?; - Ok(()) - } -} - -impl Drop for Root { - fn drop(&mut self) { - if self.tmp_path().exists() { - umount2(&self.tmp_path().to_path_buf(), MntFlags::MNT_DETACH) - .expect("Failed to unmount rootfs"); - remove_dir_all(self.tmp_path().to_path_buf()).expect("Failed to remove tmp dir"); - } - debug!("Root service has been stopped"); - } -} From 255405cd2e6f6d98cdeeba0bb885dd250e130bc4 Mon Sep 17 00:00:00 2001 From: appare45 Date: Fri, 28 Nov 2025 11:58:30 +0900 Subject: [PATCH 2/6] namespace separation from scratch --- Cargo.lock | 40 +++++++++++++++++++++++++++ Cargo.toml | 4 +-- src/lib.rs | 2 ++ src/main.rs | 16 +++++++++++ src/namespace.rs | 30 ++++++++++++++++++++ src/namespace/flags.rs | 63 ++++++++++++++++++++++++++++++++++++++++++ src/process.rs | 33 ++++++++++++++++++++++ 7 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/namespace.rs create mode 100644 src/namespace/flags.rs create mode 100644 src/process.rs diff --git a/Cargo.lock b/Cargo.lock index fe2907d..5cdc2e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,46 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "socker" version = "0.1.0" +dependencies = [ + "bitflags", + "nix", +] diff --git a/Cargo.toml b/Cargo.toml index 4037c3c..c617efb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,6 @@ name = "socker" version = "0.1.0" edition = "2024" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +bitflags = "2.4.2" +nix = { version = "0.30.1", features = ["sched"] } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ed67d52 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod namespace; +pub mod process; diff --git a/src/main.rs b/src/main.rs index e7a11a9..d589af8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,19 @@ +use socker::{namespace::flags::NamespaceFlags, process::clone}; + +fn child_fn() { + let pid = nix::unistd::getpid(); + println!("In child process with PID: {}", pid); +} + fn main() { println!("Hello, world!"); + let flags = socker::namespace::Namespace::new(NamespaceFlags::PID); + match clone(child_fn, flags.proc_clone_flags()) { + Ok(child_pid) => { + println!("Spawned child process with PID: {}", child_pid); + } + Err(e) => { + eprintln!("Failed to clone process: {}", e); + } + } } diff --git a/src/namespace.rs b/src/namespace.rs new file mode 100644 index 0000000..93962cf --- /dev/null +++ b/src/namespace.rs @@ -0,0 +1,30 @@ +use flags::NamespaceFlags; + +pub mod flags; + +#[derive(Clone, Default)] +pub struct Namespace { + flags: NamespaceFlags, +} + +impl Namespace { + pub fn new(flags: NamespaceFlags) -> Self { + Namespace { flags } + } + + pub fn has_flag(&self, flag: NamespaceFlags) -> bool { + self.flags.contains(flag) + } + + pub fn add_flag(&mut self, flag: NamespaceFlags) { + self.flags.insert(flag); + } + + pub fn remove_flag(&mut self, flag: NamespaceFlags) { + self.flags.remove(flag); + } + + pub fn proc_clone_flags(&self) -> nix::sched::CloneFlags { + self.flags.to_clone_flag() + } +} diff --git a/src/namespace/flags.rs b/src/namespace/flags.rs new file mode 100644 index 0000000..a1c83f6 --- /dev/null +++ b/src/namespace/flags.rs @@ -0,0 +1,63 @@ +use bitflags::bitflags; +use nix::sched::CloneFlags; + +bitflags! { + #[derive(Default, Clone)] + pub struct NamespaceFlags: u32 { + const CGROUP = 0b00000001; + const IPC = 0b00000010; + const MNT = 0b00000100; + const NET = 0b00001000; + const PID = 0b00010000; + const USER = 0b00100000; + const UTS = 0b01000000; + } +} + +impl NamespaceFlags { + pub fn to_clone_flag(&self) -> CloneFlags { + let mut c_flag = CloneFlags::empty(); + if self.contains(NamespaceFlags::CGROUP) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWCGROUP; + } + if self.contains(NamespaceFlags::IPC) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWIPC; + } + if self.contains(NamespaceFlags::MNT) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWNS; + } + if self.contains(NamespaceFlags::NET) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWNET; + } + if self.contains(NamespaceFlags::PID) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWPID; + } + if self.contains(NamespaceFlags::USER) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWUSER; + } + if self.contains(NamespaceFlags::UTS) { + c_flag |= nix::sched::CloneFlags::CLONE_NEWUTS; + } + c_flag + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_to_clone_flag_combined() { + let flags = NamespaceFlags::CGROUP | NamespaceFlags::NET | NamespaceFlags::USER; + let expected = nix::sched::CloneFlags::CLONE_NEWCGROUP + | nix::sched::CloneFlags::CLONE_NEWNET + | nix::sched::CloneFlags::CLONE_NEWUSER; + assert_eq!(flags.to_clone_flag(), expected); + } + + #[test] + fn test_to_clone_flag_none() { + let flags = NamespaceFlags::empty(); + assert_eq!(flags.to_clone_flag(), CloneFlags::empty()); + } +} diff --git a/src/process.rs b/src/process.rs new file mode 100644 index 0000000..790cf14 --- /dev/null +++ b/src/process.rs @@ -0,0 +1,33 @@ +use nix::unistd::Pid; + +pub struct Process { + pid: u32, + namespace: crate::namespace::Namespace, +} + +impl Process { + pub fn new(pid: u32, namespace: crate::namespace::Namespace) -> Self { + Self { pid, namespace } + } + + pub fn pid(&self) -> u32 { + self.pid + } + + pub fn namespace(&self) -> &crate::namespace::Namespace { + &self.namespace + } +} + +const CHILD_STACK_SIZE: usize = 1024 * 1024; + +// FlagはDTOで共有したほうが良いのだと思うが、一旦こうしておく +pub fn clone(child_fn: fn(), flags: nix::sched::CloneFlags) -> Result { + let stack: &mut [u8; CHILD_STACK_SIZE] = &mut [0; CHILD_STACK_SIZE]; + let cb = Box::new(move || { + child_fn(); + 0 + }); + let raw = Box::into_raw(cb); + Ok(unsafe { nix::sched::clone(nix::sched::CloneCb::from_raw(raw), stack, flags, None) }?) +} From 0fd65c27775235b7c4d757986b9703de93f80e0f Mon Sep 17 00:00:00 2001 From: appare45 Date: Fri, 28 Nov 2025 11:58:30 +0900 Subject: [PATCH 3/6] inter proc communication with fd --- Cargo.toml | 2 +- src/lib.rs | 1 - src/main.rs | 45 +++++++++++++++++++++++++++++++++++++++++---- src/process.rs | 33 --------------------------------- 4 files changed, 42 insertions(+), 39 deletions(-) delete mode 100644 src/process.rs diff --git a/Cargo.toml b/Cargo.toml index c617efb..3ec6071 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,4 @@ edition = "2024" [dependencies] bitflags = "2.4.2" -nix = { version = "0.30.1", features = ["sched"] } +nix = { version = "0.30.1", features = ["fs", "sched"] } diff --git a/src/lib.rs b/src/lib.rs index ed67d52..a0cb07f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1 @@ pub mod namespace; -pub mod process; diff --git a/src/main.rs b/src/main.rs index d589af8..5988370 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,56 @@ -use socker::{namespace::flags::NamespaceFlags, process::clone}; +use std::{ + io::{self, PipeReader, Read, Write}, + os::fd::{AsRawFd, FromRawFd}, +}; -fn child_fn() { +use nix::{libc::SIGCHLD, unistd::close}; +use socker::namespace::flags::NamespaceFlags; + +fn child_fn(readfd: i32, writefd: i32) { let pid = nix::unistd::getpid(); println!("In child process with PID: {}", pid); + let mut reader = unsafe { PipeReader::from_raw_fd(readfd) }; + close(writefd).expect("Failed to close write end of pipe in child"); + let mut read = [0_u8; 128]; + reader.read(&mut read).unwrap(); + println!("Read: {}", String::from_utf8_lossy(&read)); } +const CHILD_STACK_SIZE: usize = 1024 * 1024; fn main() { println!("Hello, world!"); - let flags = socker::namespace::Namespace::new(NamespaceFlags::PID); - match clone(child_fn, flags.proc_clone_flags()) { + let flags = socker::namespace::Namespace::new(NamespaceFlags::empty()); + let (reader, mut writer) = io::pipe().expect("Failed to create pipe"); + let stack: &mut [u8; CHILD_STACK_SIZE] = &mut [0; CHILD_STACK_SIZE]; + let pid = match unsafe { + nix::sched::clone( + Box::new(|| { + child_fn(reader.as_raw_fd(), writer.as_raw_fd()); + 0 + }), + stack, + flags.proc_clone_flags(), + Some(SIGCHLD), + ) + } { Ok(child_pid) => { println!("Spawned child process with PID: {}", child_pid); + child_pid } Err(e) => { eprintln!("Failed to clone process: {}", e); + return; + } + }; + writer + .write_all(b"Hello from parent process!\n") + .expect("Failed to write to pipe"); + match nix::sys::wait::waitpid(pid, None) { + Ok(status) => { + println!("Child process {} exited with status: {:?}", pid, status); + } + Err(e) => { + eprintln!("Failed to wait for child process {}: {}", pid, e); } } } diff --git a/src/process.rs b/src/process.rs deleted file mode 100644 index 790cf14..0000000 --- a/src/process.rs +++ /dev/null @@ -1,33 +0,0 @@ -use nix::unistd::Pid; - -pub struct Process { - pid: u32, - namespace: crate::namespace::Namespace, -} - -impl Process { - pub fn new(pid: u32, namespace: crate::namespace::Namespace) -> Self { - Self { pid, namespace } - } - - pub fn pid(&self) -> u32 { - self.pid - } - - pub fn namespace(&self) -> &crate::namespace::Namespace { - &self.namespace - } -} - -const CHILD_STACK_SIZE: usize = 1024 * 1024; - -// FlagはDTOで共有したほうが良いのだと思うが、一旦こうしておく -pub fn clone(child_fn: fn(), flags: nix::sched::CloneFlags) -> Result { - let stack: &mut [u8; CHILD_STACK_SIZE] = &mut [0; CHILD_STACK_SIZE]; - let cb = Box::new(move || { - child_fn(); - 0 - }); - let raw = Box::into_raw(cb); - Ok(unsafe { nix::sched::clone(nix::sched::CloneCb::from_raw(raw), stack, flags, None) }?) -} From bb655863a9543dea9ea614c94cb62a16aff269ad Mon Sep 17 00:00:00 2001 From: appare45 Date: Fri, 28 Nov 2025 11:58:30 +0900 Subject: [PATCH 4/6] set user ns appare45@lima-devenv:~/ghq/github.com/appare45/socker$ cargo run Compiling socker v0.1.0 (/home/appare45.linux/ghq/github.com/appare45/socker) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.55s Running `target/debug/socker` Hello, world! Spawned child process with PID: 51395 In child process with PID: 1 Child before mapping UID: 65534, GID: 65534 Parent UID: 501, GID: 1000 Writing to pipe... Read: Hello from parent process! Child UID: 0, GID: 0 Child process 51395 exited with status: Exited(Pid(51395), 0) --- Cargo.toml | 2 +- src/main.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ec6071..dff744f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,4 @@ edition = "2024" [dependencies] bitflags = "2.4.2" -nix = { version = "0.30.1", features = ["fs", "sched"] } +nix = { version = "0.30.1", features = ["fs", "sched", "user"] } diff --git a/src/main.rs b/src/main.rs index 5988370..c695a48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ use std::{ + fs, io::{self, PipeReader, Read, Write}, os::fd::{AsRawFd, FromRawFd}, }; -use nix::{libc::SIGCHLD, unistd::close}; +use nix::{ + libc::SIGCHLD, + unistd::{Gid, Uid, close, setgid, setuid}, +}; use socker::namespace::flags::NamespaceFlags; fn child_fn(readfd: i32, writefd: i32) { @@ -11,15 +15,23 @@ fn child_fn(readfd: i32, writefd: i32) { println!("In child process with PID: {}", pid); let mut reader = unsafe { PipeReader::from_raw_fd(readfd) }; close(writefd).expect("Failed to close write end of pipe in child"); + let uid = nix::unistd::getuid(); + let gid = nix::unistd::getgid(); + println!("Child before mapping UID: {}, GID: {}", uid, gid); let mut read = [0_u8; 128]; reader.read(&mut read).unwrap(); println!("Read: {}", String::from_utf8_lossy(&read)); + setuid(Uid::from_raw(0)).expect("Failed to set UID to 0"); + setgid(Gid::from_raw(0)).expect("Failed to set GID to 0"); + let uid = nix::unistd::getuid(); + let gid = nix::unistd::getgid(); + println!("Child UID: {}, GID: {}", uid, gid); } const CHILD_STACK_SIZE: usize = 1024 * 1024; fn main() { println!("Hello, world!"); - let flags = socker::namespace::Namespace::new(NamespaceFlags::empty()); + let flags = socker::namespace::Namespace::new(NamespaceFlags::USER | NamespaceFlags::PID); let (reader, mut writer) = io::pipe().expect("Failed to create pipe"); let stack: &mut [u8; CHILD_STACK_SIZE] = &mut [0; CHILD_STACK_SIZE]; let pid = match unsafe { @@ -42,6 +54,24 @@ fn main() { return; } }; + let uid = nix::unistd::getuid(); + let gid = nix::unistd::getgid(); + println!("Parent UID: {}, GID: {}", uid, gid); + fs::write(format!("/proc/{}/setgroups", pid), "deny\n").expect("Failed to write setgroups"); + // GID map + fs::write( + format!("/proc/{}/gid_map", pid), + format!("0 {} 1\n", gid.as_raw()), + ) + .expect("Failed to write gid_map"); + // UID map + fs::write( + format!("/proc/{}/uid_map", pid), + format!("0 {} 1\n", uid.as_raw()), + ) + .expect("Failed to write uid_map"); + + println!("Writing to pipe..."); writer .write_all(b"Hello from parent process!\n") .expect("Failed to write to pipe"); From f3273f182d9093a49bec2f45822ab7f2c8570a60 Mon Sep 17 00:00:00 2001 From: appare45 Date: Fri, 28 Nov 2025 11:58:30 +0900 Subject: [PATCH 5/6] introduced ctx --- src/main.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index c695a48..bb76c6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,19 +10,27 @@ use nix::{ }; use socker::namespace::flags::NamespaceFlags; -fn child_fn(readfd: i32, writefd: i32) { +#[derive(Clone, Copy)] +struct Context { + readerfd: i32, + writerfd: i32, + uid: Uid, + gid: Gid, +} + +fn child_fn(ctx: Context) { let pid = nix::unistd::getpid(); println!("In child process with PID: {}", pid); - let mut reader = unsafe { PipeReader::from_raw_fd(readfd) }; - close(writefd).expect("Failed to close write end of pipe in child"); + let mut reader = unsafe { PipeReader::from_raw_fd(ctx.readerfd) }; + close(ctx.writerfd).expect("Failed to close write end of pipe in child"); let uid = nix::unistd::getuid(); let gid = nix::unistd::getgid(); println!("Child before mapping UID: {}, GID: {}", uid, gid); let mut read = [0_u8; 128]; reader.read(&mut read).unwrap(); println!("Read: {}", String::from_utf8_lossy(&read)); - setuid(Uid::from_raw(0)).expect("Failed to set UID to 0"); - setgid(Gid::from_raw(0)).expect("Failed to set GID to 0"); + setuid(ctx.uid).expect("Failed to set UID to 0"); + setgid(ctx.gid).expect("Failed to set GID to 0"); let uid = nix::unistd::getuid(); let gid = nix::unistd::getgid(); println!("Child UID: {}, GID: {}", uid, gid); @@ -34,10 +42,16 @@ fn main() { let flags = socker::namespace::Namespace::new(NamespaceFlags::USER | NamespaceFlags::PID); let (reader, mut writer) = io::pipe().expect("Failed to create pipe"); let stack: &mut [u8; CHILD_STACK_SIZE] = &mut [0; CHILD_STACK_SIZE]; + let ctx = Context { + readerfd: reader.as_raw_fd(), + writerfd: writer.as_raw_fd(), + uid: Uid::from_raw(0), + gid: Gid::from_raw(0), + }; let pid = match unsafe { nix::sched::clone( - Box::new(|| { - child_fn(reader.as_raw_fd(), writer.as_raw_fd()); + Box::new(move || { + child_fn(ctx); 0 }), stack, From 9cc893ec9245a39a0823706b201a5079256da3cf Mon Sep 17 00:00:00 2001 From: appare45 Date: Fri, 28 Nov 2025 11:56:42 +0900 Subject: [PATCH 6/6] pivot root --- Cargo.toml | 2 +- src/main.rs | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dff744f..b8061df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,4 @@ edition = "2024" [dependencies] bitflags = "2.4.2" -nix = { version = "0.30.1", features = ["fs", "sched", "user"] } +nix = { version = "0.30.1", features = ["fs", "mount", "sched", "user"] } diff --git a/src/main.rs b/src/main.rs index bb76c6d..5d7017f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,20 +2,22 @@ use std::{ fs, io::{self, PipeReader, Read, Write}, os::fd::{AsRawFd, FromRawFd}, + path::{Path, PathBuf}, }; use nix::{ libc::SIGCHLD, - unistd::{Gid, Uid, close, setgid, setuid}, + mount::{MntFlags, MsFlags, mount, umount2}, + unistd::{Gid, Uid, close, execve, pivot_root, setgid, setuid}, }; use socker::namespace::flags::NamespaceFlags; -#[derive(Clone, Copy)] struct Context { readerfd: i32, writerfd: i32, uid: Uid, gid: Gid, + rootfs: Box, } fn child_fn(ctx: Context) { @@ -34,24 +36,46 @@ fn child_fn(ctx: Context) { let uid = nix::unistd::getuid(); let gid = nix::unistd::getgid(); println!("Child UID: {}, GID: {}", uid, gid); + if !ctx.rootfs.exists() { + panic!("New root directory does not exist"); + } + mount::(None, "/", None, MsFlags::MS_REC | MsFlags::MS_PRIVATE, None) + .expect("Failed to remount / as private"); + mount::(Some(&ctx.rootfs), &ctx.rootfs, None, MsFlags::MS_BIND, None) + .expect("Failed to bind mount"); + let old_path = "./old"; + let put_old = ctx.rootfs.join(old_path); + if !put_old.exists() { + fs::create_dir(&put_old).expect("Failed to create old directory in new root"); + } + pivot_root::(&ctx.rootfs, &put_old).expect("Failed to pivot_root"); + std::env::set_current_dir("/").expect("Failed to chdir to /"); + umount2(old_path, MntFlags::MNT_DETACH).expect("Failed to unmount /old"); + fs::remove_dir(old_path).expect("Failed to remove /old"); + let envs: [&std::ffi::CStr; 0] = []; + execve(&c"/bin/sh", &[c"/bin/sh"], &envs).expect("Failed to execve"); + panic!("Failed to execve"); } const CHILD_STACK_SIZE: usize = 1024 * 1024; fn main() { println!("Hello, world!"); - let flags = socker::namespace::Namespace::new(NamespaceFlags::USER | NamespaceFlags::PID); + let flags = socker::namespace::Namespace::new( + NamespaceFlags::USER | NamespaceFlags::PID | NamespaceFlags::MNT, + ); let (reader, mut writer) = io::pipe().expect("Failed to create pipe"); let stack: &mut [u8; CHILD_STACK_SIZE] = &mut [0; CHILD_STACK_SIZE]; - let ctx = Context { + let mut ctx = Some(Context { readerfd: reader.as_raw_fd(), writerfd: writer.as_raw_fd(), uid: Uid::from_raw(0), gid: Gid::from_raw(0), - }; + rootfs: Box::from(Path::new("./rootfs")), + }); let pid = match unsafe { nix::sched::clone( Box::new(move || { - child_fn(ctx); + child_fn(ctx.take().unwrap()); 0 }), stack,