diff --git a/Cargo.toml b/Cargo.toml index ebb9b785e..99fbcc682 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ nix = "0.23.0" oci-distribution = { git = "https://github.com/arronwy/oci-distribution", branch = "export_pull_layer" } oci-spec = { git = "https://github.com/containers/oci-spec-rs" } ocicrypt-rs = { git = "https://github.com/arronwy/ocicrypt-rs", branch = "oci_distribution" } +safe-path = "0.1" serde = { version = ">=1.0.27", features = ["serde_derive", "rc"] } serde_json = ">=1.0.9" sha2 = ">=0.10" diff --git a/src/bundle.rs b/src/bundle.rs index 302df66e1..debc1f3f2 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -2,12 +2,13 @@ // // SPDX-License-Identifier: Apache-2.0 -use anyhow::Result; use std::collections::HashMap; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; +use anyhow::{Context, Result}; use oci_spec::image::ImageConfiguration; use oci_spec::runtime::{Mount, Process, Spec}; +use safe_path::PinnedPathBuf; pub const BUNDLE_CONFIG: &str = "config.json"; pub const BUNDLE_ROOTFS: &str = "rootfs"; @@ -35,8 +36,8 @@ const ANNOTATION_EXPOSED_PORTS: &str = "org.opencontainers.image.exposedPorts"; /// runtime configuration". pub fn create_runtime_config( image_config: &ImageConfiguration, - bundle_path: &Path, -) -> Result { + bundle_path: &PinnedPathBuf, +) -> Result { let mut spec = Spec::default(); let mut annotations: HashMap = HashMap::new(); let mut labels = HashMap::new(); @@ -206,7 +207,8 @@ pub fn create_runtime_config( let bundle_config = bundle_path.join(BUNDLE_CONFIG); spec.save(&bundle_config)?; - Ok(bundle_config) + PinnedPathBuf::new(bundle_path, BUNDLE_CONFIG) + .context("The path of generated config.json file has changed, possible attack!") } #[cfg(test)] @@ -217,13 +219,14 @@ mod tests { #[test] fn test_bundle_create_config() { let image_config = ImageConfiguration::default(); - let tempdir = tempfile::tempdir().unwrap(); - let filename = tempdir.path().join(BUNDLE_CONFIG); + let tempdir = PinnedPathBuf::new("/", tempdir.path()).unwrap(); + let config_file = create_runtime_config(&image_config, &tempdir).unwrap(); - assert!(!filename.exists()); + assert!(config_file.target().exists()); + assert!(config_file.target().is_file()); - assert!(create_runtime_config(&image_config, tempdir.path()).is_ok()); - assert!(filename.exists()); + let spec = Spec::load(&config_file).unwrap(); + assert_eq!(spec.hostname().as_ref().unwrap(), BUNDLE_HOSTNAME); } } diff --git a/src/image.rs b/src/image.rs index b93ed7da1..ba37dff43 100644 --- a/src/image.rs +++ b/src/image.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, Result}; use oci_spec::image::{ImageConfiguration, Os}; +use safe_path::PinnedPathBuf; use serde::Deserialize; use std::collections::HashMap; use std::convert::TryFrom; @@ -113,7 +114,7 @@ impl ImageClient { pub async fn pull_image( &mut self, image_url: &str, - bundle_dir: &Path, + bundle_dir: &PinnedPathBuf, auth_info: &Option<&str>, decrypt_config: &Option<&str>, ) -> Result { @@ -222,10 +223,12 @@ mod tests { let mut image_client = ImageClient::default(); for image in oci_images.iter() { - let bundle_dir = tempfile::tempdir().unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + let temp_path = tempdir.path().canonicalize().unwrap(); + let bundle_dir = PinnedPathBuf::from_path(temp_path).unwrap(); assert!(image_client - .pull_image(image, bundle_dir.path(), &None, &None) + .pull_image(image, &bundle_dir, &None, &None) .await .is_ok()); }