Skip to main content

imago/format/
gate.rs

1//! Gate functionality to control implicitly opened dependencies.
2
3use super::builder::FormatDriverBuilder;
4use crate::{FormatAccess, Storage, StorageOpenOptions};
5use maybe_async::maybe_async;
6use std::io;
7
8/// Gate implicit image and storage object dependencies.
9///
10/// Depending on their format, images may have external image and storage object dependencies; for
11/// example, qcow2 images can reference a backing image (any image format), and an external data
12/// file (pure storage object, no format).  You can override these implicit choices when opening
13/// images, but if you do not, they are carried out automatically.
14///
15/// However, opening implicit dependencies is always done through an object of type
16/// `ImplicitOpenGate`, which you pass to [`FormatDriverBuilder::open()`].  Implementing this trait
17/// therefore allows you to restrict if and how images an storage objects are opened implicitly.
18///
19/// Anytime a storage object is opened, it is done by an [`ImplicitOpenGate::open_storage()`]
20/// implementation.  Anytime a format layer is opened, it is done by an
21/// [`ImplicitOpenGate::open_format()`] implementation.  Therefore, unless your implementation does
22/// perform this open operation, nothing will be opened.
23///
24/// Do note however that whatever you open explicitly through [`FormatDriverBuilder::open()`] or
25/// [`Storage::open()`] is *not* run through `ImplicitOpenGate`.
26///
27/// See [`PermissiveImplicitOpenGate`] and [`DenyImplicitOpenGate`].
28#[maybe_async(AFIT)]
29pub trait ImplicitOpenGate<S: Storage + 'static> {
30    /// Open an implicitly referenced format layer.
31    ///
32    /// You can e.g. check the supposed format via `F::FORMAT`, and its filename via
33    /// `builder.get_image_path()`.
34    ///
35    /// Note that this is not invoked for images that are explicitly opened, i.e. whenever
36    /// [`FormatDriverBuilder::open()`] is called by imago users.
37    #[allow(async_fn_in_trait)] // No need for Send
38    async fn open_format<F: FormatDriverBuilder<S>>(
39        &mut self,
40        builder: F,
41    ) -> io::Result<FormatAccess<S>>;
42
43    /// Open an implicitly referenced storage object.
44    ///
45    /// You can e.g. check the filename via `builder.get_filename()`.
46    ///
47    /// Note that this is not invoked for storage objects that are explicitly opened, i.e. whenever
48    /// an object of type `S` is created by imago users (e.g. via [`S::open()`](Storage::open())).
49    #[allow(async_fn_in_trait)] // No need for Send
50    async fn open_storage(&mut self, builder: StorageOpenOptions) -> io::Result<S>;
51}
52
53/// Open all implicitly referenced images/files unrestricted, as requested.
54///
55/// Use with caution!  Allowing all implicit dependencies to be opened automatically without
56/// restrictions is dangerous:
57/// - if you plan to give access to the image to an untrusted third party (e.g. a VM guest), and
58/// - unless the image comes from a fully trusted source.
59///
60/// This would give the untrusted third party potentially access to arbitrary storage object
61/// accessible through imago.
62///
63/// (See also the safety section on
64/// [`FormatDriverInstance::probe()`](super::drivers::FormatDriverInstance::probe()).)
65#[derive(Clone, Copy, Debug, Default)]
66pub struct PermissiveImplicitOpenGate();
67
68#[maybe_async(AFIT)]
69impl<S: Storage + 'static> ImplicitOpenGate<S> for PermissiveImplicitOpenGate {
70    async fn open_format<F: FormatDriverBuilder<S>>(
71        &mut self,
72        builder: F,
73    ) -> io::Result<FormatAccess<S>> {
74        // In async mode, Box::pin is needed for recursion
75        #[cfg(feature = "async")]
76        let driver_instance = Box::pin(builder.open(Self::default())).await?;
77        #[cfg(feature = "sync")]
78        let driver_instance = builder.open(Self::default())?;
79        Ok(FormatAccess::new(driver_instance))
80    }
81
82    async fn open_storage(&mut self, builder: StorageOpenOptions) -> io::Result<S> {
83        S::open(builder).await
84    }
85}
86
87/// Disallow any implicitly referenced images or storage objects.
88///
89/// Always returns errors, ensuring nothing can be opened implicitly.  Useful when you intend to
90/// explicitly override all potential implicit references, and want a safeguard that you did not
91/// forget anything.
92///
93/// If you did forget something, the error generated by this object will most likely be propagated
94/// up to the prompting [`FormatDriverBuilder::open()`] call, failing it.
95#[derive(Clone, Copy, Debug, Default)]
96pub struct DenyImplicitOpenGate();
97
98#[maybe_async(AFIT)]
99impl<S: Storage + 'static> ImplicitOpenGate<S> for DenyImplicitOpenGate {
100    async fn open_format<F: FormatDriverBuilder<S>>(
101        &mut self,
102        builder: F,
103    ) -> io::Result<FormatAccess<S>> {
104        let msg = if let Some(filename) = builder.get_image_path() {
105            format!("Opening implicitly referenced format layer {filename:?} denied")
106        } else {
107            "Opening implicitly referenced format layer denied".into()
108        };
109
110        Err(io::Error::new(io::ErrorKind::PermissionDenied, msg))
111    }
112
113    async fn open_storage(&mut self, builder: StorageOpenOptions) -> io::Result<S> {
114        let msg = if let Some(filename) = builder.get_filename() {
115            format!("Opening implicitly referenced storage object {filename:?} denied")
116        } else {
117            "Opening implicitly referenced storage object denied".into()
118        };
119
120        Err(io::Error::new(io::ErrorKind::PermissionDenied, msg))
121    }
122}