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