diff --git a/Cargo.toml b/Cargo.toml index a9158b17..5d907238 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,27 +26,25 @@ edition = "2021" # Common dependencies for all crates [workspace.dependencies] async-trait = "0.1.89" -cgroups-rs = "0.4.0" -crossbeam = "0.8.1" -futures = "0.3.19" -libc = "0.2.112" -log = {version = "0.4.2", features=["kv_unstable"]} -nix = "0.30" -oci-spec = "0.7" -os_pipe = "1.1" -prctl = "1.0.0" -prost = "0.14" -prost-build = "0.14" -prost-types = "0.14" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -simple_logger = { version = "5.0", default-features = false } -tempfile = "3.6" +cgroups-rs = { version = "0.5", default-features = false } +crossbeam = { version = "0.8", default-features = false } +futures = { version = "0.3", default-features = false } +libc = { version = "0.2", default-features = false } +log = { version = "0.4", default-features = false } +nix = { version = "0.31", default-features = false } +oci-spec = { version = "0.9", default-features = false } +prost = { version = "0.14", default-features = false } +prost-build = { version = "0.14", default-features = false } +prost-types = { version = "0.14", default-features = false } +serde = { version = "1.0", default-features = false } +serde_json = { version = "1.0", default-features = false } +simple_logger = { version = "5.2", default-features = false } +tempfile = "3.25" thiserror = "2.0" -time = { version = "0.3.29", features = ["serde", "std", "formatting"] } -tokio = "1.26" -tonic = "0.14" +time = { version = "0.3", default-features = false } +tokio = { version = "1.49", default-features = false } +tonic = { version = "0.14", default-features = false } tonic-prost = "0.14" -tonic-prost-build = "0.14" -tower = "0.5" -uuid = { version = "1.0", features = ["v4"] } +tonic-prost-build = { version = "0.14", default-features = false } +tower = { version = "0.5", default-features = false } +uuid = { version = "1.21", default-features = false } diff --git a/clippy.toml b/clippy.toml index 64aceb7d..df8fb6c6 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -msrv = "1.66" +msrv = "1.91" diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 2d87e492..0c566a49 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -23,19 +23,19 @@ name = "version" path = "examples/version.rs" [dependencies] -hyper-util = "0.1.6" # https://github.com/hyperium/hyper/issues/3110 -prost.workspace = true -prost-types.workspace = true -tokio = { workspace = true, optional = true } -tonic.workspace = true +hyper-util = { version = "0.1.20", default-features = false, features = ["tokio"] } +prost = { workspace = true, features = ["derive", "std"] } +prost-types = { workspace = true, features = ["std"] } +tokio = { workspace = true, features = ["net"], optional = true } +tonic = { workspace = true, features = ["codegen", "channel"] } tonic-prost.workspace = true -tower = { workspace = true, optional = true } +tower = { workspace = true, features = ["util"], optional = true } [build-dependencies] tonic-prost-build.workspace = true [dev-dependencies] -tokio = { workspace = true, features = ["rt", "macros"]} +tokio = { workspace = true, features = ["rt", "macros", "net"] } [features] connect = ["tokio", "tower"] diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index 72a6c4e0..f9c199ce 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -35,6 +35,7 @@ pub mod types { /// Generated `google.rpc` types, containerd services typically use some of these types. pub mod google { + #[allow(rustdoc::broken_intra_doc_links)] pub mod rpc { tonic::include_proto!("google.rpc"); } diff --git a/crates/runc-shim/Cargo.toml b/crates/runc-shim/Cargo.toml index 1ff4dd4b..553db7c7 100644 --- a/crates/runc-shim/Cargo.toml +++ b/crates/runc-shim/Cargo.toml @@ -28,18 +28,17 @@ doc = false containerd-shim = { path = "../shim", version = "0.10.0", features = ["async"] } libc.workspace = true log.workspace = true -nix = { workspace = true, features = ["socket", "uio", "term"] } -oci-spec.workspace = true -prctl.workspace = true +nix = { workspace = true, features = ["socket", "uio", "term", "signal"] } +oci-spec = { workspace = true, features = ["runtime"] } runc = { path = "../runc", version = "0.3.0", features = ["async"] } -serde.workspace = true -serde_json.workspace = true -time.workspace = true -uuid.workspace = true +serde = { workspace = true, features = ["derive", "std"] } +serde_json = { workspace = true, features = ["std"] } +time = { workspace = true, features = ["std"] } +uuid = { workspace = true, features = ["v4"] } # Async dependencies async-trait.workspace = true -tokio = { workspace = true, features = ["full"] } -rustix = { version = "1", features = ["termios"] } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "process", "sync", "fs", "io-util", "net", "time", "signal"] } +rustix = { version = "1.1", default-features = false, features = ["std", "termios"] } [package.metadata.cargo-machete] ignored = ["libc"] @@ -47,4 +46,4 @@ ignored = ["libc"] [target.'cfg(target_os = "linux")'.dependencies] cgroups-rs.workspace = true nix = { workspace = true, features = ["event"] } -tokio-eventfd = "0.2.1" +tokio-eventfd = "0.2.2" diff --git a/crates/runc-shim/src/service.rs b/crates/runc-shim/src/service.rs index 84756d4b..f78f33b0 100644 --- a/crates/runc-shim/src/service.rs +++ b/crates/runc-shim/src/service.rs @@ -83,17 +83,17 @@ impl Shim for Service { // Our goal is to set thp disable = true on the shim side and then restore thp // disable before starting runc. So we only need to focus on the return value // of the function get_thp_disabled, which is Result. - let thp_disabled = match prctl::get_thp_disable() { - Ok(x) => { - // The return value of the function set_thp_disabled is Result<(), i32>, - // we don't care if the setting is successful, because even if the - // setting failed, we should not exit the shim process, therefore, - // there is no need to pay attention to the set_thp_disabled function's - // return value. - let _ = prctl::set_thp_disable(true); - x.to_string() + let thp_disabled = { + let ret = unsafe { libc::prctl(libc::PR_GET_THP_DISABLE, 0, 0, 0, 0) }; + if ret >= 0 { + let was_disabled = ret > 0; + // We don't care if the setting is successful, because even if the + // setting failed, we should not exit the shim process. + let _ = unsafe { libc::prctl(libc::PR_SET_THP_DISABLE, 1u64, 0, 0, 0) }; + was_disabled.to_string() + } else { + String::new() } - Err(_) => String::new(), }; let vars: Vec<(&str, &str)> = vec![("THP_DISABLED", thp_disabled.as_str())]; diff --git a/crates/runc/Cargo.toml b/crates/runc/Cargo.toml index cd8fd0a3..07e8d153 100644 --- a/crates/runc/Cargo.toml +++ b/crates/runc/Cargo.toml @@ -19,21 +19,18 @@ docs = [] libc.workspace = true log.workspace = true nix = { workspace = true, features = ["user", "fs"] } -oci-spec.workspace = true -path-absolutize = "3.0.11" -prctl.workspace = true -serde.workspace = true -serde_json.workspace = true +oci-spec = { workspace = true, features = ["runtime"] } +serde = { workspace = true, features = ["derive", "std"] } +serde_json = { workspace = true, features = ["std"] } tempfile.workspace = true thiserror.workspace = true -time.workspace = true -uuid.workspace = true -os_pipe.workspace = true +time = { workspace = true, features = ["serde", "std"] } +uuid = { workspace = true, features = ["v4"] } # Async dependencies async-trait = { workspace = true, optional = true } -tokio = { workspace = true, features = ["full"], optional = true } -tokio-pipe = { version = "0.2.10", optional = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "process", "sync", "fs", "io-util", "net", "time"], optional = true } +tokio-pipe = { version = "0.2.12", default-features = false, optional = true } [package.metadata.docs.rs] features = ["docs"] diff --git a/crates/runc/src/asynchronous/io.rs b/crates/runc/src/asynchronous/io.rs index 14110cd4..83cfd6a9 100644 --- a/crates/runc/src/asynchronous/io.rs +++ b/crates/runc/src/asynchronous/io.rs @@ -69,7 +69,9 @@ impl PipedIo { let rd = pipe.rd.try_clone()?; nix::unistd::fchown(rd, uid, gid)?; } else { - let wr = pipe.wr.try_clone()?; + let wr = pipe + .try_clone_wr() + .ok_or_else(|| std::io::Error::other("write end closed"))?; nix::unistd::fchown(wr, uid, gid)?; } Ok(Some(pipe)) diff --git a/crates/runc/src/asynchronous/mod.rs b/crates/runc/src/asynchronous/mod.rs index f627ea95..9165c2df 100644 --- a/crates/runc/src/asynchronous/mod.rs +++ b/crates/runc/src/asynchronous/mod.rs @@ -19,7 +19,6 @@ mod runc; use std::{fmt::Debug, io::Result, os::fd::AsRawFd}; use async_trait::async_trait; -use log::debug; pub use pipe::Pipe; pub use runc::{DefaultExecutor, Spawner}; use tokio::io::{AsyncRead, AsyncWrite}; @@ -57,10 +56,11 @@ pub struct PipedIo { impl Io for PipedIo { fn stdin(&self) -> Option> { self.stdin.as_ref().and_then(|pipe| { - let fd = pipe.wr.as_raw_fd(); - tokio_pipe::PipeWrite::from_raw_fd_checked(fd) - .map(|x| Box::new(x) as Box) - .ok() + pipe.wr_as_raw_fd().and_then(|fd| { + tokio_pipe::PipeWrite::from_raw_fd_checked(fd) + .map(|x| Box::new(x) as Box) + .ok() + }) }) } @@ -91,12 +91,16 @@ impl Io for PipedIo { } if let Some(p) = self.stdout.as_ref() { - let pw = p.wr.try_clone()?; + let pw = p + .try_clone_wr() + .ok_or_else(|| std::io::Error::other("write end closed"))?; cmd.stdout(pw); } if let Some(p) = self.stderr.as_ref() { - let pw = p.wr.try_clone()?; + let pw = p + .try_clone_wr() + .ok_or_else(|| std::io::Error::other("write end closed"))?; cmd.stdout(pw); } @@ -105,11 +109,11 @@ impl Io for PipedIo { async fn close_after_start(&self) { if let Some(p) = self.stdout.as_ref() { - nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stdout: {}", e)); + p.close_wr(); } if let Some(p) = self.stderr.as_ref() { - nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stderr: {}", e)); + p.close_wr(); } } } diff --git a/crates/runc/src/asynchronous/pipe.rs b/crates/runc/src/asynchronous/pipe.rs index e19710f3..1a1d1212 100644 --- a/crates/runc/src/asynchronous/pipe.rs +++ b/crates/runc/src/asynchronous/pipe.rs @@ -14,9 +14,10 @@ limitations under the License. */ -use std::os::unix::io::OwnedFd; - -use tokio::net::unix::pipe; +use std::{ + os::unix::io::{AsRawFd, OwnedFd, RawFd}, + sync::Mutex, +}; /// Struct to represent a pipe that can be used to transfer stdio inputs and outputs. /// @@ -25,15 +26,40 @@ use tokio::net::unix::pipe; #[derive(Debug)] pub struct Pipe { pub rd: OwnedFd, - pub wr: OwnedFd, + wr: Mutex>, } impl Pipe { pub fn new() -> std::io::Result { - let (tx, rx) = pipe::pipe()?; - let rd = rx.into_blocking_fd()?; - let wr = tx.into_blocking_fd()?; - Ok(Self { rd, wr }) + let (rd, wr) = std::io::pipe()?; + Ok(Self { + rd: OwnedFd::from(rd), + wr: Mutex::new(Some(OwnedFd::from(wr))), + }) + } + + /// Return the raw fd of the write end. Returns `None` if closed. + pub fn wr_as_raw_fd(&self) -> Option { + self.wr.lock().unwrap().as_ref().map(|w| w.as_raw_fd()) + } + + /// Clone the write end. Returns `None` if closed. + pub fn try_clone_wr(&self) -> Option { + self.wr + .lock() + .unwrap() + .as_ref() + .and_then(|w| w.try_clone().ok()) + } + + /// Close the write end by dropping it. No-op if already closed. + pub fn close_wr(&self) { + let _ = self.wr.lock().unwrap().take(); + } + + /// Take ownership of the write end. Returns `None` if already closed. + pub fn take_wr(&self) -> Option { + self.wr.lock().unwrap().take() } } @@ -41,28 +67,29 @@ impl Pipe { mod tests { use std::os::fd::IntoRawFd; - use tokio::io::{AsyncReadExt, AsyncWriteExt}; + use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::unix::pipe, + }; use super::*; #[tokio::test] async fn test_pipe_creation() { let pipe = Pipe::new().expect("Failed to create pipe"); + let wr = pipe.take_wr().unwrap(); assert!( pipe.rd.into_raw_fd() >= 0, "Read file descriptor is invalid" ); - assert!( - pipe.wr.into_raw_fd() >= 0, - "Write file descriptor is invalid" - ); + assert!(wr.into_raw_fd() >= 0, "Write file descriptor is invalid"); } #[tokio::test] async fn test_pipe_write_read() { let pipe = Pipe::new().expect("Failed to create pipe"); + let mut write_end = pipe::Sender::from_owned_fd(pipe.take_wr().unwrap()).unwrap(); let mut read_end = pipe::Receiver::from_owned_fd(pipe.rd).unwrap(); - let mut write_end = pipe::Sender::from_owned_fd(pipe.wr).unwrap(); let write_data = b"hello"; write_end @@ -85,8 +112,8 @@ mod tests { #[tokio::test] async fn test_pipe_async_write_read() { let pipe = Pipe::new().expect("Failed to create pipe"); + let mut write_end = pipe::Sender::from_owned_fd(pipe.take_wr().unwrap()).unwrap(); let mut read_end = pipe::Receiver::from_owned_fd(pipe.rd).unwrap(); - let mut write_end = pipe::Sender::from_owned_fd(pipe.wr).unwrap(); let write_data = b"hello"; tokio::spawn(async move { diff --git a/crates/runc/src/asynchronous/runc.rs b/crates/runc/src/asynchronous/runc.rs index 79b1fcd5..040cc110 100644 --- a/crates/runc/src/asynchronous/runc.rs +++ b/crates/runc/src/asynchronous/runc.rs @@ -57,9 +57,16 @@ impl Runc { #[cfg(target_os = "linux")] if let Ok(thp) = std::env::var("THP_DISABLED") { if let Ok(thp_disabled) = thp.parse::() { - if let Err(e) = prctl::set_thp_disable(thp_disabled) { - debug!("set_thp_disable err: {}", e); - }; + let ret = libc::prctl( + libc::PR_SET_THP_DISABLE, + if thp_disabled { 1u64 } else { 0u64 }, + 0, + 0, + 0, + ); + if ret < 0 { + debug!("set_thp_disable err: {}", std::io::Error::last_os_error()); + } } } Ok(()) diff --git a/crates/runc/src/synchronous/io.rs b/crates/runc/src/synchronous/io.rs index 1cc3a4a6..2f0878b9 100644 --- a/crates/runc/src/synchronous/io.rs +++ b/crates/runc/src/synchronous/io.rs @@ -74,7 +74,9 @@ impl PipedIo { let rd = pipe.rd.try_clone()?; nix::unistd::fchown(rd, uid, gid)?; } else { - let wr = pipe.wr.try_clone()?; + let wr = pipe + .try_clone_wr() + .ok_or_else(|| std::io::Error::other("write end closed"))?; nix::unistd::fchown(wr, uid, gid)?; } Ok(Some(pipe)) @@ -235,7 +237,7 @@ mod tests { buf[0] = 0xce; io.stdout .as_ref() - .map(|v| v.wr.try_clone().unwrap().write(&buf).unwrap()); + .map(|v| v.try_clone_wr().unwrap().write(&buf).unwrap()); buf[0] = 0x0; stdout.read_exact(&mut buf).unwrap(); assert_eq!(&buf, &[0xceu8]); @@ -244,7 +246,7 @@ mod tests { buf[0] = 0xa5; io.stderr .as_ref() - .map(|v| v.wr.try_clone().unwrap().write(&buf).unwrap()); + .map(|v| v.try_clone_wr().unwrap().write(&buf).unwrap()); buf[0] = 0x0; stderr.read_exact(&mut buf).unwrap(); assert_eq!(&buf, &[0xa5u8]); diff --git a/crates/runc/src/synchronous/mod.rs b/crates/runc/src/synchronous/mod.rs index c4cb7cce..15ace69e 100644 --- a/crates/runc/src/synchronous/mod.rs +++ b/crates/runc/src/synchronous/mod.rs @@ -19,10 +19,8 @@ mod runc; use std::{ fmt::Debug, io::{Read, Result, Write}, - os::fd::AsRawFd, }; -use log::debug; pub use pipe::Pipe; pub use runc::{DefaultExecutor, Spawner}; @@ -61,12 +59,10 @@ pub struct PipedIo { impl Io for PipedIo { fn stdin(&self) -> Option> { - self.stdin.as_ref().and_then(|pipe| { - pipe.wr - .try_clone() - .map(|x| Box::new(x) as Box) - .ok() - }) + self.stdin + .as_ref() + .and_then(|pipe| pipe.try_clone_wr()) + .map(|x| Box::new(x) as Box) } fn stdout(&self) -> Option> { @@ -95,12 +91,16 @@ impl Io for PipedIo { } if let Some(p) = self.stdout.as_ref() { - let pw = p.wr.try_clone()?; + let pw = p + .try_clone_wr() + .ok_or_else(|| std::io::Error::other("write end closed"))?; cmd.stdout(pw); } if let Some(p) = self.stderr.as_ref() { - let pw = p.wr.try_clone()?; + let pw = p + .try_clone_wr() + .ok_or_else(|| std::io::Error::other("write end closed"))?; cmd.stdout(pw); } @@ -109,11 +109,11 @@ impl Io for PipedIo { fn close_after_start(&self) { if let Some(p) = self.stdout.as_ref() { - nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stdout: {}", e)); + p.close_wr(); } if let Some(p) = self.stderr.as_ref() { - nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stderr: {}", e)); + p.close_wr(); } } } diff --git a/crates/runc/src/synchronous/pipe.rs b/crates/runc/src/synchronous/pipe.rs index 7c882160..dad104c9 100644 --- a/crates/runc/src/synchronous/pipe.rs +++ b/crates/runc/src/synchronous/pipe.rs @@ -14,17 +14,37 @@ limitations under the License. */ -use os_pipe::{pipe, PipeReader, PipeWriter}; +use std::{ + io::{PipeReader, PipeWriter}, + sync::Mutex, +}; #[derive(Debug)] pub struct Pipe { pub rd: PipeReader, - pub wr: PipeWriter, + wr: Mutex>, } impl Pipe { pub fn new() -> std::io::Result { - let (rd, wr) = pipe()?; - Ok(Self { rd, wr }) + let (rd, wr) = std::io::pipe()?; + Ok(Self { + rd, + wr: Mutex::new(Some(wr)), + }) + } + + /// Clone the write end. Returns `None` if closed. + pub fn try_clone_wr(&self) -> Option { + self.wr + .lock() + .unwrap() + .as_ref() + .and_then(|w| w.try_clone().ok()) + } + + /// Close the write end by dropping it. No-op if already closed. + pub fn close_wr(&self) { + let _ = self.wr.lock().unwrap().take(); } } diff --git a/crates/runc/src/utils.rs b/crates/runc/src/utils.rs index 15596fe0..b2b01169 100644 --- a/crates/runc/src/utils.rs +++ b/crates/runc/src/utils.rs @@ -21,7 +21,6 @@ use std::{ path::{Path, PathBuf}, }; -use path_absolutize::*; use serde::Serialize; #[cfg(not(feature = "async"))] use tempfile::{Builder, NamedTempFile}; @@ -36,11 +35,18 @@ pub fn abs_path_buf

(path: P) -> Result where P: AsRef, { - Ok(path - .as_ref() - .absolutize() - .map_err(Error::InvalidPath)? - .to_path_buf()) + let abs = std::path::absolute(path).map_err(Error::InvalidPath)?; + let mut normalized = PathBuf::new(); + for component in abs.components() { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + c => normalized.push(c), + } + } + Ok(normalized) } fn path_to_string(path: impl AsRef) -> Result { @@ -48,11 +54,10 @@ fn path_to_string(path: impl AsRef) -> Result { .to_str() .map(|v| v.to_string()) .ok_or_else(|| { - let e = std::io::Error::new( - std::io::ErrorKind::Other, - format!("invalid UTF-8 string: {}", path.as_ref().to_string_lossy()), - ); - Error::InvalidPath(e) + Error::InvalidPath(std::io::Error::other(format!( + "invalid UTF-8 string: {}", + path.as_ref().to_string_lossy() + ))) }) } diff --git a/crates/shim-protos/Cargo.toml b/crates/shim-protos/Cargo.toml index 10c2cb05..ed2c5764 100644 --- a/crates/shim-protos/Cargo.toml +++ b/crates/shim-protos/Cargo.toml @@ -49,17 +49,17 @@ required-features = ["async"] [dependencies] async-trait = { workspace = true, optional = true } -protobuf = "3.7.2" -ttrpc = "0.8.3" +protobuf = { version = "3.7", default-features = false } +ttrpc = { version = "0.8", default-features = false, features = ["sync"] } [build-dependencies] ttrpc-codegen = "0.6.0" [dev-dependencies] -ctrlc = { version = "3.0", features = ["termination"] } +ctrlc = { version = "3.5", default-features = false, features = ["termination"] } simple_logger = { workspace = true, features = ["stderr"] } -tokio = { workspace = true, features = ["full"] } -crossbeam.workspace = true # Used by create_ttrpc_context() +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +crossbeam = { workspace = true, features = ["crossbeam-channel"] } # Used by create_ttrpc_context() [package.metadata.docs.rs] features = ["docs"] diff --git a/crates/shim/Cargo.toml b/crates/shim/Cargo.toml index 691ee8a5..7fc9eb1d 100644 --- a/crates/shim/Cargo.toml +++ b/crates/shim/Cargo.toml @@ -28,47 +28,42 @@ name = "windows-log-reader" path = "examples/windows_log_reader.rs" [dependencies] -which = "8.0.0" +which = { version = "8.0.0", default-features = false, features = ["real-sys"] } containerd-shim-protos = { path = "../shim-protos", version = "0.10.0" } go-flag = "0.1.0" -lazy_static = "1.4.0" -sha2 = "0.10.2" +sha2 = { version = "0.10", default-features = false, features = ["std"] } libc.workspace = true log = { workspace = true, features = ["std", "kv_unstable"] } nix = { workspace = true, features = [ - "ioctl", "fs", "socket", "signal", "mount", "sched", ] } -oci-spec.workspace = true -page_size = "0.6.0" -prctl.workspace = true -signal-hook = "0.3.13" -serde.workspace = true -serde_json.workspace = true +oci-spec = { workspace = true, features = ["runtime"] } +signal-hook = "0.3.18" +serde = { workspace = true, features = ["derive", "std"] } +serde_json = { workspace = true, features = ["std"] } tempfile.workspace = true thiserror.workspace = true -time.workspace = true +time = { workspace = true, features = ["std", "formatting"] } # tracing -tracing = { version = "0.1", optional = true } +tracing = { version = "0.1", default-features = false, optional = true } # Async dependencies async-trait = { workspace = true, optional = true } -futures = { workspace = true, optional = true } -tokio = { workspace = true, features = ["full"], optional = true } +futures = { workspace = true, features = ["std", "alloc"], optional = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "process", "sync", "fs", "io-util", "time", "signal", "io-std"], optional = true } [target.'cfg(target_os = "linux")'.dependencies] cgroups-rs.workspace = true [target.'cfg(windows)'.dependencies] -mio = { version = "1.0", features = ["os-ext", "os-poll"] } -windows-sys = { version = "0.52.0", features = [ +mio = { version = "1.1", default-features = false, features = ["os-ext", "os-poll"] } +windows-sys = { version = "0.52.0", default-features = false, features = [ "Win32_Foundation", - "Win32_System_WindowsProgramming", "Win32_System_Console", "Win32_System_Pipes", "Win32_Security", diff --git a/crates/shim/src/asynchronous/monitor.rs b/crates/shim/src/asynchronous/monitor.rs index efc7b0ff..0b4114a2 100644 --- a/crates/shim/src/asynchronous/monitor.rs +++ b/crates/shim/src/asynchronous/monitor.rs @@ -14,9 +14,8 @@ limitations under the License. */ -use std::collections::HashMap; +use std::{collections::HashMap, sync::LazyLock}; -use lazy_static::lazy_static; use log::error; use tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, @@ -28,16 +27,13 @@ use crate::{ monitor::{ExitEvent, Subject, Topic}, }; -lazy_static! { - pub static ref MONITOR: Mutex = { - let monitor = Monitor { - seq_id: 0, - subscribers: HashMap::new(), - topic_subs: HashMap::new(), - }; - Mutex::new(monitor) - }; -} +pub static MONITOR: LazyLock> = LazyLock::new(|| { + Mutex::new(Monitor { + seq_id: 0, + subscribers: HashMap::new(), + topic_subs: HashMap::new(), + }) +}); pub async fn monitor_subscribe(topic: Topic) -> Result { let mut monitor = MONITOR.lock().await; diff --git a/crates/shim/src/mount_linux.rs b/crates/shim/src/mount_linux.rs index 09983c77..cf67c0d4 100644 --- a/crates/shim/src/mount_linux.rs +++ b/crates/shim/src/mount_linux.rs @@ -13,8 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -#![allow(unused)] - use std::{ collections::HashMap, env, @@ -23,15 +21,16 @@ use std::{ ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}, os::fd::AsRawFd, path::Path, + sync::LazyLock, }; -use lazy_static::lazy_static; +#[cfg(not(feature = "async"))] use log::error; -use nix::{ - mount::{mount, MntFlags, MsFlags}, - sched::{unshare, CloneFlags}, - unistd::{fork, ForkResult}, -}; +use nix::mount::{mount, MntFlags, MsFlags}; +#[cfg(feature = "async")] +use nix::sched::{unshare, CloneFlags}; +#[cfg(not(feature = "async"))] +use nix::unistd::{fork, ForkResult}; use crate::error::{Error, Result}; #[cfg(not(feature = "async"))] @@ -89,10 +88,13 @@ impl Default for LoopInfo { } const LOOP_CONTROL_PATH: &str = "/dev/loop-control"; +#[cfg(feature = "async")] const LOOP_DEV_FORMAT: &str = "/dev/loop"; +#[cfg(feature = "async")] const EBUSY_STRING: &str = "device or resource busy"; const OVERLAY_LOWERDIR_PREFIX: &str = "lowerdir="; +#[allow(dead_code)] #[derive(Debug, Default, Clone)] struct MountInfo { /// id is a unique identifier of the mount (may be reused after umount). @@ -126,195 +128,202 @@ struct MountInfo { pub vfs_options: String, } -lazy_static! { - static ref MOUNT_FLAGS: HashMap<&'static str, Flag> = { - let mut mf = HashMap::new(); - let zero: MsFlags = MsFlags::empty(); - mf.insert( - "async", - Flag { - clear: true, - flags: MsFlags::MS_SYNCHRONOUS, - }, - ); - mf.insert( - "atime", - Flag { - clear: true, - flags: MsFlags::MS_NOATIME, - }, - ); - mf.insert( - "bind", - Flag { - clear: false, - flags: MsFlags::MS_BIND, - }, - ); - mf.insert( - "defaults", - Flag { - clear: false, - flags: zero, - }, - ); - mf.insert( - "dev", - Flag { - clear: true, - flags: MsFlags::MS_NODEV, - }, - ); - mf.insert( - "diratime", - Flag { - clear: true, - flags: MsFlags::MS_NODIRATIME, - }, - ); - mf.insert( - "dirsync", - Flag { - clear: false, - flags: MsFlags::MS_DIRSYNC, - }, - ); - mf.insert( - "exec", - Flag { - clear: true, - flags: MsFlags::MS_NOEXEC, - }, - ); - mf.insert( - "mand", - Flag { - clear: false, - flags: MsFlags::MS_MANDLOCK, - }, - ); - mf.insert( - "noatime", - Flag { - clear: false, - flags: MsFlags::MS_NOATIME, - }, - ); - mf.insert( - "nodev", - Flag { - clear: false, - flags: MsFlags::MS_NODEV, - }, - ); - mf.insert( - "nodiratime", - Flag { - clear: false, - flags: MsFlags::MS_NODIRATIME, - }, - ); - mf.insert( - "noexec", - Flag { - clear: false, - flags: MsFlags::MS_NOEXEC, - }, - ); - mf.insert( - "nomand", - Flag { - clear: true, - flags: MsFlags::MS_MANDLOCK, - }, - ); - mf.insert( - "norelatime", - Flag { - clear: true, - flags: MsFlags::MS_RELATIME, - }, - ); - mf.insert( - "nostrictatime", - Flag { - clear: true, - flags: MsFlags::MS_STRICTATIME, - }, - ); - mf.insert( - "nosuid", - Flag { - clear: false, - flags: MsFlags::MS_NOSUID, - }, - ); - mf.insert( - "rbind", - Flag { - clear: false, - flags: MsFlags::MS_BIND | MsFlags::MS_REC, - }, - ); - mf.insert( - "relatime", - Flag { - clear: false, - flags: MsFlags::MS_RELATIME, - }, - ); - mf.insert( - "remount", - Flag { - clear: false, - flags: MsFlags::MS_REMOUNT, - }, - ); - mf.insert( - "ro", - Flag { - clear: false, - flags: MsFlags::MS_RDONLY, - }, - ); - mf.insert( - "rw", - Flag { - clear: true, - flags: MsFlags::MS_RDONLY, - }, - ); - mf.insert( - "strictatime", - Flag { - clear: false, - flags: MsFlags::MS_STRICTATIME, - }, - ); - mf.insert( - "suid", - Flag { - clear: true, - flags: MsFlags::MS_NOSUID, - }, - ); - mf.insert( - "sync", - Flag { - clear: false, - flags: MsFlags::MS_SYNCHRONOUS, - }, - ); - mf - }; - static ref PROPAGATION_TYPES: MsFlags = MsFlags::MS_SHARED - .bitor(MsFlags::MS_PRIVATE) - .bitor(MsFlags::MS_SLAVE) - .bitor(MsFlags::MS_UNBINDABLE); - static ref MS_PROPAGATION: MsFlags = PROPAGATION_TYPES - .bitor(MsFlags::MS_REC) - .bitor(MsFlags::MS_SILENT); - static ref MS_BIND_RO: MsFlags = MsFlags::MS_BIND.bitor(MsFlags::MS_RDONLY); +static MOUNT_FLAGS: LazyLock> = LazyLock::new(|| { + let mut mf = HashMap::new(); + let zero: MsFlags = MsFlags::empty(); + mf.insert( + "async", + Flag { + clear: true, + flags: MsFlags::MS_SYNCHRONOUS, + }, + ); + mf.insert( + "atime", + Flag { + clear: true, + flags: MsFlags::MS_NOATIME, + }, + ); + mf.insert( + "bind", + Flag { + clear: false, + flags: MsFlags::MS_BIND, + }, + ); + mf.insert( + "defaults", + Flag { + clear: false, + flags: zero, + }, + ); + mf.insert( + "dev", + Flag { + clear: true, + flags: MsFlags::MS_NODEV, + }, + ); + mf.insert( + "diratime", + Flag { + clear: true, + flags: MsFlags::MS_NODIRATIME, + }, + ); + mf.insert( + "dirsync", + Flag { + clear: false, + flags: MsFlags::MS_DIRSYNC, + }, + ); + mf.insert( + "exec", + Flag { + clear: true, + flags: MsFlags::MS_NOEXEC, + }, + ); + mf.insert( + "mand", + Flag { + clear: false, + flags: MsFlags::MS_MANDLOCK, + }, + ); + mf.insert( + "noatime", + Flag { + clear: false, + flags: MsFlags::MS_NOATIME, + }, + ); + mf.insert( + "nodev", + Flag { + clear: false, + flags: MsFlags::MS_NODEV, + }, + ); + mf.insert( + "nodiratime", + Flag { + clear: false, + flags: MsFlags::MS_NODIRATIME, + }, + ); + mf.insert( + "noexec", + Flag { + clear: false, + flags: MsFlags::MS_NOEXEC, + }, + ); + mf.insert( + "nomand", + Flag { + clear: true, + flags: MsFlags::MS_MANDLOCK, + }, + ); + mf.insert( + "norelatime", + Flag { + clear: true, + flags: MsFlags::MS_RELATIME, + }, + ); + mf.insert( + "nostrictatime", + Flag { + clear: true, + flags: MsFlags::MS_STRICTATIME, + }, + ); + mf.insert( + "nosuid", + Flag { + clear: false, + flags: MsFlags::MS_NOSUID, + }, + ); + mf.insert( + "rbind", + Flag { + clear: false, + flags: MsFlags::MS_BIND.union(MsFlags::MS_REC), + }, + ); + mf.insert( + "relatime", + Flag { + clear: false, + flags: MsFlags::MS_RELATIME, + }, + ); + mf.insert( + "remount", + Flag { + clear: false, + flags: MsFlags::MS_REMOUNT, + }, + ); + mf.insert( + "ro", + Flag { + clear: false, + flags: MsFlags::MS_RDONLY, + }, + ); + mf.insert( + "rw", + Flag { + clear: true, + flags: MsFlags::MS_RDONLY, + }, + ); + mf.insert( + "strictatime", + Flag { + clear: false, + flags: MsFlags::MS_STRICTATIME, + }, + ); + mf.insert( + "suid", + Flag { + clear: true, + flags: MsFlags::MS_NOSUID, + }, + ); + mf.insert( + "sync", + Flag { + clear: false, + flags: MsFlags::MS_SYNCHRONOUS, + }, + ); + mf +}); + +const PROPAGATION_TYPES: MsFlags = MsFlags::MS_SHARED + .union(MsFlags::MS_PRIVATE) + .union(MsFlags::MS_SLAVE) + .union(MsFlags::MS_UNBINDABLE); + +const MS_PROPAGATION: MsFlags = PROPAGATION_TYPES + .union(MsFlags::MS_REC) + .union(MsFlags::MS_SILENT); + +const MS_BIND_RO: MsFlags = MsFlags::MS_BIND.union(MsFlags::MS_RDONLY); + +fn page_size() -> usize { + let ret = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }; + assert!(ret > 0, "sysconf(_SC_PAGESIZE) failed"); + ret as usize } fn options_size(options: &[String]) -> usize { @@ -494,7 +503,7 @@ pub fn mount_rootfs( target: impl AsRef, ) -> Result<()> { //TODO add helper to mount fuse - let max_size = page_size::get(); + let max_size = page_size(); // avoid hitting one page limit of mount argument buffer // // NOTE: 512 id a buffer during pagesize check. @@ -558,12 +567,12 @@ pub fn mount_rootfs( }); } // change the propagation type - if flags.bitand(*PROPAGATION_TYPES).ne(&zero) { + if flags.bitand(PROPAGATION_TYPES).ne(&zero) { mount::( None, target.as_ref(), None, - flags.bitand(*MS_PROPAGATION), + flags.bitand(MS_PROPAGATION), None, ) .unwrap_or_else(|err| { @@ -576,7 +585,7 @@ pub fn mount_rootfs( unsafe { libc::_exit(code.into()) }; }); } - if oflags.bitand(*MS_BIND_RO).eq(&MS_BIND_RO) { + if oflags.bitand(MS_BIND_RO).eq(&MS_BIND_RO) { mount::( None, target.as_ref(), @@ -608,7 +617,7 @@ pub fn mount_rootfs( target: impl AsRef, ) -> Result<()> { //TODO add helper to mount fuse - let max_size = page_size::get(); + let max_size = page_size(); // NOTE: 512 id a buffer during pagesize check. let (chdir, options) = if fs_type.unwrap_or("") == "overlay" && options_size(options) >= max_size - 512 { @@ -659,7 +668,7 @@ pub fn mount_rootfs( } let zero: MsFlags = MsFlags::empty(); if flags.bitand(MsFlags::MS_REMOUNT).eq(&zero) || data.is_some() { - let mut lo_file = String::new(); + let lo_file: String; let s = if lo_setup { lo_file = setup_loop(source, loop_params)?; Some(lo_file.as_str()) @@ -675,13 +684,13 @@ pub fn mount_rootfs( } // change the propagation type - if flags.bitand(*PROPAGATION_TYPES).ne(&zero) { - mount::(None, target.as_ref(), None, *MS_PROPAGATION, None).map_err( + if flags.bitand(PROPAGATION_TYPES).ne(&zero) { + mount::(None, target.as_ref(), None, MS_PROPAGATION, None).map_err( mount_error!(e, "Change {} mount propagation", target.as_ref().display()), )?; } - if oflags.bitand(*MS_BIND_RO).eq(&MS_BIND_RO) { + if oflags.bitand(MS_BIND_RO).eq(&MS_BIND_RO) { mount::( None, target.as_ref(), @@ -699,6 +708,7 @@ pub fn mount_rootfs( Ok(()) } +#[cfg(feature = "async")] fn setup_loop(source: Option<&str>, params: LoopParams) -> Result { let src = source.ok_or(other!("loop source is None"))?; for _ in 0..100 { @@ -877,8 +887,8 @@ pub fn umount_recursive(target: Option<&str>, flags: i32) -> Result<()> { if let Some(target) = target { let mut mounts = get_mounts(Some(prefix_filter(target.to_string())))?; mounts.sort_by(|a, b| b.mountpoint.len().cmp(&a.mountpoint.len())); - for (index, target) in mounts.iter().enumerate() { - umount_all(Some(target.clone().mountpoint), flags)?; + for target in &mounts { + umount_all(Some(target.mountpoint.clone()), flags)?; } }; Ok(()) @@ -907,12 +917,7 @@ fn umount_all(target: Option, flags: i32) -> Result<()> { } fn prefix_filter(prefix: String) -> impl Fn(MountInfo) -> bool { - move |m: MountInfo| { - if let Some(s) = (m.mountpoint.clone() + "/").strip_prefix(&(prefix.clone() + "/")) { - return false; - } - true - } + move |m: MountInfo| !(m.mountpoint.clone() + "/").starts_with(&(prefix.clone() + "/")) } fn get_mounts(f: Option) -> Result> diff --git a/crates/shim/src/reap.rs b/crates/shim/src/reap.rs index 585e3749..10f35624 100644 --- a/crates/shim/src/reap.rs +++ b/crates/shim/src/reap.rs @@ -27,7 +27,14 @@ use crate::error::Result; /// on the process to discover its termination status. pub fn set_subreaper() -> Result<()> { use crate::error::Error; - prctl::set_child_subreaper(true).map_err(other_error!("linux prctl returned")) + let ret = unsafe { libc::prctl(libc::PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) }; + if ret < 0 { + return Err(other!( + "linux prctl returned: {}", + std::io::Error::last_os_error() + )); + } + Ok(()) } #[cfg(not(target_os = "linux"))] @@ -43,6 +50,17 @@ mod tests { #[test] fn test_set_subreaper() { set_subreaper().unwrap(); - assert!(prctl::get_child_subreaper().unwrap()); + let mut val: libc::c_int = 0; + let ret = unsafe { + libc::prctl( + libc::PR_GET_CHILD_SUBREAPER, + &mut val as *mut libc::c_int as libc::c_ulong, + 0, + 0, + 0, + ) + }; + assert!(ret >= 0); + assert!(val != 0); } } diff --git a/crates/shim/src/synchronous/monitor.rs b/crates/shim/src/synchronous/monitor.rs index e36730a1..da35dd03 100644 --- a/crates/shim/src/synchronous/monitor.rs +++ b/crates/shim/src/synchronous/monitor.rs @@ -18,11 +18,10 @@ use std::{ collections::HashMap, sync::{ mpsc::{channel, Receiver, Sender}, - Mutex, + LazyLock, Mutex, }, }; -use lazy_static::lazy_static; use log::{error, warn}; use crate::{ @@ -30,16 +29,13 @@ use crate::{ Result, }; -lazy_static! { - pub static ref MONITOR: Mutex = { - let monitor = Monitor { - seq_id: 0, - subscribers: HashMap::new(), - topic_subs: HashMap::new(), - }; - Mutex::new(monitor) - }; -} +pub static MONITOR: LazyLock> = LazyLock::new(|| { + Mutex::new(Monitor { + seq_id: 0, + subscribers: HashMap::new(), + topic_subs: HashMap::new(), + }) +}); pub fn monitor_subscribe(topic: Topic) -> Result { let mut monitor = MONITOR.lock().unwrap(); diff --git a/crates/shim/src/util.rs b/crates/shim/src/util.rs index 7e087c41..3ba767e4 100644 --- a/crates/shim/src/util.rs +++ b/crates/shim/src/util.rs @@ -125,15 +125,13 @@ pub fn connect(address: impl AsRef) -> Result { use nix::fcntl::{fcntl, FcntlArg, FdFlag}; // SAFETY: fd is a valid file descriptor that we just created let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) }; - fcntl(borrowed_fd, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC)).map_err(|e| { + fcntl(borrowed_fd, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC)).inspect_err(|_| { let _ = close(fd); - e })?; } - connect(fd, &unix_addr).map_err(|e| { + connect(fd, &unix_addr).inspect_err(|_| { let _ = close(fd); - e })?; Ok(fd) diff --git a/crates/snapshots/Cargo.toml b/crates/snapshots/Cargo.toml index f806c33b..7a34655f 100644 --- a/crates/snapshots/Cargo.toml +++ b/crates/snapshots/Cargo.toml @@ -18,22 +18,22 @@ homepage.workspace = true docs = [] [dependencies] -async-stream = "0.3.3" -futures.workspace = true -pin-utils = "0.1.0" -prost.workspace = true -prost-types.workspace = true -serde.workspace = true +async-stream = "0.3.6" +futures = { workspace = true, features = ["std", "alloc"] } +prost = { workspace = true, features = ["derive", "std"] } +prost-types = { workspace = true, features = ["std"] } +serde = { workspace = true, features = ["derive", "std"] } thiserror.workspace = true -tonic.workspace = true +tonic = { workspace = true, features = ["codegen"] } tonic-prost.workspace = true -tokio-stream = "0.1.8" +tokio-stream = { version = "0.1", default-features = false } [dev-dependencies] futures.workspace = true log.workspace = true simple_logger.workspace = true -tokio = { workspace = true, features = ["sync"] } +tokio = { workspace = true, features = ["macros", "rt", "sync", "net", "io-util"] } +tonic = { workspace = true, features = ["server", "router"] } [build-dependencies] tonic-prost-build.workspace = true diff --git a/crates/snapshots/src/wrap.rs b/crates/snapshots/src/wrap.rs index aa4d69aa..1bae9565 100644 --- a/crates/snapshots/src/wrap.rs +++ b/crates/snapshots/src/wrap.rs @@ -164,7 +164,7 @@ impl Snapshots for Wrapper { let sn = self.snapshotter.clone(); let output = async_stream::try_stream! { let walk_stream = sn.list(request.snapshotter, request.filters).await?; - pin_utils::pin_mut!(walk_stream); + let mut walk_stream = std::pin::pin!(walk_stream); let mut infos = Vec::::new(); while let Some(info) = walk_stream.next().await { infos.push(info?.into()); diff --git a/deny.toml b/deny.toml index ee735da6..77c5a110 100644 --- a/deny.toml +++ b/deny.toml @@ -70,8 +70,6 @@ feature-depth = 1 # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ - "RUSTSEC-2024-0370", # proc-macro-error is unmaintained - "RUSTSEC-2024-0437", # Crash due to uncontrolled recursion in protobuf crate #"RUSTSEC-0000-0000", #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish @@ -94,6 +92,7 @@ allow = [ "MIT", "Apache-2.0", "BSD-3-Clause", + "Zlib", "Unicode-3.0", #"Apache-2.0 WITH LLVM-exception", ]