From 43210ab72e0ff0031bb49635a5ae882fcf524bc0 Mon Sep 17 00:00:00 2001 From: Pascal Bach Date: Fri, 20 Jul 2018 21:59:16 +0200 Subject: [PATCH] Add wrapper for linux kernel module loading - init_module and finit_module to load kernel modules - delete_module to unload kernel modules --- src/kmod.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 2 files changed, 92 insertions(+) create mode 100644 src/kmod.rs diff --git a/src/kmod.rs b/src/kmod.rs new file mode 100644 index 0000000000..a25f50393c --- /dev/null +++ b/src/kmod.rs @@ -0,0 +1,90 @@ +//! Load and unload kernel modules. + +use libc; +use std::os::unix::io::AsRawFd; +use std::ffi::CStr; + +use errno::Errno; +use Result; + +/// Loads an ELF image into kernel space, performs any necessary symbol relocations, +/// initializes module parameters to values provided by the caller, and then runs the module's init function. +/// This function requires privilege. +/// +/// The module_image argument points to a buffer containing the binary image to be loaded. +/// The module image should be a valid ELF image, built for the running kernel. +/// +/// The param_values argument is a string containing space-delimited specifications of the values for module parameters. +/// Each of the parameter specifications has the form: +/// +/// `name[=value[,value...]]` +/// +/// Example usage: +/// +/// ``` +/// let mut f = File::open("mykernel.ko").unwrap(); +/// let mut contents: Vec = Vec::new(); +/// f.read_to_end(&mut contents).unwrap(); +/// init_module(&mut contents, &CString::new("").unwrap()).unwrap(); +/// ``` +/// +pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> { + let res = unsafe { + libc::syscall( + libc::SYS_init_module, + module_image.as_ptr(), + module_image.len(), + param_values.as_ptr(), + ) + }; + + Errno::result(res).map(drop) +} + + +libc_bitflags!( + /// Flags used by the `finit_module` function. + pub struct ModuleInitFlags: libc::c_uint { + /// Ignore symbol version hashes. + MODULE_INIT_IGNORE_MODVERSIONS; + /// Ignore kernel version magic. + MODULE_INIT_IGNORE_VERMAGIC; + } +); + +/// Loads a kernel module from a given file descriptor. +/// +/// Example usage: +/// +/// ``` +/// let f = File::open("mymod.ko").unwrap(); +/// finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()).unwrap(); +/// ``` +/// +pub fn finit_module(fd: &T, param_values: &CStr, flags:ModuleInitFlags) -> Result<()> { + let res = unsafe { libc::syscall(libc::SYS_finit_module, fd.as_raw_fd(), param_values.as_ptr(), flags.bits()) }; + + Errno::result(res).map(drop) +} + +libc_bitflags!( + /// Flags used by `delete_module`. + pub struct OFlags: libc::c_int { + O_NONBLOCK; + O_TRUNC; + } +); + +/// Unloads the kernel module with the given name. +/// +/// Example usage: +/// +/// ``` +/// delete_module(&CString::new("mymod").unwrap(), OFlags::O_NONBLOCK).unwrap(); +/// ``` +/// +pub fn delete_module(name: &CStr, flags: OFlags) -> Result<()> { + let res = unsafe { libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) }; + + Errno::result(res).map(drop) +} diff --git a/src/lib.rs b/src/lib.rs index 07e84c1272..6aa4a41641 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,8 @@ pub mod fcntl; target_os = "openbsd"))] pub mod ifaddrs; #[cfg(any(target_os = "linux", target_os = "android"))] +pub mod kmod; +#[cfg(any(target_os = "linux", target_os = "android"))] pub mod mount; #[cfg(any(target_os = "dragonfly", target_os = "freebsd",