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

Adding the cheriot-audit tests to the test suite #144

Closed
wants to merge 1 commit into from
Closed
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
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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this code come from cheriot? Do we need some attribution here?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is our SPDX header:

// Copyright SCI Semiconductor and CHERIoT Contributors.
// SPDX-License-Identifier: MIT


#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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aiming to fix this with microsoft/Trieste#117

// 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
Loading