diff --git a/build.rs b/build.rs index 7d537493..485e56d0 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,7 @@ use std::io::{BufRead, BufReader}; -use std::path::PathBuf; +use std::path::{Path,PathBuf}; use std::{env, fs}; +use std::ffi::OsStr; const INCLUDED_TYPES: &[&str] = &["file_system_type", "mode_t", "umode_t", "ctl_table"]; const INCLUDED_FUNCTIONS: &[&str] = &[ @@ -111,9 +112,22 @@ fn handle_kernel_symbols_cfg(symvers_path: &PathBuf) { } } +// Alist of plugin basename (without .so) to whether it leaves the ABI unchanged. See +// https://github.com/fishinabarrel/linux-kernel-module-rust/issues/152#issuecomment-671219181 +const KNOWN_PLUGINS: &[(&str, bool)] = &[ + ("cyc_complexity_plugin", true), + ("latent_entropy_plugin", true), + ("sancov_plugin", true), + ("structleak_plugin", true), + ("randomize_layout_plugin", false), + ("stackleak_plugin", true), + ("arm_ssp_per_task_plugin", true), +]; + // Takes the CFLAGS from the kernel Makefile and changes all the include paths to be absolute -// instead of relative. -fn prepare_cflags(cflags: &str, kernel_dir: &str) -> Vec { +// instead of relative. Also, filter out arguments to load or configure plugins and throw an error +// if the requested plugin would change the ABI. +fn prepare_cflags(cflags: &str, kernel_dir: &str) -> Option> { let cflag_parts = shlex::split(&cflags).unwrap(); let mut cflag_iter = cflag_parts.iter(); let mut kernel_args = vec![]; @@ -128,11 +142,34 @@ fn prepare_cflags(cflags: &str, kernel_dir: &str) -> Vec { } else { kernel_args.push(format!("{}/{}", kernel_dir, include_path)); } + } else if arg.starts_with("-fplugin=") { +continue; + let plugin_filename = arg.strip_prefix("-fplugin=").unwrap(); + let plugin_basename = Path::new(&plugin_filename).file_stem().unwrap(); + for (known_plugin, abi_safe) in KNOWN_PLUGINS { + if plugin_basename == OsStr::new(known_plugin) { + if !abi_safe { + eprintln!("Your kernel uses the {:?} plugin, which changes the ABI in a way we can't handle :(", plugin_basename); + return None; + } + if known_plugin == &"stackleak_plugin" { + println!("cargo:warning=Rust code will not call stackleak, potentially weakining stackleak's protection."); + } + continue; + } + } + eprintln!("Your kernel uses the {:?} plugin, which we don't know about.", plugin_basename); + eprintln!("Edit linux-kernel-module-rust/build.rs if it doesn't change the ABI."); + return None; + } else if arg.starts_with("-fplugin-arg-") { + continue; } else { kernel_args.push(arg.to_string()); } } - kernel_args +kernel_args.push("-USTRUCTLEAK_PLUGIN".to_owned()); +kernel_args.push("-DMODULE".to_owned()); + Some(kernel_args) } fn main() { @@ -143,7 +180,8 @@ fn main() { let kernel_dir = env::var("abs_srctree").expect("Must be invoked from kernel makefile"); let kernel_cflags = env::var("c_flags").expect("Add 'export c_flags' to Kbuild"); - let kernel_args = prepare_cflags(&kernel_cflags, &kernel_dir); + let kernel_args = + prepare_cflags(&kernel_cflags, &kernel_dir).unwrap_or_else(|| std::process::exit(1)); let target = env::var("TARGET").unwrap(); diff --git a/hello-world/Kbuild b/hello-world/Kbuild index dfac1853..fda3a181 100644 --- a/hello-world/Kbuild +++ b/hello-world/Kbuild @@ -1,6 +1,8 @@ obj-m := helloworld.o helloworld-objs := hello_world.rust.o +c_flags := $(filter-out -fplugin-%,${c_flags}) + CARGO ?= cargo export c_flags diff --git a/hello-world/Makefile b/hello-world/Makefile index 4677c5f6..d12b3cf2 100644 --- a/hello-world/Makefile +++ b/hello-world/Makefile @@ -6,7 +6,7 @@ CC := ${CLANG} endif all: - $(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC) CONFIG_CC_IS_CLANG=y + $(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC) CONFIG_CC_IS_CLANG=y cmd_cc_o_c='$$(CC) $$(filter-out -D%_PLUGIN,$$(filter-out -fplugin%,$$(c_flags))) -c -o $$@ $$<' clean: $(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC) clean