Skip to content

Commit

Permalink
Add wrapper for linux kernel module loading
Browse files Browse the repository at this point in the history
- init_module and finit_module to load kernel modules
- delete_module to unload kernel modules
  • Loading branch information
bachp committed Jul 23, 2018
1 parent 237ec7b commit 43210ab
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/kmod.rs
Original file line number Diff line number Diff line change
@@ -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<u8> = 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<T: AsRawFd>(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)
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 43210ab

Please sign in to comment.