Skip to content

Commit

Permalink
Glue code for using snmalloc in EDP
Browse files Browse the repository at this point in the history
  • Loading branch information
Jethro Beekman committed May 2, 2024
1 parent 092e963 commit 8841b4d
Show file tree
Hide file tree
Showing 11 changed files with 383 additions and 3 deletions.
22 changes: 21 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CFLAGS_x86_64_fortanix_unknown_sgx: "-isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening"
# CXXFLAGS is set below
CC_x86_64_fortanix_unknown_sgx: clang-11
CXX_x86_64_fortanix_unknown_sgx: clang++-11

jobs:
test:
Expand Down Expand Up @@ -48,7 +50,7 @@ jobs:
rustup update
- name: Cargo test --all --exclude sgxs-loaders
run: cargo test --verbose --locked --all --exclude sgxs-loaders --exclude async-usercalls && [ "$(echo $(nm -D target/debug/sgx-detect|grep __vdso_sgx_enter_enclave))" = "w __vdso_sgx_enter_enclave" ]
run: true || ( cargo test --verbose --locked --all --exclude sgxs-loaders --exclude async-usercalls --exclude snmalloc-edp && [ "$(echo $(nm -D target/debug/sgx-detect|grep __vdso_sgx_enter_enclave))" = "w __vdso_sgx_enter_enclave" ] )

- name: cargo test -p async-usercalls --target x86_64-fortanix-unknown-sgx --no-run
run: cargo +nightly test --verbose --locked -p async-usercalls --target x86_64-fortanix-unknown-sgx --no-run
Expand Down Expand Up @@ -96,6 +98,24 @@ jobs:
- name: Build em-app, get-certificate for x86_64-fortanix-unknown-sgx
run: cargo build --verbose --locked -p em-app -p get-certificate --target=x86_64-fortanix-unknown-sgx

- name: Build snmalloc-edp
run: |
git submodule update --init --recursive
detect_cxx_include_path() {
for path in $(clang++-12 -print-search-dirs|sed -n 's/^libraries:\s*=//p'|tr : ' '); do
num_component="$(basename "$path")"
if [[ "$num_component" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
if [[ "$(basename "$(dirname "$path")")" == 'x86_64-linux-gnu' ]]; then
echo $num_component
return
fi
fi
done
exit 1
}
export CXXFLAGS_x86_64_fortanix_unknown_sgx="-cxx-isystem/usr/include/c++/$(detect_cxx_include_path) -cxx-isystem/usr/include/x86_64-linux-gnu/c++/$(detect_cxx_include_path) $CFLAGS_x86_64_fortanix_unknown_sgx"
cargo build --verbose --locked -p snmalloc-edp --target=x86_64-fortanix-unknown-sgx
- name: Generate API docs
run: ./doc/generate-api-docs.sh

Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "snmalloc-edp/snmalloc"]
path = snmalloc-edp/snmalloc
url = https://github.com/microsoft/snmalloc
11 changes: 9 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ members = [
"intel-sgx/sgxs",
"ipc-queue",
"rs-libc",
"snmalloc-edp",
]
exclude = [
"examples/backtrace_panic",
Expand Down
10 changes: 10 additions & 0 deletions snmalloc-edp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.14)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
project(snmalloc-edp CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SNMALLOC_HEADER_ONLY_LIBRARY ON)
add_subdirectory(snmalloc EXCLUDE_FROM_ALL)
add_library(snmalloc-edp src/rust-sgx-snmalloc-shim.cpp)
target_link_libraries(snmalloc-edp PRIVATE snmalloc_lib)
target_compile_options(snmalloc-edp PRIVATE -nostdlib -ffreestanding -fno-exceptions -mrdrnd -fPIC)
11 changes: 11 additions & 0 deletions snmalloc-edp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "snmalloc-edp"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

build = "build.rs"

[build-dependencies]
cmake = "0.1.50"
5 changes: 5 additions & 0 deletions snmalloc-edp/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
let mut dst = cmake::build(".");
dst.push("build");
println!("cargo:rustc-link-search=native={}", dst.display());
}
1 change: 1 addition & 0 deletions snmalloc-edp/snmalloc
Submodule snmalloc added at dc1268
24 changes: 24 additions & 0 deletions snmalloc-edp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![no_std]

use core::ffi::c_void;

#[repr(C)]
pub struct Alloc {
_data: [u8; 0],
_marker:
core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

#[link(name = "snmalloc-edp", kind = "static")]
extern {
pub fn sn_global_init(heap_start_address: *mut c_void, heap_end_address: *mut c_void);
pub fn sn_thread_init(allocator: *mut Alloc);
pub fn sn_thread_cleanup(allocator: *mut Alloc);
pub static sn_alloc_size: usize;
pub static sn_alloc_align: usize;

pub fn sn_rust_alloc(alignment: usize, size: usize) -> *mut u8;
pub fn sn_rust_alloc_zeroed(alignment: usize, size: usize) -> *mut u8;
pub fn sn_rust_dealloc(ptr: *mut u8, alignment: usize, size: usize);
pub fn sn_rust_realloc(ptr: *mut u8, alignment: usize, old_size: usize, new_size: usize) -> *mut u8;
}
187 changes: 187 additions & 0 deletions snmalloc-edp/src/rust-sgx-snmalloc-shim.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Open Enclave SDK contributors.
// Copyright (c) 2020 SchrodingerZhu
// Copyright (c) Fortanix, Inc.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE

#include <immintrin.h>
#include <string.h>

/***************************************************/
/*** Imported symbols needed by snmalloc SGX PAL ***/
/***************************************************/

// from entry.S
extern "C" size_t get_tcs_addr();

// from Rust std
extern "C" void __rust_print_err(const char *m, size_t s);
extern "C" [[noreturn]] void __rust_abort();

/*******************************************************/
/*** Standard C functions needed by snmalloc SGX PAL ***/
/*******************************************************/

// definition needs to match GNU header
extern "C" [[noreturn]] void abort() __THROW {
__rust_abort();
}

// definition needs to match GNU header
extern "C" inline int * __attribute_const__ __errno_location (void) __THROW {
static int errno;
return &errno;
}

/***********************************/
/*** snmalloc SGX PAL definition ***/
/***********************************/

#define SNMALLOC_PROVIDE_OWN_CONFIG
#define SNMALLOC_SGX
#define SNMALLOC_USE_SMALL_CHUNKS
#define SNMALLOC_MEMORY_PROVIDER PALEdpSgx
#define OPEN_ENCLAVE
// needed for openenclave header:
#define OE_OK 0

#include "../snmalloc/src/snmalloc/pal/pal_noalloc.h"

namespace snmalloc {
void register_clean_up() {
// TODO: not sure what this is supposed to do
abort();
}

class EdpErrorHandler {
public:
static void print_stack_trace() {}

[[noreturn]] static void error(const char *const str) {
__rust_print_err(str, strlen(str));
abort();
}
static constexpr size_t address_bits = Aal::address_bits;
static constexpr size_t page_size = Aal::smallest_page_size;
};

using EdpBasePAL = PALNoAlloc<EdpErrorHandler>;

class PALEdpSgx : public EdpBasePAL {
public:
using ThreadIdentity = size_t;
static constexpr uint64_t pal_features = EdpBasePAL::pal_features | Entropy;

template <bool page_aligned = false>
static void zero(void *p, size_t size) noexcept {
memset(p, 0, size);
}

static inline uint64_t get_entropy64() {
long long unsigned int result = 0;
while (_rdrand64_step(&result) != 1)
;
return result;
}

static inline ThreadIdentity get_tid() noexcept {
return (size_t)get_tcs_addr();
}
};
} // namespace snmalloc

/**************************************/
/*** Instantiation of the allocator ***/
/**************************************/

#include "../snmalloc/src/snmalloc/backend/fixedglobalconfig.h"
#include "../snmalloc/src/snmalloc/snmalloc_core.h"

using namespace snmalloc;

using Globals = FixedRangeConfig<PALEdpSgx>;
using Alloc = LocalAllocator<Globals>;

/// Do global initialization for snmalloc. Should be called exactly once prior
/// to any other snmalloc function calls.
// TODO: this function shouldn't need the addresses passed in, these can be
// obtained from the HEAP_* symbols
extern "C" void sn_global_init(void *heap_start_address,
void *heap_end_address) {
size_t _max_heap_size =
static_cast<size_t>(static_cast<uint8_t *>(heap_end_address) -
static_cast<uint8_t *>(heap_start_address));

Globals::init(nullptr, heap_start_address, _max_heap_size);
}

/// Construct a thread-local allocator object in place
extern "C" void sn_thread_init(Alloc* allocator) {
new(allocator) Alloc();
allocator->init();
}

/// Destruct a thread-local allocator object in place
extern "C" void sn_thread_cleanup(Alloc* allocator) {
allocator->teardown();
allocator->~Alloc();
}

extern "C" size_t sn_alloc_size = sizeof(Alloc);
extern "C" size_t sn_alloc_align = alignof(Alloc);

/// Return a pointer to a thread-local allocator object of size
/// `sn_alloc_size` and alignment `sn_alloc_align`.
extern "C" Alloc* __rust_get_thread_allocator();

/******************************************************/
/*** Rust-compatible shims for the global allocator ***/
/******************************************************/

extern "C" void *sn_rust_alloc(size_t alignment, size_t size) {
return __rust_get_thread_allocator()->alloc(aligned_size(alignment, size));
}

extern "C" void *sn_rust_alloc_zeroed(size_t alignment, size_t size) {
return __rust_get_thread_allocator()->alloc<YesZero>(
aligned_size(alignment, size));
}

extern "C" void sn_rust_dealloc(void *ptr, size_t alignment, size_t size) {
__rust_get_thread_allocator()->dealloc(ptr, aligned_size(alignment, size));
}

extern "C" void *sn_rust_realloc(void *ptr, size_t alignment, size_t old_size,
size_t new_size) {
size_t aligned_old_size = aligned_size(alignment, old_size),
aligned_new_size = aligned_size(alignment, new_size);
if (size_to_sizeclass_full(aligned_old_size).raw() ==
size_to_sizeclass_full(aligned_new_size).raw())
return ptr;
Alloc* allocator = __rust_get_thread_allocator();
void *p = allocator->alloc(aligned_new_size);
if (p) {
std::memcpy(p, ptr, old_size < new_size ? old_size : new_size);
allocator->dealloc(ptr, aligned_old_size);
}
return p;
}
Loading

0 comments on commit 8841b4d

Please sign in to comment.