1 use std::fs::copy;
2 use std::path::PathBuf;
3 use std::process::Command;
4 use tempfile::{tempdir, TempDir};
5 
compile_kernel_module() -> (PathBuf, String, TempDir)6 fn compile_kernel_module() -> (PathBuf, String, TempDir) {
7     let _m = ::FORK_MTX
8         .lock()
9         .expect("Mutex got poisoned by another test");
10 
11     let tmp_dir = tempdir().expect("unable to create temporary build directory");
12 
13     copy(
14         "test/test_kmod/hello_mod/hello.c",
15         &tmp_dir.path().join("hello.c"),
16     ).expect("unable to copy hello.c to temporary build directory");
17     copy(
18         "test/test_kmod/hello_mod/Makefile",
19         &tmp_dir.path().join("Makefile"),
20     ).expect("unable to copy Makefile to temporary build directory");
21 
22     let status = Command::new("make")
23         .current_dir(tmp_dir.path())
24         .status()
25         .expect("failed to run make");
26 
27     assert!(status.success());
28 
29     // Return the relative path of the build kernel module
30     (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir)
31 }
32 
33 use nix::errno::Errno;
34 use nix::kmod::{delete_module, DeleteModuleFlags};
35 use nix::kmod::{finit_module, init_module, ModuleInitFlags};
36 use nix::Error;
37 use std::ffi::CString;
38 use std::fs::File;
39 use std::io::Read;
40 
41 #[test]
test_finit_and_delete_module()42 fn test_finit_and_delete_module() {
43     require_capability!(CAP_SYS_MODULE);
44     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
45     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
46 
47     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
48 
49     let f = File::open(kmod_path).expect("unable to open kernel module");
50     finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
51         .expect("unable to load kernel module");
52 
53     delete_module(
54         &CString::new(kmod_name).unwrap(),
55         DeleteModuleFlags::empty(),
56     ).expect("unable to unload kernel module");
57 }
58 
59 #[test]
test_finit_and_delete_modul_with_params()60 fn test_finit_and_delete_modul_with_params() {
61     require_capability!(CAP_SYS_MODULE);
62     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
63     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
64 
65     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
66 
67     let f = File::open(kmod_path).expect("unable to open kernel module");
68     finit_module(
69         &f,
70         &CString::new("who=Rust number=2018").unwrap(),
71         ModuleInitFlags::empty(),
72     ).expect("unable to load kernel module");
73 
74     delete_module(
75         &CString::new(kmod_name).unwrap(),
76         DeleteModuleFlags::empty(),
77     ).expect("unable to unload kernel module");
78 }
79 
80 #[test]
test_init_and_delete_module()81 fn test_init_and_delete_module() {
82     require_capability!(CAP_SYS_MODULE);
83     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
84     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
85 
86     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
87 
88     let mut f = File::open(kmod_path).expect("unable to open kernel module");
89     let mut contents: Vec<u8> = Vec::new();
90     f.read_to_end(&mut contents)
91         .expect("unable to read kernel module content to buffer");
92     init_module(&mut contents, &CString::new("").unwrap()).expect("unable to load kernel module");
93 
94     delete_module(
95         &CString::new(kmod_name).unwrap(),
96         DeleteModuleFlags::empty(),
97     ).expect("unable to unload kernel module");
98 }
99 
100 #[test]
test_init_and_delete_module_with_params()101 fn test_init_and_delete_module_with_params() {
102     require_capability!(CAP_SYS_MODULE);
103     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
104     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
105 
106     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
107 
108     let mut f = File::open(kmod_path).expect("unable to open kernel module");
109     let mut contents: Vec<u8> = Vec::new();
110     f.read_to_end(&mut contents)
111         .expect("unable to read kernel module content to buffer");
112     init_module(&mut contents, &CString::new("who=Nix number=2015").unwrap())
113         .expect("unable to load kernel module");
114 
115     delete_module(
116         &CString::new(kmod_name).unwrap(),
117         DeleteModuleFlags::empty(),
118     ).expect("unable to unload kernel module");
119 }
120 
121 #[test]
test_finit_module_invalid()122 fn test_finit_module_invalid() {
123     require_capability!(CAP_SYS_MODULE);
124     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
125     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
126 
127     let kmod_path = "/dev/zero";
128 
129     let f = File::open(kmod_path).expect("unable to open kernel module");
130     let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
131 
132     assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
133 }
134 
135 #[test]
test_finit_module_twice_and_delete_module()136 fn test_finit_module_twice_and_delete_module() {
137     require_capability!(CAP_SYS_MODULE);
138     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
139     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
140 
141     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
142 
143     let f = File::open(kmod_path).expect("unable to open kernel module");
144     finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
145         .expect("unable to load kernel module");
146 
147     let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
148 
149     assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST));
150 
151     delete_module(
152         &CString::new(kmod_name).unwrap(),
153         DeleteModuleFlags::empty(),
154     ).expect("unable to unload kernel module");
155 }
156 
157 #[test]
test_delete_module_not_loaded()158 fn test_delete_module_not_loaded() {
159     require_capability!(CAP_SYS_MODULE);
160     let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
161     let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
162 
163     let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
164 
165     assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
166 }
167