diff --git a/include/libkrun.h b/include/libkrun.h index 16619aac..7f5ed647 100644 --- a/include/libkrun.h +++ b/include/libkrun.h @@ -95,16 +95,20 @@ int32_t krun_set_root_disk(uint32_t ctx_id, const char *disk_path); int32_t krun_set_data_disk(uint32_t ctx_id, const char *disk_path); /** - * Adds a disk image to be used as a general partition for the microVM. + * Adds a disk image to be used as a general partition for the microVM. The only supported image + * format is "raw". * * This API is mutually exclusive with the deprecated krun_set_root_disk and * krun_set_data_disk methods and must not be used together. * + * This function deliberately only handles images in the Raw format, because it doesn't allow + * specifying an image format, and probing an image's format is dangerous. For more information, + * see the security note on `krun_add_disk2`, which allows opening non-Raw images. + * * 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_path" - a null-terminated string representing the path leading to the disk image. * "read_only" - whether the mount should be read-only. Required if the caller does not have * write permissions (for disk images in /usr/share). * @@ -113,6 +117,59 @@ 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); +/* Supported disk image formats */ +#define KRUN_DISK_FORMAT_RAW 0 +#define KRUN_DISK_FORMAT_QCOW2 1 +/** + * Adds a disk image to be used as a general partition for the microVM. The supported + * image formats are: "raw" and "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. + * + * SECURITY NOTE: + * Non-Raw images can reference other files, which libkrun will automatically open, and to which the + * guest will have access. Libkrun should therefore never be asked to open an image in a non-Raw + * format when it doesn't come from a fully trustworthy source. + * + * Consequently, probing an image's format is quite dangerous and to be avoided if at all possible, + * which is why libkrun provides no facilities for doing so. If it's not clear what format an image + * has, it may also not be clear whether it can be trusted to not reference files to which the guest + * shouldn't have access. + * + * If probing absolutely can't be avoided, it must only be done on images that are fully trusted, i.e. + * before a potentially untrusted guest had write access to it. Specifically, consider that a guest has + * full access to all of a Raw image, and can therefore turn it into a file in an arbitrary format, for + * example, into a Qcow2 image, referencing and granting a malicious guest access to arbitrary files. + * To hand a Raw image to an untrusted and potentially malicious guest, and then to re-probe it after + * the guest was able to write to it (when it can no longer be trusted), would therefore be a severe + * security vulnerability. + * + * Therefore, after having probed a yet fully trusted image once, the result must be remembered so the + * image will from then on always be opened in the format that was detected originally. When adhering + * to this, a guest can write anything they want to a Raw image, it's always going to be opened as a + * Raw image, preventing the security vulnerability outlined above. + * + * However, if at all possible, the image format should be explicitly selected based on knowledge + * obtained separately from the pure image data, for example by the user. + * + * 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. + * "disk_format" - the disk image format (i.e. KRUN_DISK_FORMAT_{RAW, QCOW2}) + * "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_disk2(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. * diff --git a/src/libkrun/src/lib.rs b/src/libkrun/src/lib.rs index 058353fe..0f864f17 100644 --- a/src/libkrun/src/lib.rs +++ b/src/libkrun/src/lib.rs @@ -534,6 +534,53 @@ pub unsafe extern "C" fn krun_add_disk( KRUN_SUCCESS } +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +#[cfg(feature = "blk")] +pub unsafe extern "C" fn krun_add_disk2( + 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::Raw, + 1 => ImageType::Qcow2, + _ => { + // Do not continue if the user cannot specify a valid disk format + 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); + } + Entry::Vacant(_) => return -libc::ENOENT, + } + + KRUN_SUCCESS +} + #[allow(clippy::missing_safety_doc)] #[no_mangle] #[cfg(feature = "blk")]