diff --git a/crates/bpf-common/src/containers/layers.rs b/crates/bpf-common/src/containers/layers.rs index c423106c..ec8f783f 100644 --- a/crates/bpf-common/src/containers/layers.rs +++ b/crates/bpf-common/src/containers/layers.rs @@ -80,12 +80,27 @@ struct Rootfs { /// Returns a list of layer paths for the given Docker image ID. pub(crate) async fn docker_layers(image_id: &str) -> Result, ContainerError> { let client = Client::unix(); - let url = HyperlocalUri::new(DOCKER_SOCKET, &format!("/images/{}/json", image_id)); - - let response = client.get(url.into()).await.unwrap(); - let body_bytes = body::to_bytes(response).await.unwrap(); - - let response: ImageInspect = serde_json::from_slice(&body_bytes).unwrap(); + let uri = HyperlocalUri::new(DOCKER_SOCKET, &format!("/images/{}/json", image_id)); + let uri: hyper::Uri = uri.into(); + + let response = + client + .get(uri.clone()) + .await + .map_err(|source| ContainerError::HyperRequest { + source, + uri: uri.clone(), + })?; + let body_bytes = + body::to_bytes(response) + .await + .map_err(|source| ContainerError::HyperResponse { + source, + uri: uri.clone(), + })?; + + let response: ImageInspect = serde_json::from_slice(&body_bytes) + .map_err(|source| ContainerError::ParseResponse { source, uri })?; match response.graph_driver.name { GraphDriverName::Btrfs => docker_btrfs_layers(image_id), @@ -132,7 +147,10 @@ fn docker_btrfs_layers(image_id: &str) -> Result, ContainerError> { .map_err(|source| ContainerError::ParseConfigFile { source, path })?; for layer_id in imagedb_entry.rootfs.diff_ids { - let layer_id = layer_id.split(':').last().unwrap(); + let layer_id = layer_id + .split(':') + .last() + .ok_or(ContainerError::InvalidLayerID(layer_id.clone()))?; let path = PathBuf::from(DOCKER_LAYERDB_PATH).join(&layer_id); if path.exists() { @@ -156,6 +174,7 @@ fn docker_overlayfs_layers( if let Some(graph_driver_data) = graph_driver_data { if let Some(lower_dirs) = graph_driver_data.lower_dir { for lower_dir in lower_dirs.split(':') { + // `PathBuf::from_str` is infallible. layers.push(PathBuf::from_str(lower_dir).unwrap()); } } diff --git a/crates/bpf-common/src/containers/mod.rs b/crates/bpf-common/src/containers/mod.rs index 1a434b0a..f34510e9 100644 --- a/crates/bpf-common/src/containers/mod.rs +++ b/crates/bpf-common/src/containers/mod.rs @@ -41,8 +41,26 @@ pub enum ContainerError { source: serde_json::error::Error, path: PathBuf, }, + #[error("parsing response from `{uri:?}` failed")] + ParseResponse { + #[source] + source: serde_json::error::Error, + uri: hyper::Uri, + }, #[error("path `{path}` is non-UTF-8")] PathNonUtf8 { path: PathBuf }, + #[error("failed to make a request to the UNIX socket `{uri:?}`")] + HyperRequest { + #[source] + source: hyper::Error, + uri: hyper::Uri, + }, + #[error("failed to parse a response from the UNIX socket `{uri:?}`")] + HyperResponse { + #[source] + source: hyper::Error, + uri: hyper::Uri, + }, #[error("could not connect to the database `{path:?}`")] SqliteConnection { #[source] @@ -79,6 +97,10 @@ pub enum ContainerError { BoltBucketNotFound(String), #[error("bolt key `{0}` not found")] BoltKeyNotFound(String), + #[error("Invalid layer ID: `{0}`")] + InvalidLayerID(String), + #[error("Invalid image digest: `{0}`")] + InvalidImageDigest(String), } /// A container ID. @@ -204,7 +226,10 @@ impl ContainerInfo { // ``` // // The unprefixed digest is used as an image ID. - let image_id = image_digest.split(':').last().unwrap(); + let image_id = image_digest + .split(':') + .last() + .ok_or(ContainerError::InvalidImageDigest(image_digest.clone()))?; let layers = layers::docker_layers(image_id).await?; log::debug!("found layer filesystems for container {id}: {layers:?}");