summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorPascal Bach <pascal.bach@nextrem.ch>2018-07-20 21:59:16 +0200
committerPascal Bach <pascal.bach@nextrem.ch>2018-09-05 22:01:40 +0200
commita7fea44fe38b61a65ebc2d840c4c6c9e1bd8431d (patch)
treeefd7d1a498b8e9344452ba20d309751f441750e4 /test
parent81088abb3e257086f7dfc5810a363d28fea05706 (diff)
downloadnix-a7fea44fe38b61a65ebc2d840c4c6c9e1bd8431d.zip
Add wrapper for linux kernel module loading
- init_module and finit_module to load kernel modules - delete_module to unload kernel modules Signed-off-by: Pascal Bach <pascal.bach@nextrem.ch>
Diffstat (limited to 'test')
-rw-r--r--test/sys/test_select.rs1
-rw-r--r--test/test.rs3
-rw-r--r--test/test_kmod/hello_mod/Makefile7
-rw-r--r--test/test_kmod/hello_mod/hello.c26
-rw-r--r--test/test_kmod/mod.rs152
5 files changed, 188 insertions, 1 deletions
diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs
index 19d12fba..cf68700c 100644
--- a/test/sys/test_select.rs
+++ b/test/sys/test_select.rs
@@ -2,7 +2,6 @@ use nix::sys::select::*;
use nix::unistd::{pipe, write};
use nix::sys::signal::SigSet;
use nix::sys::time::{TimeSpec, TimeValLike};
-use std::os::unix::io::RawFd;
#[test]
pub fn test_pselect() {
diff --git a/test/test.rs b/test/test.rs
index 14f63e26..a91b6348 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -27,6 +27,9 @@ macro_rules! skip_if_not_root {
mod sys;
mod test_dir;
mod test_fcntl;
+#[cfg(any(target_os = "android",
+ target_os = "linux"))]
+mod test_kmod;
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "fushsia",
diff --git a/test/test_kmod/hello_mod/Makefile b/test/test_kmod/hello_mod/Makefile
new file mode 100644
index 00000000..74c99b77
--- /dev/null
+++ b/test/test_kmod/hello_mod/Makefile
@@ -0,0 +1,7 @@
+obj-m += hello.o
+
+all:
+ make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
+
+clean:
+ make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
diff --git a/test/test_kmod/hello_mod/hello.c b/test/test_kmod/hello_mod/hello.c
new file mode 100644
index 00000000..1c34987d
--- /dev/null
+++ b/test/test_kmod/hello_mod/hello.c
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+ or MIT
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+static int number= 1;
+static char *who = "World";
+
+module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(myint, "Just some number");
+module_param(who, charp, 0000);
+MODULE_PARM_DESC(who, "Whot to greet");
+
+int init_module(void)
+{
+ printk(KERN_INFO "Hello %s (%d)!\n", who, number);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO "Goodbye %s (%d)!\n", who, number);
+}
+
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs
new file mode 100644
index 00000000..e0cb0df5
--- /dev/null
+++ b/test/test_kmod/mod.rs
@@ -0,0 +1,152 @@
+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() {
+ skip_if_not_root!("test_finit_module");
+
+ 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() {
+ skip_if_not_root!("test_finit_module_with_params");
+
+ 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() {
+ skip_if_not_root!("test_init_module");
+
+ 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<u8> = 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() {
+ skip_if_not_root!("test_init_module");
+
+ 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<u8> = 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() {
+ skip_if_not_root!("test_finit_module_invalid");
+
+ 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() {
+ skip_if_not_root!("test_finit_module_twice_and_delete_module");
+
+ 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() {
+ skip_if_not_root!("test_delete_module_not_loaded");
+
+ let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
+
+ assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
+}