Skip to content

Commit f96c208

Browse files
committed
feedback from colin:
- Move Decompressable and friends to generic_decompress.rs - Add module docstring - Add tests to feed garbage into gzip/zstd decompressors and make sure they don't panic on drop Signed-off-by: John Eckersberg <[email protected]>
1 parent cc52892 commit f96c208

File tree

3 files changed

+92
-51
lines changed

3 files changed

+92
-51
lines changed

ostree-ext/src/container/unencapsulate.rs

Lines changed: 25 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
// which is exactly what is exported by the [`crate::tar::export`] process.
3333

3434
use crate::container::store::LayerProgress;
35+
use crate::generic_decompress::{
36+
Decompressable, GzipDecompressor, TransparentDecompressor, ZstdDecompressor,
37+
};
3538

3639
use super::*;
3740
use containers_image_proxy::{ImageProxy, OpenedImage};
@@ -191,57 +194,6 @@ pub async fn unencapsulate(repo: &ostree::Repo, imgref: &OstreeImageReference) -
191194
importer.unencapsulate().await
192195
}
193196

194-
trait Decompressable: Read + Send + 'static {
195-
fn get_inner_mut(&mut self) -> &mut (dyn Read);
196-
}
197-
198-
// TransparentDecompressor
199-
200-
struct TransparentDecompressor<R: Read + Send + 'static>(R);
201-
202-
impl<R: Read + Send + 'static> Read for TransparentDecompressor<R> {
203-
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
204-
self.0.read(buf)
205-
}
206-
}
207-
208-
impl<R: Read + Send + 'static> Decompressable for TransparentDecompressor<R> {
209-
fn get_inner_mut(&mut self) -> &mut (dyn Read) {
210-
&mut self.0
211-
}
212-
}
213-
214-
// GzipDecompressor
215-
216-
struct GzipDecompressor<R: std::io::BufRead>(flate2::bufread::GzDecoder<R>);
217-
218-
impl<R: std::io::BufRead + Send + 'static> Read for GzipDecompressor<R> {
219-
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
220-
self.0.read(buf)
221-
}
222-
}
223-
224-
impl<R: std::io::BufRead + Send + 'static> Decompressable for GzipDecompressor<R> {
225-
fn get_inner_mut(&mut self) -> &mut (dyn Read) {
226-
self.0.get_mut()
227-
}
228-
}
229-
230-
// ZstdDecompressor
231-
struct ZstdDecompressor<'a, R: std::io::BufRead>(zstd::stream::read::Decoder<'a, R>);
232-
233-
impl<'a: 'static, R: std::io::BufRead + Send + 'static> Read for ZstdDecompressor<'a, R> {
234-
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
235-
self.0.read(buf)
236-
}
237-
}
238-
239-
impl<'a: 'static, R: std::io::BufRead + Send + 'static> Decompressable for ZstdDecompressor<'a, R> {
240-
fn get_inner_mut(&mut self) -> &mut (dyn Read) {
241-
self.0.get_mut()
242-
}
243-
}
244-
245197
pub(crate) struct Decompressor {
246198
inner: Box<dyn Decompressable>,
247199
finished: bool,
@@ -429,4 +381,26 @@ mod tests {
429381
let d = Decompressor::new(&oci_image::MediaType::ImageLayerZstd, empty).unwrap();
430382
drop(d)
431383
}
384+
385+
#[test]
386+
fn test_gzip_decompressor_with_garbage_input() {
387+
let garbage = b"This is not valid gzip data";
388+
let mut d = Decompressor::new(&oci_image::MediaType::ImageLayerGzip, &garbage[..]).unwrap();
389+
let mut buf = [0u8; 32];
390+
let e = d.read(&mut buf).unwrap_err();
391+
assert!(matches!(e.kind(), std::io::ErrorKind::InvalidInput));
392+
assert_eq!(e.to_string(), "invalid gzip header".to_string());
393+
drop(d)
394+
}
395+
396+
#[test]
397+
fn test_zstd_decompressor_with_garbage_input() {
398+
let garbage = b"This is not valid zstd data";
399+
let mut d = Decompressor::new(&oci_image::MediaType::ImageLayerZstd, &garbage[..]).unwrap();
400+
let mut buf = [0u8; 32];
401+
let e = d.read(&mut buf).unwrap_err();
402+
assert!(matches!(e.kind(), std::io::ErrorKind::Other));
403+
assert_eq!(e.to_string(), "Unknown frame descriptor".to_string());
404+
drop(d)
405+
}
432406
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! This module contains the `Decompressable` trait and related
2+
//! concrete implementations thereof. These provide a means for each
3+
//! specific decompressor to give mutable access to the inner reader.
4+
//!
5+
//! For example, the GzipDecompressor would give the underlying
6+
//! compressed stream.
7+
//!
8+
//! We need a common way to access this stream so that we can flush
9+
//! the data during cleanup.
10+
//!
11+
//! See: https://github.com/bootc-dev/bootc/issues/1407
12+
13+
use std::io::Read;
14+
15+
/// Extends the `Read` trait with another method to get mutable access to the inner reader
16+
pub(crate) trait Decompressable: Read + Send + 'static {
17+
fn get_inner_mut(&mut self) -> &mut (dyn Read);
18+
}
19+
20+
// TransparentDecompressor
21+
22+
pub(crate) struct TransparentDecompressor<R: Read + Send + 'static>(pub R);
23+
24+
impl<R: Read + Send + 'static> Read for TransparentDecompressor<R> {
25+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
26+
self.0.read(buf)
27+
}
28+
}
29+
30+
impl<R: Read + Send + 'static> Decompressable for TransparentDecompressor<R> {
31+
fn get_inner_mut(&mut self) -> &mut (dyn Read) {
32+
&mut self.0
33+
}
34+
}
35+
36+
// GzipDecompressor
37+
38+
pub(crate) struct GzipDecompressor<R: std::io::BufRead>(pub flate2::bufread::GzDecoder<R>);
39+
40+
impl<R: std::io::BufRead + Send + 'static> Read for GzipDecompressor<R> {
41+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
42+
self.0.read(buf)
43+
}
44+
}
45+
46+
impl<R: std::io::BufRead + Send + 'static> Decompressable for GzipDecompressor<R> {
47+
fn get_inner_mut(&mut self) -> &mut (dyn Read) {
48+
self.0.get_mut()
49+
}
50+
}
51+
52+
// ZstdDecompressor
53+
54+
pub(crate) struct ZstdDecompressor<'a, R: std::io::BufRead>(pub zstd::stream::read::Decoder<'a, R>);
55+
56+
impl<'a: 'static, R: std::io::BufRead + Send + 'static> Read for ZstdDecompressor<'a, R> {
57+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
58+
self.0.read(buf)
59+
}
60+
}
61+
62+
impl<'a: 'static, R: std::io::BufRead + Send + 'static> Decompressable for ZstdDecompressor<'a, R> {
63+
fn get_inner_mut(&mut self) -> &mut (dyn Read) {
64+
self.0.get_mut()
65+
}
66+
}

ostree-ext/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub mod cli;
3737
pub mod container;
3838
pub mod container_utils;
3939
pub mod diff;
40+
pub(crate) mod generic_decompress;
4041
pub mod ima;
4142
pub mod keyfileext;
4243
pub(crate) mod logging;

0 commit comments

Comments
 (0)