Fix mprotect failures by enabling cranelift-jit selinux-fix (#5204)

The sample program in cranelift/filetests/src/function_runner.rs
would abort with an mprotect failure under certain circumstances,
see https://github.com/bytecodealliance/wasmtime/pull/4453#issuecomment-1303803222

Root cause was that enabling PROT_EXEC on the main process heap
may be prohibited, depending on Linux distro and version.

This only shows up in the doc test sample program because the main
clif-util is multi-threaded and therefore allocations will happen
on glibc's per-thread heap, which is allocated via mmap, and not
the main process heap.

Work around the problem by enabling the "selinux-fix" feature of
the cranelift-jit crate dependency in the filetests.  Note that
this didn't compile out of the box, so a separate fix is also
required and provided as part of this PR.

Going forward, it would be preferable to always use mmap to allocate
the backing memory for JITted code.
This commit is contained in:
Ulrich Weigand
2022-11-04 22:01:37 +01:00
committed by GitHub
parent d3a6181939
commit fba2287c54
2 changed files with 7 additions and 7 deletions

View File

@@ -16,7 +16,7 @@ cranelift-interpreter = { workspace = true }
cranelift-native = { workspace = true } cranelift-native = { workspace = true }
cranelift-reader = { workspace = true } cranelift-reader = { workspace = true }
cranelift-preopt = { workspace = true } cranelift-preopt = { workspace = true }
cranelift-jit = { workspace = true } cranelift-jit = { workspace = true, features = ["selinux-fix"] }
cranelift-module = { workspace = true } cranelift-module = { workspace = true }
file-per-thread-logger = "0.1.2" file-per-thread-logger = "0.1.2"
filecheck = "0.5.0" filecheck = "0.5.0"

View File

@@ -1,6 +1,6 @@
use cranelift_module::{ModuleError, ModuleResult}; use cranelift_module::{ModuleError, ModuleResult};
#[cfg(feature = "selinux-fix")] #[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))]
use memmap2::MmapMut; use memmap2::MmapMut;
#[cfg(not(any(feature = "selinux-fix", windows)))] #[cfg(not(any(feature = "selinux-fix", windows)))]
@@ -14,7 +14,7 @@ use wasmtime_jit_icache_coherence as icache_coherence;
/// A simple struct consisting of a pointer and length. /// A simple struct consisting of a pointer and length.
struct PtrLen { struct PtrLen {
#[cfg(feature = "selinux-fix")] #[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))]
map: Option<MmapMut>, map: Option<MmapMut>,
ptr: *mut u8, ptr: *mut u8,
@@ -25,7 +25,7 @@ impl PtrLen {
/// Create a new empty `PtrLen`. /// Create a new empty `PtrLen`.
fn new() -> Self { fn new() -> Self {
Self { Self {
#[cfg(feature = "selinux-fix")] #[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))]
map: None, map: None,
ptr: ptr::null_mut(), ptr: ptr::null_mut(),
@@ -250,10 +250,10 @@ impl Memory {
fn non_protected_allocations_iter(&self) -> impl Iterator<Item = &PtrLen> { fn non_protected_allocations_iter(&self) -> impl Iterator<Item = &PtrLen> {
let iter = self.allocations[self.already_protected..].iter(); let iter = self.allocations[self.already_protected..].iter();
#[cfg(feature = "selinux-fix")] #[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))]
return iter.filter(|&PtrLen { ref map, len, .. }| len != 0 && map.is_some()); return iter.filter(|&PtrLen { ref map, len, .. }| *len != 0 && map.is_some());
#[cfg(not(feature = "selinux-fix"))] #[cfg(any(target_os = "windows", not(feature = "selinux-fix")))]
return iter.filter(|&PtrLen { len, .. }| *len != 0); return iter.filter(|&PtrLen { len, .. }| *len != 0);
} }