Skip to content

Commit

Permalink
Adding the cheriot tests to the test suite.
Browse files Browse the repository at this point in the history
Signed-off-by: Matthew A Johnson <matjoh@microsoft.com>
  • Loading branch information
matajoh committed Jun 6, 2024
1 parent 9cb7b03 commit 5289172
Show file tree
Hide file tree
Showing 18 changed files with 5,733 additions and 31 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ if (REGOCPP_BUILD_TESTS)
install(TARGETS rego_test rego_test_c_api RUNTIME)
install(FILES tests/regocpp.yaml tests/bigint.yaml tests/bugs.yaml DESTINATION tests)
install(DIRECTORY tests/aci DESTINATION tests)
install(DIRECTORY tests/cheriot DESTINATION tests)
endif()

export(EXPORT ${PROJECT_NAME}_Targets
Expand Down
4 changes: 2 additions & 2 deletions include/rego/rego.hh
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ namespace rego
| (Ref <<= RefHead * RefArgSeq)
| (RefHead <<= Var | Array | Object | Set | ArrayCompr | ObjectCompr | SetCompr | ExprCall)
| (RefArgSeq <<= (RefArgDot | RefArgBrack)++)
| (RefArgBrack <<= ExprInfix | Scalar | Var | Array | Object | Set | Placeholder)
| (RefArgBrack <<= Expr | Placeholder)
| (RefArgDot <<= Var)
| (Scalar <<= String | Int | Float | True | False | Null)
| (String <<= JSONString | RawString)
Expand Down Expand Up @@ -945,7 +945,7 @@ namespace rego
* This object can be used to register custom built-ins created using
* BuiltInDef::create.
*/
BuiltIns builtins() const;
BuiltInsDef& builtins() const;

private:
friend const char* ::regoGetError(regoInterpreter* rego);
Expand Down
10 changes: 10 additions & 0 deletions src/internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,16 @@ namespace rego
else
{
Node index = arg->front();
if(index == Expr)
{
index = index->front();
}

if (index == Term)
{
index = index->front();
}

if (index->type() == Scalar)
{
index = index->front();
Expand Down
4 changes: 2 additions & 2 deletions src/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,8 @@ namespace rego
return m_reader.wf_check_enabled();
}

BuiltIns Interpreter::builtins() const
BuiltInsDef& Interpreter::builtins() const
{
return m_builtins;
return *m_builtins;
}
}
7 changes: 0 additions & 7 deletions src/reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1452,13 +1452,6 @@ namespace
In(VarSeq) * (T(Term) << T(Var)[Var]) >>
[](Match& _) { return _(Var); },

In(RefArgBrack) *
(T(Expr) << (T(Term) << T(Scalar, Var, Object, Array, Set)[Idx])) >>
[](Match& _) { return _(Idx); },

In(RefArgBrack) * (T(Expr) << T(ExprInfix)[ExprInfix]) >>
[](Match& _) { return _(ExprInfix); },

In(RuleHead) * (T(RuleHeadComp) << End) >>
[](Match&) {
return RuleHeadComp
Expand Down
4 changes: 2 additions & 2 deletions src/rego_c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ extern "C"
void regoSetStrictBuiltInErrors(regoInterpreter* rego, regoBoolean enabled)
{
logging::Debug() << "regoSetStrictBuiltInErrors: " << enabled;
reinterpret_cast<rego::Interpreter*>(rego)->builtins()->strict_errors(
reinterpret_cast<rego::Interpreter*>(rego)->builtins().strict_errors(
enabled);
}

Expand All @@ -257,7 +257,7 @@ extern "C"
logging::Debug() << "regoGetStrictBuiltInErrors";
return reinterpret_cast<rego::Interpreter*>(rego)
->builtins()
->strict_errors();
.strict_errors();
}

// Output functions
Expand Down
2 changes: 1 addition & 1 deletion src/unify.hh
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ namespace rego
| (SetCompr <<= Expr * (Body >>= NestedBody))
| (RefTerm <<= Ref | Var)
| (NumTerm <<= Int | Float)
| (RefArgBrack <<= RefTerm | Scalar | Object | Array | Set | Expr)
| (RefArgBrack <<= RefTerm | NumTerm | Scalar | Object | Array | Set | Expr)
| (Expr <<= wf_symbols_exprs)
| (NestedBody <<= Key * (Val >>= UnifyBody))
;
Expand Down
13 changes: 10 additions & 3 deletions src/unify/symbols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -436,16 +436,23 @@ namespace rego
return NumTerm << _(Val);
},

In(RefArgBrack) * T(Var)[Var] >>
In(RefArgBrack) * (T(Expr) << T(RefTerm, NumTerm)[Term]) >>
[](Match& _) {
ACTION();
return _(Term);
},

In(RefArgBrack) * T(Var)[Var] >>
[](Match& _){
ACTION();
return RefTerm << _(Var);
},

In(RefArgBrack) * T(ExprInfix)[ExprInfix] >>
In(RefArgBrack) *
(T(Expr) << (T(Term) << T(Scalar, Object, Array, Set)[Term])) >>
[](Match& _) {
ACTION();
return Expr << _(ExprInfix);
return _(Term);
},

In(UnifyBody) *
Expand Down
5 changes: 4 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
add_executable(rego_test main.cc test_case.cc)
add_executable(rego_test main.cc test_case.cc cheriot/builtins.cpp)
target_link_libraries(rego_test
PRIVATE
regocpp::rego)
Expand All @@ -16,6 +16,7 @@ endif()
add_test(NAME rego_test_regocpp COMMAND rego_test regocpp.yaml -wf WORKING_DIRECTORY $<TARGET_FILE_DIR:rego_test>)
add_test(NAME rego_test_bugs COMMAND rego_test bugs.yaml -wf WORKING_DIRECTORY $<TARGET_FILE_DIR:rego_test>)
add_test(NAME rego_test_aci COMMAND rego_test aci/aci.yaml WORKING_DIRECTORY $<TARGET_FILE_DIR:rego_test>)
add_test(NAME rego_test_cheriot COMMAND rego_test cheriot/cheriot.yaml -wf WORKING_DIRECTORY $<TARGET_FILE_DIR:rego_test>)
add_test(NAME rego_test_c_api COMMAND rego_test_c_api WORKING_DIRECTORY $<TARGET_FILE_DIR:rego_test>)
set_tests_properties(rego_test_aci PROPERTIES TIMEOUT 300)

Expand All @@ -25,6 +26,8 @@ add_custom_command(TARGET rego_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bugs.yaml $<TARGET_FILE_DIR:rego_test>/bugs.yaml)
add_custom_command(TARGET rego_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/aci $<TARGET_FILE_DIR:rego_test>/aci)
add_custom_command(TARGET rego_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/cheriot $<TARGET_FILE_DIR:rego_test>/cheriot)

if(REGOCPP_OPA_TESTS)
set( OPA_TEST_DIRS
Expand Down
181 changes: 181 additions & 0 deletions tests/cheriot/builtins.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#include "../rego_test.h"

#include <charconv>
#include <cxxabi.h>

namespace
{
using namespace rego;

/**
* Built-in function exposed to Rego for demangling the symbol names in
* export entries. Takes two arguments, the compartment name and the
* mangled symbol name.
*/
Node demangle_export(const Nodes& args)
{
Node exportName = unwrap_arg(args, UnwrapOpt(1).types({JSONString}));
if (exportName->type() == Error)
{
return scalar(false);
}
Node compartmentName = unwrap_arg(args, UnwrapOpt(0).types({JSONString}));
if (compartmentName->type() == Error)
{
return scalar(false);
}
auto string = get_string(exportName);
auto compartmentNameString = get_string(compartmentName);
const std::string_view LibraryExportPrefix = "__library_export_libcalls";
const std::string_view ExportPrefix = "__export_";
if (string.starts_with(LibraryExportPrefix))
{
string = string.substr(LibraryExportPrefix.size());
}
else
{
if (!string.starts_with(ExportPrefix))
{
return scalar(false);
}
string = string.substr(ExportPrefix.size());
if (!string.starts_with(compartmentNameString))
{
return scalar(false);
}
string = string.substr(compartmentNameString.size());
}
if (!string.starts_with("_"))
{
return scalar(false);
}
string = string.substr(1);
// The way that rego-cpp exposes snmalloc can cause the realloc here to
// crash. Try to allocate a buffer that's large enough that we don't
// care.
size_t bufferSize = strlen(string.c_str()) * 8;
char* buffer = static_cast<char*>(malloc(bufferSize));
int error;
buffer = abi::__cxa_demangle(string.c_str(), buffer, &bufferSize, &error);
if (error != 0)
{
free(buffer);
return scalar(false);
}
std::string demangled(buffer);
free(buffer);
return scalar(std::move(demangled));
}

/**
* Helper that decodes the hex strings emitted for static sealed objects.
* These are written as sequences of bytes, with a space between each four
* bytes.
*
* Takes a node that must have been unwrapped to a JSONString.
*/
std::vector<uint8_t> decode_hex_node(const Node& node)
{
if (node->type() == Error)
{
return {};
}
auto hexString = get_string(node);
std::vector<uint8_t> result;
while (hexString.size() >= 8)
{
for (size_t i = 0; i < 8; i += 2)
{
uint8_t byte;
auto [p, ec] = std::from_chars(
hexString.data() + i, hexString.data() + i + 2, byte, 16);
if (ec != std::errc{})
{
return {};
}
result.push_back(byte);
}
hexString = hexString.substr(8);
if (hexString.size() > 0 && hexString[0] == ' ')
{
hexString = hexString.substr(1);
}
}
return result;
}

/**
* Built-in function exposed to Rego for decoding a hex string into an
* integer.
*
* Takes three arguments:
* 1. The hex string to decode
* 2. The offset in the string to start decoding
* 3. The number of bytes to decode
*
* The third argument must be 1, 2, 3, or 4 bytes (3 does not make sense,
* but it's easier to allow it than exclude it). This corresponds to
* uint8_t, uint16_t, and uint32_t in the source.
*/
Node decode_integer(const Nodes& args)
{
auto bytes =
decode_hex_node(unwrap_arg(args, UnwrapOpt(0).types({JSONString})));
auto offsetNode = unwrap_arg(args, UnwrapOpt(1).types({Int}));
auto lengthNode = unwrap_arg(args, UnwrapOpt(2).types({Int}));
if ((offsetNode->type() == Error) || (lengthNode->type() == Error))
{
return scalar(false);
}
size_t offset = get_int(offsetNode).to_int();
size_t length = get_int(lengthNode).to_int();
uint32_t result = 0;
size_t end = offset + length;
if ((length > 4) || (end > bytes.size()))
{
return scalar(false);
}
for (size_t i = 0; i < length; i++)
{
result |= (bytes[offset + i] << (i * 8));
}
return scalar(BigInt{int64_t(result)});
}

/**
* Built-in function exposed to Rego for decoding a hex string containing a
* C string into a Rego string. This takes two arguments, the hex string
* and the offset where the C string starts.
*/
Node decode_c_string(const Nodes& args)
{
auto bytes =
decode_hex_node(unwrap_arg(args, UnwrapOpt(0).types({JSONString})));
auto offsetNode = unwrap_arg(args, UnwrapOpt(1).types({Int}));
size_t offset = get_int(offsetNode).to_int();
std::string result;
if (offset >= bytes.size())
{
return scalar(false);
}
for (auto it = bytes.begin() + offset; (it != bytes.end()) && (*it != '\0');
it++)
{
result.push_back(*it);
}
return scalar(std::move(result));
}
}

namespace rego_test
{
std::vector<BuiltIn> cheriot_builtins()
{
return {
BuiltInDef::create(Location("export_entry_demangle"), 2, demangle_export),
BuiltInDef::create(
Location("integer_from_hex_string"), 3, decode_integer),
BuiltInDef::create(
Location("string_from_hex_string"), 2, decode_c_string)};
}
}
41 changes: 41 additions & 0 deletions tests/cheriot/cheriot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
cases:
- note: Check that we can demangle a library export correctly
modules:
- compartment.rego
data: sail.yaml
input: test-suite.json
query: data.compartment.compartment_call_allow_list("allocator_test", `test_allocator\(\)`, {"test_runner"}) = x
want_result:
- x : true
- note: Check that we can demangle a compartment export correctly
modules:
- compartment.rego
data: sail.yaml
input: test-suite.json
query: export_entry_demangle("alloc", input.compartments.allocator.exports[6].export_symbol) = x
want_result:
- x: heap_free(SObjStruct*, void*)
- note: Check that we can demangle a library export correctly
modules:
- compartment.rego
data: sail.yaml
input: test-suite.json
query: export_entry_demangle("token_library", input.compartments.token_library.exports[0].export_symbol) = x
want_result:
- x: token_obj_unseal(SKeyStruct*, SObjStruct*)
- note: Check that we can demangle a library export correctly
modules:
- compartment.rego
data: sail.yaml
input: test-suite.json
query: data.compartment.mmio_allow_list("clint", {"scheduler"}) = x
want_result:
- x: true
- note: Check that we can demangle a library export correctly.
modules:
- rtos.rego
data: sail.yaml
input: test-suite.json
query: sum([ data.rtos.decode_allocator_capability(c).quota | c = input.compartments[_].imports[_] ; data.rtos.is_allocator_capability(c) ]) = x
want_result:
- x: 1070080
Loading

0 comments on commit 5289172

Please sign in to comment.