Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

c_no_std binding to show use in C freestanding environments. #238

Merged
merged 1 commit into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ Cargo.lock
.vscode/

# worktrees
worktrees/
worktrees/

# build folders
**/build
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ jsonwebtoken = { version = "9.2.0", optional = true }
itertools = { version = "0.12.1", default-features = false, optional = true }

serde_yaml = {version = "0.9.16", default-features = false, optional = true }
rand = { version = "0.8.5", default-features = false, optional = true }
rand = { version = "0.8.5", default-features = false, optional = true }

[dev-dependencies]
anyhow = "1.0.45"
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

Regorus is also
- *cross-platform* - Written in platform-agnostic Rust.
- *no_std compatible* - Regorus can be used in `no_std` environments too. Most of the builtins are supported.
- *current* - We strive to keep Regorus up to date with latest OPA release. Regorus supports `import rego.v1`.
- *compliant* - Regorus is mostly compliant with the latest [OPA release v0.64.0](https://github.com/open-policy-agent/opa/releases/tag/v0.64.0). See [OPA Conformance](#opa-conformance) for details. Note that while we behaviorally produce the same results, we don't yet support all the builtins.
- *extensible* - Extend the Rego language by implementing custom stateful builtins in Rust.
Expand Down Expand Up @@ -85,7 +86,7 @@ Regorus is designed with [Confidential Computing](https://confidentialcomputing.
it is important to be able to control exactly what is being run. Regorus allows enabling and disabling various components using cargo
features. By default all features are enabled.

The default build of regorus example program is 6.4M:
The default build of regorus example program is 6.3M:
```bash
$ cargo build -r --example regorus; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
-rwxr-xr-x 1 anand staff 6.3M May 11 22:03 target/release/examples/regorus*
Expand All @@ -108,6 +109,7 @@ Regorus can be used from a variety of languages:
- *C*: C binding is generated using [cbindgen](https://github.com/mozilla/cbindgen).
[corrosion-rs](https://github.com/corrosion-rs/corrosion) can be used to seamlessly use Regorous
in your CMake based projects. See [bindings/c](https://github.com/microsoft/regorus/tree/main/bindings/c).
- *C freestanding*: [bindings/c_no_std](https://github.com/microsoft/regorus/tree/main/bindings/c_no_std) shows how to use Regorus from C environments without a libc.
- *C++*: C++ binding is generated using [cbindgen](https://github.com/mozilla/cbindgen).
[corrosion-rs](https://github.com/corrosion-rs/corrosion) can be used to seamlessly use Regorous
in your CMake based projects. See [bindings/cpp](https://github.com/microsoft/regorus/tree/main/bindings/cpp).
Expand Down
41 changes: 41 additions & 0 deletions bindings/c-nostd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (c) Microsoft
# Licensed under the MIT License.

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
include(FetchContent)

FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.4 # Optionally specify a commit hash, version tag or branch here
)
FetchContent_MakeAvailable(Corrosion)

project("regorus-test")

corrosion_import_crate(
# Path to <regorus-source-folder>/bindings/ffi/Cargo.toml
MANIFEST_PATH "../ffi/Cargo.toml"
# Always build regorus in Release mode.
PROFILE "release"
# Only build the "regorus-ffi" crate.
CRATES "regorus-ffi"

# Turn off std support in regorus-ffi.
NO_DEFAULT_FEATURES
NO_STD

# custom_allocator allows using a custom memory allocator.
# To use malloc/free remove custom_allocator below.
# Additionally, select specific features in regorus.
# See regorus/opa_no_std
FEATURES "custom_allocator,regorus/semver"

# Link statically
CRATE_TYPES staticlib FLAGS --crate-type=staticlib
)

add_executable(regorus_test_nostd main.c)
# Add path to <regorus-source-folder>/bindings/ffi
target_include_directories(regorus_test_nostd PRIVATE "../ffi")
target_link_libraries(regorus_test_nostd regorus-ffi)
96 changes: 96 additions & 0 deletions bindings/c-nostd/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <stdio.h>
#include "regorus.h"


// Regorus has been built for no_std and cannot access files.
char* file_to_string(const char* file) {
char * buffer = 0;
long length;
FILE * f = fopen (file, "rb");

if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}

return buffer;
}

// If regorus is built with custom-allocator, then provide implementation.
uint8_t* regorus_aligned_alloc(size_t alignment, size_t size) {
printf("%ld %ld\n", size, alignment);
fflush(stdout);
return aligned_alloc(alignment, size);
}

void regorus_free(uint8_t* ptr) {
free(ptr);
}


int main() {
// Create engine.
RegorusEngine* engine = regorus_engine_new();
RegorusResult r;
char* buffer = NULL;

// Load policies.
r = regorus_engine_add_policy(engine, "framework.rego", (buffer = file_to_string("../../../tests/aci/framework.rego")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
regorus_result_drop(r);

r = regorus_engine_add_policy(engine, "api.rego", (buffer = file_to_string("../../../tests/aci/api.rego")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
regorus_result_drop(r);

r = regorus_engine_add_policy(engine, "policy.rego", (buffer = file_to_string("../../../tests/aci/policy.rego")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
regorus_result_drop(r);

// Add data
r = regorus_engine_add_data_json(engine, (buffer = file_to_string("../../../tests/aci/data.json")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
regorus_result_drop(r);

// Set input
r = regorus_engine_set_input_json(engine, (buffer = file_to_string("../../../tests/aci/input.json")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
regorus_result_drop(r);

// Eval query
r = regorus_engine_eval_query(engine, "data.framework.mount_overlay=x");
if (r.status != RegorusStatusOk)
goto error;

// Print output
printf("%s", r.output);
regorus_result_drop(r);


// Free the engine.
regorus_engine_drop(engine);

return 0;
error:
printf("%s", r.error_message);

return 1;
}
11 changes: 9 additions & 2 deletions bindings/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ corrosion_import_crate(
MANIFEST_PATH "../ffi/Cargo.toml"
# Always build regorus in Release mode.
PROFILE "release"
# Only build the "regorusc" crate.
CRATES "regorus-ffi")
# Only build the "regorus-ffi" crate.
CRATES "regorus-ffi"

# Select specific features in regorus.
FEATURES "regorus/semver"

# Link statically
CRATE_TYPES "staticlib"
)

add_executable(regorus_test main.c)
# Add path to <regorus-source-folder>/bindings/ffi
Expand Down
9 changes: 7 additions & 2 deletions bindings/ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
crate-type = ["cdylib", "staticlib"]

[dependencies]
anyhow = "1.0"
regorus = { path = "../.." }
regorus = { path = "../..", default-features = false }
serde_json = "1.0.113"

[features]
default = ["std"]
std = ["regorus/std"]
custom_allocator = []

[build-dependencies]
cbindgen = "0.26.0"
csbindgen = "1.9.0"
1 change: 0 additions & 1 deletion bindings/ffi/RegorusFFI.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,3 @@ internal enum RegorusStatus : uint


}

5 changes: 1 addition & 4 deletions bindings/ffi/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,6 @@ bitflags = false






############## Options for How Your Rust library Should Be Parsed ##############

[parse]
Expand All @@ -154,5 +151,5 @@ extra_bindings = []
[parse.expand]
crates = []
all_features = false
default_features = true
default_features = false
features = []
4 changes: 4 additions & 0 deletions bindings/ffi/regorus.ffi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ RegorusResult regorus_engine_set_input_from_json_file(RegorusEngine *engine, con
/// * `query`: Rego expression to be evaluate.
RegorusResult regorus_engine_eval_query(RegorusEngine *engine, const char *query);

extern uint8_t *regorus_aligned_alloc(uintptr_t alignment, uintptr_t size);

extern void regorus_free(uint8_t *ptr);

} // extern "C"

#endif // REGORUS_FFI_HPP
4 changes: 4 additions & 0 deletions bindings/ffi/regorus.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,8 @@ struct RegorusResult regorus_engine_set_input_from_json_file(struct RegorusEngin
*/
struct RegorusResult regorus_engine_eval_query(struct RegorusEngine *engine, const char *query);

extern uint8_t *regorus_aligned_alloc(uintptr_t alignment, uintptr_t size);

extern void regorus_free(uint8_t *ptr);

#endif /* REGORUS_H */
33 changes: 32 additions & 1 deletion bindings/ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
///
/// * `path`: A filename to be associated with the policy.
/// * `rego`: Rego policy.

#[no_mangle]
pub extern "C" fn regorus_engine_add_policy(
engine: *mut RegorusEngine,
Expand All @@ -141,6 +140,7 @@ pub extern "C" fn regorus_engine_add_policy(
}())
}

#[cfg(feature = "std")]
#[no_mangle]
pub extern "C" fn regorus_engine_add_policy_from_file(
engine: *mut RegorusEngine,
Expand Down Expand Up @@ -169,6 +169,7 @@ pub extern "C" fn regorus_engine_add_data_json(
}())
}

#[cfg(feature = "std")]
#[no_mangle]
pub extern "C" fn regorus_engine_add_data_from_json_file(
engine: *mut RegorusEngine,
Expand Down Expand Up @@ -209,6 +210,7 @@ pub extern "C" fn regorus_engine_set_input_json(
}())
}

#[cfg(feature = "std")]
#[no_mangle]
pub extern "C" fn regorus_engine_set_input_from_json_file(
engine: *mut RegorusEngine,
Expand Down Expand Up @@ -246,3 +248,32 @@ pub extern "C" fn regorus_engine_eval_query(
Err(e) => to_regorus_result(Err(e)),
}
}

#[cfg(feature = "custom_allocator")]
extern "C" {
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;
fn regorus_free(ptr: *mut u8);
}

#[cfg(feature = "custom_allocator")]
mod allocator {
use std::alloc::{GlobalAlloc, Layout};

struct RegorusAllocator {}

unsafe impl GlobalAlloc for RegorusAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let size = layout.size();
let align = layout.align();

crate::regorus_aligned_alloc(align, size)
}

unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
crate::regorus_free(ptr)
}
}

#[global_allocator]
static ALLOCATOR: RegorusAllocator = RegorusAllocator {};
}
Loading