From e4f8a66a778966c2cae3aeecbfc8da91cc4ae9b5 Mon Sep 17 00:00:00 2001 From: Douglas Raillard Date: Thu, 28 Nov 2024 12:16:25 +0000 Subject: [PATCH 1/2] lisa._assets.kmodules.lisa: Compat with old kernels APIs FIX Some kernel APIs have changed over time, especially around const-correctness. Add a CONST_CAST() macro to deal with such API change. --- .../lisa/rust/lisakmod/src/runtime/sysfs.rs | 6 ++++- lisa/_assets/kmodules/lisa/utils.h | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lisa/_assets/kmodules/lisa/rust/lisakmod/src/runtime/sysfs.rs b/lisa/_assets/kmodules/lisa/rust/lisakmod/src/runtime/sysfs.rs index 65d3dec75..79ec73f10 100644 --- a/lisa/_assets/kmodules/lisa/rust/lisakmod/src/runtime/sysfs.rs +++ b/lisa/_assets/kmodules/lisa/rust/lisakmod/src/runtime/sysfs.rs @@ -112,13 +112,17 @@ impl KObjectInner { r#" #include #include + #include "#; r#" // memset() is necessary here, otherwise kobj->name stays uninitialized and that leads // to crashes when calling kobject_add() since it tries to free the previous name. memset(kobj, 0, sizeof(*kobj)); - kobject_init(kobj, kobj_type); + + // Some old kernels (e.g. 5.15) don't have a const qualifier for kobj_type, so we cast + // it away with the warnings disabled to avoid hitting -Werror + kobject_init(kobj, CONST_CAST(struct kobj_type*, kobj_type)); "# } // Increase refcount since we are going to keep a pointer to KObjType. We decrement it diff --git a/lisa/_assets/kmodules/lisa/utils.h b/lisa/_assets/kmodules/lisa/utils.h index c7ab03cea..6666fa0a5 100644 --- a/lisa/_assets/kmodules/lisa/utils.h +++ b/lisa/_assets/kmodules/lisa/utils.h @@ -12,4 +12,27 @@ #include "linux/kernel.h" +#define IGNORE_WARNING(warning, expr) ({ \ + __diag_push(); \ + __diag(ignored warning); \ + typeof(expr) ___expression_value = expr; \ + __diag_pop(); \ + ___expression_value; \ +}) + +#ifdef __clang__ +# define PER_COMPILER(clang, gcc) clang +#else +# define PER_COMPILER(clang, gcc) gcc +#endif + +/// CONST_CAST - Same as C++ const_cast<> +#define CONST_CAST(type, expr) IGNORE_WARNING( \ + PER_COMPILER( \ + "-Wincompatible-pointer-types-discards-qualifiers", \ + "-Wignored-qualifiers" \ + ), \ + (type)(expr) \ +) + #endif /* _UTILS_H */ -- GitLab From 6090ce3a06d6711fda9cfd1822ddc9e364782592 Mon Sep 17 00:00:00 2001 From: Douglas Raillard Date: Thu, 28 Nov 2024 15:13:34 +0000 Subject: [PATCH 2/2] lisa._assets.kmodules.lisa: Compat with old CFI FIX Before the current kCFI implementation, older kernels were using the CFI sanitizer. The end result is similar but the implementation is more complex than kCFI and requires a special attributes for C functions that have their address taken in Rust code, and then executed by C again. This happens for callbacks, e.g. the release callback in struct kobj_type. See: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-cfi-canonical-jump-tables --- .../lisakmod-macros/macros/src/inlinec.rs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lisa/_assets/kmodules/lisa/rust/lisakmod-macros/macros/src/inlinec.rs b/lisa/_assets/kmodules/lisa/rust/lisakmod-macros/macros/src/inlinec.rs index 920fab601..eb5b64b28 100644 --- a/lisa/_assets/kmodules/lisa/rust/lisakmod-macros/macros/src/inlinec.rs +++ b/lisa/_assets/kmodules/lisa/rust/lisakmod-macros/macros/src/inlinec.rs @@ -125,14 +125,16 @@ fn make_c_func( f_generics: Option<&Generics>, f_args: &[(Ident, Type)], f_ret_ty: &Type, + c_attrs: Vec, c_code: ( Option, Option, Option, ), ) -> Result { - let (c_out, c_header_out, rust_out) = - _make_c_func(rust_name, c_name, f_generics, f_args, f_ret_ty, c_code)?; + let (c_out, c_header_out, rust_out) = _make_c_func( + rust_name, c_name, f_generics, f_args, f_ret_ty, c_attrs, c_code, + )?; let c_out = [ make_c_out(c_out, &format!(".binstore.c.code.{}", c_name))?, @@ -151,6 +153,7 @@ fn _make_c_func( f_generics: Option<&Generics>, f_args: &[(Ident, Type)], f_ret_ty: &Type, + mut c_attrs: Vec, c_code: ( Option, Option, @@ -254,6 +257,10 @@ fn _make_c_func( None => quote! {""}, }; + // Disabling CFI inside the function allows us to call anything we want, including Rust + // functions if needed. + c_attrs.push(quote!{"__nocfi"}); + let c_header_out = concatcp(quote! { r#" #include @@ -264,6 +271,13 @@ fn _make_c_func( #define CONST_TY_DECL(declarator) const declarator #define ATTR_TY_DECL(attributes, declarator) attributes declarator #define FN_TY_DECL(args, declarator) ((declarator)args) + + /* On recent kernels, kCFI is used instead of CFI and __cficanonical is therefore not + * defined anymore + */ + #ifndef __cficanonical + # define __cficanonical + #endif "#, "#line ", #c_code_line, " \"", file!(), "\"\n", @@ -279,7 +293,7 @@ fn _make_c_func( } get() }, - "\n#define ", #c_proto, " ", #c_ret_ty, "(FN_TY_DECL((", #c_args, "), ATTR_TY_DECL(__nocfi, ", #c_name_str, ")))", + "\n#define ", #c_proto, " ", #c_ret_ty, "(FN_TY_DECL((", #c_args, "), ATTR_TY_DECL(", #(#c_attrs, " ",)* ", ", #c_name_str, ")))", "\n#line ", #c_code_line, " \"", file!(), "\"\n", #c_proto, ";\n", })?; @@ -327,6 +341,7 @@ pub fn cfunc(_attrs: TokenStream, code: TokenStream) -> Result Result Result