forked from vbpf/ebpf-verifier
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make the JIT'd code completely portable. (vbpf#427)
Signed-off-by: Will Hawkins <[email protected]> Co-authored-by: Alan Jowett <[email protected]>
- Loading branch information
1 parent
cb77dbe
commit ec13a3a
Showing
38 changed files
with
2,149 additions
and
383 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Copyright (c) Microsoft Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
set(CMAKE_CXX_STANDARD 20) | ||
|
||
file(GLOB test_descr_files ${CMAKE_SOURCE_DIR}/custom_tests/descrs/*.md) | ||
|
||
add_library(ubpf_custom_test_support srcs/ubpf_custom_test_support.cc) | ||
|
||
target_link_libraries( | ||
ubpf_custom_test_support | ||
ubpf | ||
ubpf_settings | ||
) | ||
|
||
target_include_directories(ubpf_custom_test_support PUBLIC ".srcs/") | ||
target_include_directories(ubpf_custom_test_support PRIVATE | ||
"${CMAKE_SOURCE_DIR}/vm" | ||
"${CMAKE_BINARY_DIR}/vm" | ||
"${CMAKE_SOURCE_DIR}/vm/inc" | ||
"${CMAKE_BINARY_DIR}/vm/inc" | ||
) | ||
|
||
set(QEMU_RUNNER "") | ||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 AND (NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL aarch64)) | ||
set(QEMU_RUNNER qemu-aarch64 -L /usr/aarch64-linux-gnu) | ||
endif() | ||
|
||
foreach(test_file ${test_descr_files}) | ||
get_filename_component(test_name ${test_file} NAME_WE) | ||
set(test_source_path "${CMAKE_SOURCE_DIR}/custom_tests/srcs/${test_name}.cc") | ||
|
||
add_executable( | ||
${test_name} | ||
${test_source_path} | ||
) | ||
target_include_directories(${test_name} PRIVATE | ||
"${CMAKE_SOURCE_DIR}/vm" | ||
"${CMAKE_BINARY_DIR}/vm" | ||
"${CMAKE_SOURCE_DIR}/vm/inc" | ||
"${CMAKE_BINARY_DIR}/vm/inc" | ||
) | ||
target_link_libraries( | ||
${test_name} | ||
ubpf | ||
ubpf_custom_test_support | ||
ubpf_settings | ||
) | ||
set(potential_input_file ${CMAKE_SOURCE_DIR}/custom_tests/data/${test_name}.input) | ||
if (EXISTS ${potential_input_file}) | ||
list(JOIN QEMU_RUNNER " " QEMU_RUNNER_STR) | ||
add_test( | ||
NAME ${test_name}-Custom | ||
COMMAND sh -c "cat ${potential_input_file} | ${QEMU_RUNNER_STR} $<TARGET_FILE:${test_name}>" | ||
) | ||
else() | ||
add_test( | ||
NAME ${test_name}-Custom | ||
COMMAND ${QEMU_RUNNER} $<TARGET_FILE:${test_name}> | ||
) | ||
endif() | ||
endforeach() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
## Writing a uBPF Custom Tests | ||
|
||
Custom tests are enabled by creating two (2) or three (3) different files in the `custom_tests` directory. | ||
|
||
### Files Of a uBPF Custom Test | ||
|
||
#### Description Files | ||
|
||
The first file to create is the Description File. The Description File is a file with a `.md` extension that resides in the `descrs` directory. The purpose of this file is to identify the name of the test (everything before the `.md` extension) and provide a place to document the purpose of the test. | ||
|
||
#### Source Files | ||
|
||
The second file to create is the Source File. The Source file should reside in the `srcs` directory and have a name that matches its Description File (with the `.cc` extension rather than the `.md` extension). | ||
|
||
#### Input Files | ||
|
||
The final file is optional. The Input File resides in the `data` directory and should have the same name as the other two (2) files but with an `.input` extension rather than `.cc` or `.md` for the Source and Description File respectively. If present, the contents of this file will be given to the executed custom test over standard input. | ||
|
||
### Building | ||
|
||
The Source Files for a custom test are compiled using C++20 and are saved as an executable named according to the name of the test in the CMake build directory. | ||
|
||
### Return Values | ||
|
||
All successful tests should return `0`. All failing tests should return something other than `0`. | ||
|
||
### Supporting Libraries | ||
|
||
To reduce the boilerplate needed to write custom tests, there is a custom test library with several helpful functions. These functions are documented in the library's header file (`custom_tests/srcs/ubpf_custom_test_support.h`). | ||
|
||
### Putting It Together | ||
|
||
After describing the test's purpose in a Markdown syntax in a file named, say, `test_example.md` and stored in the `descrs` directory, you can write the test's Source Code (in C++20) and give it the name `test_example.cc` in the `srcs` directory. If the test needs input, you can save that input in the tests Input File (`test_input.input`) in the `data` directory. | ||
|
||
Because all the files are present, this test will be run when the CTest target is invoked. Because there the optional `test_input.input` file is present, the contents of that file will be given to the executable via standard input. |
1 change: 1 addition & 0 deletions
1
custom_tests/data/ubpf_test_external_dispatcher_context_overwrite.input
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
b7 01 00 00 01 02 03 04 85 00 00 00 01 00 00 00 95 00 00 00 00 00 00 00 |
1 change: 1 addition & 0 deletions
1
custom_tests/data/ubpf_test_external_dispatcher_simple_context.input
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
85 00 00 00 01 00 00 00 95 00 00 00 00 00 00 00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
8f 00 00 00 01 00 00 00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
85 00 00 00 01 00 00 00 95 00 00 00 00 00 00 00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
85 00 00 00 01 00 00 00 95 00 00 00 00 00 00 00 |
7 changes: 7 additions & 0 deletions
7
custom_tests/descrs/ubpf_test_external_dispatcher_context_overwrite.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
## Test Description | ||
|
||
This custom test program tests whether JIT'd eBPF programs properly pass the original context | ||
to external helper dispatcher even when (eBPF) register r0 has been modified. The original | ||
context to the eBPF program is passed in (eBPF) register r0. Subsequent changes to that | ||
register by the eBPF program should *not* affect that context (which is given to the | ||
helper function external dispatcher). |
4 changes: 4 additions & 0 deletions
4
custom_tests/descrs/ubpf_test_external_dispatcher_simple_context.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## Test Description | ||
|
||
This custom test program tests whether JIT'd eBPF programs properly pass the context | ||
to external helper dispatcher. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## Test Description | ||
|
||
This custom test program tests whether compilation fails (with the proper error message) when | ||
the user gives a buffer that is too small to accommodate the size of the JIT'd code. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## Test Description | ||
|
||
This custom test program tests that an eBPF program fails to load (with the proper error) in | ||
the presence of a program with an invalid instruction opcode. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## Test Description | ||
|
||
This custom test program tests whether it is possible to update the external helper dispatcher | ||
after an eBPF program has been compiled. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## Test Description | ||
|
||
This custom test program tests whether it is possible to update the external helper | ||
functions for an eBPF program that has already been JIT'd. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#pragma once | ||
#include "ubpf.h" | ||
#include <string.h> | ||
#include <cmath> | ||
#include <cstdint> | ||
#include <map> | ||
|
||
#if !defined(UNREFERENCED_PARAMETER) | ||
#define UNREFERENCED_PARAMETER(P) (void)(P) | ||
#endif | ||
|
||
static uint64_t | ||
gather_bytes(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
return ((uint64_t)(a & 0xff) << 32) | ((uint64_t)(b & 0xff) << 24) | ((uint64_t)(c & 0xff) << 16) | | ||
((uint64_t)(d & 0xff) << 8) | (e & 0xff); | ||
}; | ||
|
||
static uint64_t | ||
memfrob(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
|
||
uint8_t* p = reinterpret_cast<uint8_t*>(a); | ||
for (uint64_t i = 0; i < b; i++) { | ||
p[i] ^= 42; | ||
} | ||
return 0; | ||
}; | ||
|
||
; | ||
|
||
static uint64_t | ||
no_op(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
|
||
return 0; | ||
} | ||
|
||
static uint64_t | ||
sqrti(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
|
||
return static_cast<uint64_t>(std::sqrt(a)); | ||
} | ||
|
||
static uint64_t | ||
strcmp_ext(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return strcmp(reinterpret_cast<char*>(a), reinterpret_cast<char*>(b)); | ||
} | ||
|
||
static uint64_t | ||
unwind(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return a; | ||
} | ||
|
||
static std::map<uint32_t, external_function_t> helper_functions = { | ||
{0, gather_bytes}, | ||
{1, memfrob}, | ||
{2, no_op}, | ||
{3, sqrti}, | ||
{4, strcmp_ext}, | ||
{5, unwind}, | ||
}; | ||
|
||
static uint64_t | ||
dispatcher_test_memfrob(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 42; | ||
|
||
} | ||
|
||
static uint64_t | ||
updated_dispatcher_test_memfrob(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 43; | ||
} | ||
|
||
static uint64_t | ||
dispatcher_gather_bytes(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 44; | ||
|
||
} | ||
|
||
static uint64_t | ||
updated_dispatcher_gather_bytes(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 45; | ||
} | ||
|
||
static uint64_t | ||
dispatcher_no_op(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 46; | ||
|
||
} | ||
|
||
static uint64_t | ||
updated_dispatcher_no_op(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 47; | ||
} | ||
|
||
static uint64_t | ||
dispatcher_sqrti(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 48; | ||
|
||
} | ||
|
||
static uint64_t | ||
updated_dispatcher_sqrti(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 49; | ||
} | ||
|
||
static uint64_t | ||
dispatcher_strcmp_ext(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 50; | ||
|
||
} | ||
|
||
static uint64_t | ||
updated_dispatcher_strcmp_ext(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 51; | ||
} | ||
|
||
static uint64_t | ||
dispatcher_unwind(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 52; | ||
|
||
} | ||
|
||
static uint64_t | ||
updated_dispatcher_unwind(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) | ||
{ | ||
UNREFERENCED_PARAMETER(a); | ||
UNREFERENCED_PARAMETER(b); | ||
UNREFERENCED_PARAMETER(c); | ||
UNREFERENCED_PARAMETER(d); | ||
UNREFERENCED_PARAMETER(e); | ||
return 53; | ||
} |
Oops, something went wrong.