diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index fa807a80e8b2a306b563e5cca84bf25b05703d06..d0ca0108d1d6cbcc43c314e8d5582dba0705edeb 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -26,6 +26,7 @@ use nix::unistd::{mkstemp, sysconf, unlink, SysconfVar}; use crate::{AddressRange, GuestAddress, Region}; use machine_manager::config::{HostMemPolicy, MachineMemConfig, MemZoneConfig}; use util::{ + file::check_not_symlink, syscall::mbind, unix::{do_mmap, host_page_size}, }; @@ -109,6 +110,7 @@ impl FileBackend { // SAFETY: only one FileBackend instance has the ownership of the file descriptor unsafe { File::from_raw_fd(raw_fd) } } else { + check_not_symlink(path)?; need_unlink = !path.exists(); // Open the file, if not exist, create it. std::fs::OpenOptions::new() diff --git a/boot_loader/src/aarch64/mod.rs b/boot_loader/src/aarch64/mod.rs index d06a95af65a57a31a6884132f1a0eb99efcd7f84..5558e32ff8954d07ce5a041b540f999e0b328a42 100644 --- a/boot_loader/src/aarch64/mod.rs +++ b/boot_loader/src/aarch64/mod.rs @@ -22,6 +22,7 @@ use crate::error::BootLoaderError; use address_space::{AddressAttr, AddressSpace, GuestAddress}; use devices::legacy::{error::LegacyError as FwcfgErrorKind, FwCfgEntryType, FwCfgOps}; use util::byte_code::ByteCode; +use util::file::check_not_symlink; const AARCH64_KERNEL_OFFSET: u64 = 0x8_0000; @@ -54,6 +55,7 @@ fn load_kernel( kernel_path: &Path, sys_mem: &Arc, ) -> Result { + check_not_symlink(kernel_path)?; let mut kernel_image = File::open(kernel_path).with_context(|| BootLoaderError::BootLoaderOpenKernel)?; let kernel_size = kernel_image.metadata().unwrap().len(); @@ -102,6 +104,7 @@ fn load_initrd( sys_mem: &Arc, kernel_end: u64, ) -> Result<(u64, u64)> { + check_not_symlink(initrd_path)?; let mut initrd_image = File::open(initrd_path).with_context(|| BootLoaderError::BootLoaderOpenInitrd)?; let initrd_size = initrd_image.metadata().unwrap().len(); diff --git a/boot_loader/src/x86_64/direct_boot/mod.rs b/boot_loader/src/x86_64/direct_boot/mod.rs index c910d8225ec772480d8a6cf81d275d321c18ee5a..650f5db33ce02c29d7cfd29faf096cae7108a612 100644 --- a/boot_loader/src/x86_64/direct_boot/mod.rs +++ b/boot_loader/src/x86_64/direct_boot/mod.rs @@ -31,6 +31,7 @@ use super::{ use crate::error::BootLoaderError; use address_space::{AddressAttr, AddressSpace, GuestAddress}; use util::byte_code::ByteCode; +use util::file::check_not_symlink; /// Load bzImage linux kernel to Guest Memory. /// @@ -106,6 +107,7 @@ fn load_kernel_image( sys_mem: &Arc, boot_layout: &mut X86BootLoader, ) -> Result { + check_not_symlink(kernel_path)?; let mut kernel_image = File::open(kernel_path).with_context(|| BootLoaderError::BootLoaderOpenKernel)?; @@ -146,8 +148,10 @@ fn load_initrd( initrd_addr_max = sys_mem.memory_end_address().raw_value(); }; - let mut initrd_image = File::open(config.initrd.as_ref().unwrap()) - .with_context(|| BootLoaderError::BootLoaderOpenInitrd)?; + let initrd = config.initrd.as_ref().unwrap(); + check_not_symlink(Path::new(initrd))?; + let mut initrd_image = + File::open(initrd).with_context(|| BootLoaderError::BootLoaderOpenInitrd)?; let initrd_size = initrd_image.metadata().unwrap().len(); let initrd_addr = (initrd_addr_max - initrd_size) & !0xfff_u64; diff --git a/boot_loader/src/x86_64/standard_boot/mod.rs b/boot_loader/src/x86_64/standard_boot/mod.rs index 5ad697bf769c4401d6a93f8084e965e0f626505d..eaff79c12e42c769799263dbef93de80001bc328 100644 --- a/boot_loader/src/x86_64/standard_boot/mod.rs +++ b/boot_loader/src/x86_64/standard_boot/mod.rs @@ -30,6 +30,7 @@ use crate::x86_64::{INITRD_ADDR_MAX, SETUP_START}; use address_space::AddressSpace; use devices::legacy::{FwCfgEntryType, FwCfgOps}; use util::byte_code::ByteCode; +use util::file::check_not_symlink; fn load_image( image: &mut File, @@ -102,8 +103,10 @@ fn load_initrd( initrd_addr_max = sys_mem.memory_end_address().raw_value(); }; - let mut initrd_image = File::open(config.initrd.as_ref().unwrap()) - .with_context(|| BootLoaderError::BootLoaderOpenInitrd)?; + let initrd = config.initrd.as_ref().unwrap(); + check_not_symlink(Path::new(initrd))?; + let mut initrd_image = + File::open(initrd).with_context(|| BootLoaderError::BootLoaderOpenInitrd)?; let initrd_size = initrd_image.metadata().unwrap().len(); let initrd_addr = (initrd_addr_max - initrd_size) & !0xfff_u64; @@ -207,8 +210,10 @@ pub fn load_linux( return Ok(()); } - let mut kernel_image = File::open(config.kernel.as_ref().unwrap().clone()) - .with_context(|| BootLoaderError::BootLoaderOpenKernel)?; + let kernel = config.kernel.as_ref().unwrap().clone(); + check_not_symlink(Path::new(kernel))?; + let mut kernel_image = + File::open(kernel).with_context(|| BootLoaderError::BootLoaderOpenKernel)?; let mut boot_header = RealModeKernelHeader::default(); kernel_image.seek(SeekFrom::Start(BOOT_HDR_START))?; diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index d13d306e20858c90b345ffbb6c234f103583d99f..ad5f58e77e109b9f2f1015df47280aba7354a87d 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -14,7 +14,7 @@ use std::collections::VecDeque; use std::fs::{read_link, File, OpenOptions}; use std::io::{ErrorKind, Stdin, Stdout}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -33,7 +33,7 @@ use machine_manager::{ config::{ChardevConfig, ChardevType, SocketType}, temp_cleaner::TempCleaner, }; -use util::file::clear_file; +use util::file::{check_not_symlink, clear_file}; use util::loop_context::{ gen_delete_notifiers, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; @@ -172,6 +172,7 @@ impl Chardev { } } ChardevType::File { path, .. } => { + check_not_symlink(Path::new(path))?; let file = Arc::new(Mutex::new( OpenOptions::new() .read(true) diff --git a/image/src/img.rs b/image/src/img.rs index 3e359a3fc2f5e076f6145df3cbc3c62bbce0e10e..1416409ca129a6ed0d96e0fe06596fe2a9c3dbd8 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -13,6 +13,7 @@ use std::{ fs::File, os::unix::prelude::{FileExt, OpenOptionsExt}, + path::Path, str::FromStr, sync::Arc, }; @@ -29,7 +30,7 @@ use block_backend::{ use machine_manager::config::{memory_unit_conversion, DiskFormat}; use util::{ aio::{Aio, AioEngine, WriteZeroesState}, - file::{lock_file, open_file, unlock_file}, + file::{check_not_symlink, lock_file, open_file, unlock_file}, }; enum SnapshotOperation { @@ -165,6 +166,7 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { } let path = create_options.path.clone(); + check_not_symlink(Path::new(&path))?; let file = Arc::new( std::fs::OpenOptions::new() .read(true) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index ce4c313b2f9733462d63d48b14a0f3e4bbd478bb..72a1ca99fad78a0ee3a73798b6811c73d3cf51ff 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -55,6 +55,7 @@ pub use sasl_auth::*; pub use smbios::*; #[cfg(feature = "vnc_auth")] pub use tls_creds::*; +use util::file::check_not_symlink; #[cfg(feature = "vnc")] pub use vnc::*; @@ -449,6 +450,7 @@ pub fn parse_bool(s: &str) -> Result { } fn enable_trace_state_from_file(path: &str) -> Result<()> { + check_not_symlink(Path::new(path))?; let mut file = File::open(path).with_context(|| format!("Failed to open {}", path))?; let mut buf = String::new(); file.read_to_string(&mut buf) diff --git a/migration/src/snapshot.rs b/migration/src/snapshot.rs index 3a449bad8a7213da886363fe1ae260d5a77803aa..7c91757c8e654d4f308e773d8532bb9af8eda491 100644 --- a/migration/src/snapshot.rs +++ b/migration/src/snapshot.rs @@ -16,6 +16,7 @@ use std::io::{Read, Write}; use std::path::PathBuf; use anyhow::{anyhow, bail, Context, Result}; +use util::file::check_not_symlink; use crate::general::{translate_id, Lifecycle}; use crate::manager::{MigrationManager, MIGRATION_MANAGER}; @@ -108,6 +109,7 @@ impl MigrationManager { } snapshot_path.push(MEMORY_PATH_SUFFIX); + check_not_symlink(snapshot_path.as_path())?; let mut memory_file = File::open(&snapshot_path).with_context(|| "Failed to open memory snapshot file")?; let memory_header = Self::restore_header(&mut memory_file)?; @@ -117,6 +119,7 @@ impl MigrationManager { } snapshot_path.pop(); snapshot_path.push(DEVICE_PATH_SUFFIX); + check_not_symlink(snapshot_path.as_path())?; let mut device_state_file = File::open(&snapshot_path) .with_context(|| "Failed to open device state snapshot file")?; let device_state_header = Self::restore_header(&mut device_state_file)?; diff --git a/util/src/daemonize.rs b/util/src/daemonize.rs index f693abb4e612d457816e500a4b1db942ce574d32..5ef67031c224a01a59e15a77bd5ba9a334170d17 100644 --- a/util/src/daemonize.rs +++ b/util/src/daemonize.rs @@ -41,12 +41,14 @@ use std::process::exit; use anyhow::{anyhow, Result}; +use crate::file::check_not_symlink; use crate::UtilError; /// Write process id to pid file. fn create_pid_file(path: &str) -> Result<()> { let pid: u32 = std::process::id(); + check_not_symlink(Path::new(path))?; let mut pid_file: File = OpenOptions::new() .write(true) .create(true) diff --git a/util/src/file.rs b/util/src/file.rs index bacce3db8369d7913694b3516f951ee6d4f747e3..cc9a2e897edc4d0e1ec8e0060cfa10f38888608f 100644 --- a/util/src/file.rs +++ b/util/src/file.rs @@ -38,6 +38,7 @@ pub fn open_file(path: &str, read_only: bool, direct: bool) -> Result { if direct { options.custom_flags(libc::O_DIRECT); } + check_not_symlink(Path::new(path))?; let file = options.open(path).with_context(|| { format!( "failed to open the file for block {}. Error: {}", @@ -182,3 +183,10 @@ pub fn clear_file(path: String) -> Result<()> { Ok(()) } + +pub fn check_not_symlink(path: &Path) -> Result<()> { + if path.is_symlink() { + bail!("{:?} is a symlink file and is not allowed to access!", path); + } + Ok(()) +} diff --git a/util/src/logger.rs b/util/src/logger.rs index c5f6aec7cf53b867ca1e579af4e537b49cd17cbf..16e7aa799b2e28bf21c1b3d3372d5bb884a95a9a 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -22,7 +22,10 @@ use anyhow::{Context, Result}; use log::{Level, LevelFilter, Log, Metadata, Record}; use nix::unistd::{getpid, gettid}; -use crate::time::{get_format_time, gettime}; +use crate::{ + file::check_not_symlink, + time::{get_format_time, gettime}, +}; // Max size of the log file is 100MB. const LOG_ROTATE_SIZE_MAX: usize = 100 * 1024 * 1024; @@ -191,6 +194,7 @@ fn init_logger_with_env(logfile: Box, logfile_path: String) -> } fn open_log_file(path: &str) -> Result { + check_not_symlink(Path::new(path))?; std::fs::OpenOptions::new() .read(false) .append(true)