use std::fs::copy; use std::path::PathBuf; use std::process::Command; use tempfile::{tempdir, TempDir}; fn compile_kernel_module() -> (PathBuf, String, TempDir) { let _m = ::FORK_MTX .lock() .expect("Mutex got poisoned by another test"); let tmp_dir = tempdir().expect("unable to create temporary build directory"); copy( "test/test_kmod/hello_mod/hello.c", &tmp_dir.path().join("hello.c"), ).expect("unable to copy hello.c to temporary build directory"); copy( "test/test_kmod/hello_mod/Makefile", &tmp_dir.path().join("Makefile"), ).expect("unable to copy Makefile to temporary build directory"); let status = Command::new("make") .current_dir(tmp_dir.path()) .status() .expect("failed to run make"); assert!(status.success()); // Return the relative path of the build kernel module (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir) } use nix::errno::Errno; use nix::kmod::{delete_module, DeleteModuleFlags}; use nix::kmod::{finit_module, init_module, ModuleInitFlags}; use nix::Error; use std::ffi::CString; use std::fs::File; use std::io::Read; #[test] fn test_finit_and_delete_module() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); let f = File::open(kmod_path).expect("unable to open kernel module"); finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) .expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), ).expect("unable to unload kernel module"); } #[test] fn test_finit_and_delete_modul_with_params() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); let f = File::open(kmod_path).expect("unable to open kernel module"); finit_module( &f, &CString::new("who=Rust number=2018").unwrap(), ModuleInitFlags::empty(), ).expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), ).expect("unable to unload kernel module"); } #[test] fn test_init_and_delete_module() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); let mut f = File::open(kmod_path).expect("unable to open kernel module"); let mut contents: Vec = Vec::new(); f.read_to_end(&mut contents) .expect("unable to read kernel module content to buffer"); init_module(&mut contents, &CString::new("").unwrap()).expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), ).expect("unable to unload kernel module"); } #[test] fn test_init_and_delete_module_with_params() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); let mut f = File::open(kmod_path).expect("unable to open kernel module"); let mut contents: Vec = Vec::new(); f.read_to_end(&mut contents) .expect("unable to read kernel module content to buffer"); init_module(&mut contents, &CString::new("who=Nix number=2015").unwrap()) .expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), ).expect("unable to unload kernel module"); } #[test] fn test_finit_module_invalid() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let kmod_path = "/dev/zero"; let f = File::open(kmod_path).expect("unable to open kernel module"); let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL)); } #[test] fn test_finit_module_twice_and_delete_module() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); let f = File::open(kmod_path).expect("unable to open kernel module"); finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) .expect("unable to load kernel module"); let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST)); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), ).expect("unable to unload kernel module"); } #[test] fn test_delete_module_not_loaded() { require_capability!(CAP_SYS_MODULE); let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty()); assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT)); }