Skip to content

Commit

Permalink
Add krun_add_formatted_disk_image API
Browse files Browse the repository at this point in the history
Adds the `krun_add_formatted_disk_image` API that requires the user to
specify the format of the disk image they're providing.

The API only supports the QCOW2 formatted disk as an option in the form
of the `KRUN_DISK_IMAGE_QCOW2` constant.

If the user wants to add a Raw disk image, they must use the
`krun_add_disk` API.

Signed-off-by: Jake Correnti <[email protected]>
  • Loading branch information
jakecorrenti committed Nov 18, 2024
1 parent d06cbb5 commit 5571dd1
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 3 deletions.
35 changes: 35 additions & 0 deletions include/libkrun.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ int32_t krun_set_data_disk(uint32_t ctx_id, const char *disk_path);
* This API is mutually exclusive with the deprecated krun_set_root_disk and
* krun_set_data_disk methods and must not be used together.
*
* By all possible means, one should avoid probing the disk image file that will be given to libkrun.
* If a raw file is probed, and a QCOW2 header is written into the raw file's header, the next time
* libkrun launches the VM it will boot as a QCOW2 image. QCOW2 files can, and will, open other files.
* The guest will most likely have access to the data in those files, essentially giving the guest
* access to any file on the host system the disk emulation has access to.
*
* Arguments:
* "ctx_id" - the configuration context ID.
* "block_id" - a null-terminated string representing the partition.
Expand All @@ -113,6 +119,35 @@ int32_t krun_set_data_disk(uint32_t ctx_id, const char *disk_path);
*/
int32_t krun_add_disk(uint32_t ctx_id, const char *block_id, const char *disk_path, bool read_only);

/* Formatted disk image that are supported */
#define KRUN_DISK_FORMAT_QCOW2 0
/**
* Adds a formatted disk image to be used as a general partition for the microVM. The supported
* image formats are: "qcow2".
*
* This API is mutually exclusive with the deprecated krun_set_root_disk and
* krun_set_data_disk methods and must not be used together.
*
* By all possible means, one should avoid probing the disk image file that will be given to libkrun.
*
* Arguments:
* "ctx_id" - the configuration context ID.
* "block_id" - a null-terminated string representing the partition.
* "disk_path" - a null-terminated string representing the path leading to the disk image that
* contains the root file-system.
* "disk_format" - the formatted disk image format
* "read_only" - whether the mount should be read-only. Required if the caller does not have
* write permissions (for disk images in /usr/share).
*
* Returns:
* Zero on success or a negative error number on failure.
*/
int32_t krun_add_formatted_disk(uint32_t ctx_id,
const char *block_id,
const char *disk_path,
uint32_t disk_format,
bool read_only);

/**
* NO LONGER SUPPORTED. DO NOT USE.
*
Expand Down
10 changes: 9 additions & 1 deletion src/devices/src/virtio/block/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use std::cmp;
use std::convert::From;
use std::fs::{File, OpenOptions};
use std::io::{self, Write};
use std::io::{self, ErrorKind, Write};
#[cfg(target_os = "linux")]
use std::os::linux::fs::MetadataExt;
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -204,6 +204,7 @@ impl Block {
partuuid: Option<String>,
cache_type: CacheType,
disk_image_path: String,
disk_image_format: ImageType,
is_disk_read_only: bool,
) -> io::Result<Block> {
let disk_image = OpenOptions::new()
Expand All @@ -215,6 +216,13 @@ impl Block {

let image_type = disk::detect_image_type(&disk_image, false).unwrap();

if image_type != disk_image_format {
return Err(io::Error::new(
ErrorKind::InvalidInput,
"image type reported does not match image header",
));
}

let disk_image = match image_type {
ImageType::Qcow2 => {
let mut qcow_disk_image =
Expand Down
2 changes: 1 addition & 1 deletion src/devices/src/virtio/block/disk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub enum Error {
type Result<T> = std::result::Result<T, Error>;

/// The variants of image files on the host that can be used as virtual disks.
#[derive(Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ImageType {
Raw,
Qcow2,
Expand Down
52 changes: 52 additions & 0 deletions src/libkrun/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use std::sync::Mutex;

#[cfg(target_os = "macos")]
use crossbeam_channel::unbounded;
#[cfg(feature = "blk")]
use devices::virtio::block::disk::ImageType;
#[cfg(feature = "net")]
use devices::virtio::net::device::VirtioNetBackend;
#[cfg(feature = "blk")]
Expand Down Expand Up @@ -521,6 +523,54 @@ pub unsafe extern "C" fn krun_add_disk(
block_id: block_id.to_string(),
cache_type: CacheType::Writeback,
disk_image_path: disk_path.to_string(),
disk_image_format: ImageType::Raw,
is_disk_read_only: read_only,
};
cfg.add_block_cfg(block_device_config);
}
Entry::Vacant(_) => return -libc::ENOENT,
}

KRUN_SUCCESS
}

#[allow(clippy::missing_safety_doc)]
#[no_mangle]
#[cfg(feature = "blk")]
pub unsafe extern "C" fn krun_add_formatted_disk(
ctx_id: u32,
c_block_id: *const c_char,
c_disk_path: *const c_char,
disk_format: u32,
read_only: bool,
) -> i32 {
let disk_path = match CStr::from_ptr(c_disk_path).to_str() {
Ok(disk) => disk,
Err(_) => return -libc::EINVAL,
};

let block_id = match CStr::from_ptr(c_block_id).to_str() {
Ok(block_id) => block_id,
Err(_) => return -libc::EINVAL,
};

let format = match disk_format {
0 => ImageType::Qcow2,
_ => {
// Qcow2 is the only supported formatted disk image format. Any other value specified
// is invalid.
return -libc::EINVAL;
}
};

match CTX_MAP.lock().unwrap().entry(ctx_id) {
Entry::Occupied(mut ctx_cfg) => {
let cfg = ctx_cfg.get_mut();
let block_device_config = BlockDeviceConfig {
block_id: block_id.to_string(),
cache_type: CacheType::Writeback,
disk_image_path: disk_path.to_string(),
disk_image_format: format,
is_disk_read_only: read_only,
};
cfg.add_block_cfg(block_device_config);
Expand All @@ -547,6 +597,7 @@ pub unsafe extern "C" fn krun_set_root_disk(ctx_id: u32, c_disk_path: *const c_c
block_id: "root".to_string(),
cache_type: CacheType::Writeback,
disk_image_path: disk_path.to_string(),
disk_image_format: ImageType::Raw,
is_disk_read_only: false,
};
cfg.set_root_block_cfg(block_device_config);
Expand All @@ -573,6 +624,7 @@ pub unsafe extern "C" fn krun_set_data_disk(ctx_id: u32, c_disk_path: *const c_c
block_id: "data".to_string(),
cache_type: CacheType::Writeback,
disk_image_path: disk_path.to_string(),
disk_image_format: ImageType::Raw,
is_disk_read_only: false,
};
cfg.set_data_block_cfg(block_device_config);
Expand Down
4 changes: 3 additions & 1 deletion src/vmm/src/vmm_config/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::VecDeque;
use std::fmt;
use std::sync::{Arc, Mutex};

use devices::virtio::{Block, CacheType};
use devices::virtio::{block::disk::ImageType, Block, CacheType};

#[derive(Debug)]
pub enum BlockConfigError {
Expand All @@ -26,6 +26,7 @@ pub struct BlockDeviceConfig {
pub block_id: String,
pub cache_type: CacheType,
pub disk_image_path: String,
pub disk_image_format: ImageType,
pub is_disk_read_only: bool,
}

Expand Down Expand Up @@ -53,6 +54,7 @@ impl BlockBuilder {
None,
config.cache_type,
config.disk_image_path,
config.disk_image_format,
config.is_disk_read_only,
)
.map_err(BlockConfigError::CreateBlockDevice)
Expand Down

0 comments on commit 5571dd1

Please sign in to comment.