Update verifier to include changes to check ctx mismatches (#106)
Signed-off-by: Dave Thaler <dthaler@ntdev.microsoft.com>
This commit is contained in:
Родитель
88cd4bf3cb
Коммит
39c1819f18
162
docs/tutorial.md
162
docs/tutorial.md
|
@ -1,6 +1,6 @@
|
||||||
# 1. Introduction
|
# 1. Introduction
|
||||||
|
|
||||||
This tutorial illustrates how eBPF works and how to run eBPF verifier on Windows,
|
This tutorial illustrates how eBPF works and in particular how the eBPF verifier works on Windows,
|
||||||
starting from authoring a new eBPF program in C.
|
starting from authoring a new eBPF program in C.
|
||||||
|
|
||||||
To try out this tutorial yourself, you should first install the [Prerequisites](GettingStarted.md#Prerequisites).
|
To try out this tutorial yourself, you should first install the [Prerequisites](GettingStarted.md#Prerequisites).
|
||||||
|
@ -215,8 +215,15 @@ in the specified subdirectory ("external\ebpf-verifier\build").
|
||||||
|
|
||||||
**Step 3)** Build the solution:
|
**Step 3)** Build the solution:
|
||||||
|
|
||||||
This can be done from within the Visual Studio UI as follows.
|
This can be done either from the command line or from within the Visual Studio UI.
|
||||||
First, open the solution in Visual Studio:
|
|
||||||
|
To use the command line:
|
||||||
|
|
||||||
|
```
|
||||||
|
> msbuild /m /p:Configuration=Debug /p:Platform=x64 ebpf-for-windows.sln
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, to use the Visual Studio UI, open the solution in Visual Studio:
|
||||||
|
|
||||||
```
|
```
|
||||||
> ebpf-for-windows.sln
|
> ebpf-for-windows.sln
|
||||||
|
@ -230,9 +237,9 @@ Building the solution may generate some compiler warnings, but should still
|
||||||
compile successfully.
|
compile successfully.
|
||||||
|
|
||||||
|
|
||||||
# 4. Installing eBPF on Windows
|
# 4. Installing the eBPF netsh helper on Windows
|
||||||
|
|
||||||
Now we're ready to learn how to use eBPF on Windows. Let's first install the `netsh` helper.
|
Now we're ready to learn how to use eBPF on Windows. For this tutorial, we only need to install the `netsh` helper.
|
||||||
From an Admin command shell, do the following from your ebpf-for-windows directory:
|
From an Admin command shell, do the following from your ebpf-for-windows directory:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -240,7 +247,11 @@ From an Admin command shell, do the following from your ebpf-for-windows directo
|
||||||
> netsh add helper %windir%\system32\ebpfnetsh.dll
|
> netsh add helper %windir%\system32\ebpfnetsh.dll
|
||||||
```
|
```
|
||||||
|
|
||||||
# 5. Running eBPF on Windows
|
# 5. Verifying eBPF programs on Windows
|
||||||
|
|
||||||
|
Normally verification happens at the time an eBPF program is submitted to be loaded. That can be done,
|
||||||
|
but in this tutorial, we'll just do verification _without_ needing to load the program. This allows this
|
||||||
|
tutorial to be done on any machine, not just one with the eBPF driver installed into the kernel.
|
||||||
|
|
||||||
**Step 1)** Enumerate sections
|
**Step 1)** Enumerate sections
|
||||||
|
|
||||||
|
@ -450,7 +461,7 @@ is commonly used to designate which hook point the eBPF program is designed
|
||||||
for. Specifically, a set of prefix strings are used to match against the
|
for. Specifically, a set of prefix strings are used to match against the
|
||||||
section name. For example, any section name starting with "xdp" is meant
|
section name. For example, any section name starting with "xdp" is meant
|
||||||
as an XDP layer program. This is a convenient default, but can be
|
as an XDP layer program. This is a convenient default, but can be
|
||||||
overridden by an app, such as when the eBPF program is simply in the
|
overridden by an app asking to load an eBPF program, such as when the eBPF program is simply in the
|
||||||
".text" section.
|
".text" section.
|
||||||
|
|
||||||
Each hook point has a specified prototype which must be understood by the
|
Each hook point has a specified prototype which must be understood by the
|
||||||
|
@ -506,7 +517,7 @@ this info is in the [windows_platform.cpp](../src/ebpf/libs/api/windows_platform
|
||||||
which for the above prototype might have:
|
which for the above prototype might have:
|
||||||
|
|
||||||
```
|
```
|
||||||
constexpr EbpfContextDescriptor xdp_context_descriptor = {
|
const EbpfContextDescriptor g_xdp_context_descriptor = {
|
||||||
24, // Size of ctx struct.
|
24, // Size of ctx struct.
|
||||||
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
||||||
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
||||||
|
@ -515,13 +526,13 @@ constexpr EbpfContextDescriptor xdp_context_descriptor = {
|
||||||
|
|
||||||
const EbpfProgramType windows_xdp_program_type =
|
const EbpfProgramType windows_xdp_program_type =
|
||||||
PTYPE("xdp", // Just for printing messages to users.
|
PTYPE("xdp", // Just for printing messages to users.
|
||||||
xdp_context_descriptor,
|
&g_xdp_context_descriptor,
|
||||||
EBPF_PROG_TYPE_XDP,
|
EBPF_PROG_TYPE_XDP,
|
||||||
{"xdp"}); // Set of section name prefixes for matching.
|
{"xdp"}); // Set of section name prefixes for matching.
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's look at the code above in more detail. The EbpfContextDescriptor
|
Let's look at the code above in more detail. The EbpfContextDescriptor
|
||||||
info (i.e., `xdp_context_descriptor`) tells the verifier about the format
|
info (i.e., `g_xdp_context_descriptor`) tells the verifier about the format
|
||||||
of the context structure (i.e., `struct ebpf_xdp_args`). The struct is
|
of the context structure (i.e., `struct ebpf_xdp_args`). The struct is
|
||||||
24 bytes long, includes packet data, and so the scalar fields that
|
24 bytes long, includes packet data, and so the scalar fields that
|
||||||
are safe to access start at offset 16.
|
are safe to access start at offset 16.
|
||||||
|
@ -581,23 +592,27 @@ Now that we've seen how hooks work, let's look at how calls from an eBPF
|
||||||
program into helper functions exposed by the system are verified.
|
program into helper functions exposed by the system are verified.
|
||||||
As with hook prototypes, the set of helper functions and their prototypes
|
As with hook prototypes, the set of helper functions and their prototypes
|
||||||
can vary by platform. For comparison, helpers for Linux are documented in the
|
can vary by platform. For comparison, helpers for Linux are documented in the
|
||||||
[IOVisor docs](https://github.com/iovisor/bpf-docs/blob/master/bpf_helpers.rst).
|
[IOVisor bpf helpers documentation](https://github.com/iovisor/bpf-docs/blob/master/bpf_helpers.rst).
|
||||||
|
|
||||||
Let's say the following helper function prototype is exposed by Windows:
|
Let's say the following helper function prototype is exposed by Windows:
|
||||||
|
|
||||||
```
|
```
|
||||||
// helpers.h
|
// helpers.h
|
||||||
static int (*ebpf_get_tick_count)(void* ctx) = (void*) 4;
|
#include <stdint.h>
|
||||||
|
struct ebpf_map;
|
||||||
|
static int (*ebpf_map_update_elem)(struct ebpf_map* map, const void* key, const void* value, uint64_t flags) = (void*) 2;
|
||||||
```
|
```
|
||||||
|
|
||||||
A sample eBPF program that uses it might look like this:
|
We'll cover in section 6.3 what this function does, but for now we only care about the prototype.
|
||||||
|
We can create a sample (but, as we will see, invalid) program like so:
|
||||||
|
|
||||||
```
|
```
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
int func(void* ctx)
|
int func()
|
||||||
{
|
{
|
||||||
return ebpf_get_tick_count(ctx);
|
int result = ebpf_map_update_elem((struct ebpf_map*)0, (uint32_t*)0, (uint32_t*)0, 0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -614,50 +629,69 @@ helpers.o: file format ELF64-BPF
|
||||||
Disassembly of section .text:
|
Disassembly of section .text:
|
||||||
0000000000000000 func:
|
0000000000000000 func:
|
||||||
; {
|
; {
|
||||||
0: 85 00 00 00 04 00 00 00 call 4
|
0: b7 01 00 00 00 00 00 00 r1 = 0
|
||||||
; return ebpf_get_tick_count(ctx);
|
; int result = ebpf_map_update_elem((struct ebpf_map*)0, (uint32_t*)0, (uint32_t*)0, 0);
|
||||||
1: 95 00 00 00 00 00 00 00 exit
|
1: b7 02 00 00 00 00 00 00 r2 = 0
|
||||||
|
2: b7 03 00 00 00 00 00 00 r3 = 0
|
||||||
|
3: b7 04 00 00 00 00 00 00 r4 = 0
|
||||||
|
4: 85 00 00 00 02 00 00 00 call 2
|
||||||
|
; return result;
|
||||||
|
5: 95 00 00 00 00 00 00 00 exit
|
||||||
```
|
```
|
||||||
|
|
||||||
Now let's see how the verifier deals with this. The verifier needs to
|
Now let's see how the verifier deals with this. The verifier needs to
|
||||||
know the prototype in order to verify that eBPF program passes arguments
|
know the prototype in order to verify that the eBPF program passes arguments
|
||||||
correctly, and handles the results correct (e.g., not passing an invalid
|
correctly, and handles the results correct (e.g., not passing an invalid
|
||||||
value in a pointer argument).
|
value in a pointer argument).
|
||||||
|
|
||||||
The verifier calls into a `get_helper_prototype(4)` API exposed by
|
The verifier calls into a `get_helper_prototype(2)` API exposed by
|
||||||
platform-specific code to query the prototype for a given helper function.
|
platform-specific code to query the prototype for a given helper function.
|
||||||
The platform-specific code ([windows_helpers.cpp](../src/ebpf/libs/api/windows_helpers.cpp)) will return an entry like this one:
|
The platform-specific code ([windows_helpers.cpp](../src/ebpf/libs/api/windows_helpers.cpp)) will return an entry like this one:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{// long ebpf_map_update_elem(struct ebpf_map *map, const void *key, const
|
||||||
// int ebpf_get_tick_count(void* ctx);
|
// void *value, uint64_t flags);
|
||||||
.name = "ebpf_get_tick_count",
|
.name = "ebpf_map_update_elem",
|
||||||
.return_type = EbpfHelperReturnType::INTEGER,
|
.return_type = EbpfHelperReturnType::INTEGER,
|
||||||
.argument_type = {
|
.argument_type =
|
||||||
EbpfHelperArgumentType::PTR_TO_CTX,
|
{
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
EbpfHelperArgumentType::PTR_TO_MAP,
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
EbpfHelperArgumentType::PTR_TO_MAP_KEY,
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
EbpfHelperArgumentType::PTR_TO_MAP_VALUE,
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
EbpfHelperArgumentType::ANYTHING,
|
||||||
}
|
EbpfHelperArgumentType::DONTCARE,
|
||||||
},
|
}},
|
||||||
```
|
```
|
||||||
|
|
||||||
The above helps the verifier know the type and semantics of the arguments
|
The above helps the verifier know the type and semantics of the arguments
|
||||||
and the return value.
|
and the return value.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
> netsh ebpf show disassembly helpers.o
|
||||||
|
0: r1 = 0
|
||||||
|
1: r2 = 0
|
||||||
|
2: r3 = 0
|
||||||
|
3: r4 = 0
|
||||||
|
4: r0 = ebpf_map_update_elem:2(r1:FD, r2:K, r3:V, r4)
|
||||||
|
5: exit
|
||||||
|
|
||||||
> netsh ebpf show verification helpers.o
|
> netsh ebpf show verification helpers.o
|
||||||
|
|
||||||
Verification succeeded
|
error: Verification failed
|
||||||
|
|
||||||
> netsh ebpf show disassembly helpers.o
|
Verification report:
|
||||||
0: r0 = ebpf_get_tick_count:4(r1:CTX)
|
|
||||||
1: exit
|
4: r0 = ebpf_map_update_elem:2(r1:FD, r2:K, r3:V, r4)
|
||||||
|
assertion failed: r1 is map_fd
|
||||||
|
Code is unreachable after 4
|
||||||
|
|
||||||
|
1 errors
|
||||||
```
|
```
|
||||||
|
|
||||||
As shown above, verification is successful, and the verifier understands
|
As shown above, the verifier understands the function name and prototype,
|
||||||
the function name, and knows that the first argument is the context.
|
and knows that the program is invalid because it is passing null instead
|
||||||
|
of a valid value. We'll come back to this in section 6.3 to see how to
|
||||||
|
use the helper correctly.
|
||||||
|
|
||||||
### 6.2.1. Why -O2?
|
### 6.2.1. Why -O2?
|
||||||
|
|
||||||
|
@ -667,29 +701,39 @@ happens if we didn't compile with `-O2`? The disassembly looks instead
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
func:
|
> clang -target bpf -Wall -g -c helpers.c -o helpers.o
|
||||||
|
|
||||||
|
> llvm-objdump --triple bpf -S helpers.o
|
||||||
|
|
||||||
|
helpers.o: file format ELF64-BPF
|
||||||
|
|
||||||
|
Disassembly of section .text:
|
||||||
|
0000000000000000 func:
|
||||||
; {
|
; {
|
||||||
0: bf 12 00 00 00 00 00 00 r2 = r1
|
0: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
|
||||||
1: 7b 1a f8 ff 00 00 00 00 *(u64 *)(r10 - 8) = r1
|
; int result = ebpf_map_update_elem((struct ebpf_map*)0, (uint32_t*)0, (uint32_t*)0, 0);
|
||||||
; return bpf_get_socket_uid(ctx);
|
2: 79 11 00 00 00 00 00 00 r1 = *(u64 *)(r1 + 0)
|
||||||
2: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
|
3: b7 02 00 00 00 00 00 00 r2 = 0
|
||||||
4: 79 11 00 00 00 00 00 00 r1 = *(u64 *)(r1 + 0)
|
4: 7b 1a f0 ff 00 00 00 00 *(u64 *)(r10 - 16) = r1
|
||||||
5: 79 a3 f8 ff 00 00 00 00 r3 = *(u64 *)(r10 - 8)
|
5: bf 21 00 00 00 00 00 00 r1 = r2
|
||||||
6: 7b 1a f0 ff 00 00 00 00 *(u64 *)(r10 - 16) = r1
|
6: 7b 2a e8 ff 00 00 00 00 *(u64 *)(r10 - 24) = r2
|
||||||
7: bf 31 00 00 00 00 00 00 r1 = r3
|
7: 79 a3 e8 ff 00 00 00 00 r3 = *(u64 *)(r10 - 24)
|
||||||
8: 79 a3 f0 ff 00 00 00 00 r3 = *(u64 *)(r10 - 16)
|
8: 79 a4 e8 ff 00 00 00 00 r4 = *(u64 *)(r10 - 24)
|
||||||
9: 7b 2a e8 ff 00 00 00 00 *(u64 *)(r10 - 24) = r2
|
9: 79 a5 f0 ff 00 00 00 00 r5 = *(u64 *)(r10 - 16)
|
||||||
10: 8d 00 00 00 03 00 00 00 callx 3
|
10: 8d 00 00 00 05 00 00 00 callx 5
|
||||||
11: 95 00 00 00 00 00 00 00 exit
|
11: 63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0
|
||||||
|
; return result;
|
||||||
|
12: 61 a0 fc ff 00 00 00 00 r0 = *(u32 *)(r10 - 4)
|
||||||
|
13: 95 00 00 00 00 00 00 00 exit
|
||||||
```
|
```
|
||||||
|
|
||||||
The helper function is called in line 10 via the `callx` instruction
|
The helper function is called in line 10 via the `callx` instruction
|
||||||
(0x8d), but importantly that instruction *is not listed in the
|
(0x8d), but importantly that instruction *is not listed in the
|
||||||
[eBPF spec](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md)*!
|
[eBPF spec](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md)*!
|
||||||
Furthermore, the Prevail verifier's ELF parser also has problems with it.
|
Furthermore, the PREVAIL verifier's ELF parser also has problems with it.
|
||||||
Let's see
|
Let's see
|
||||||
why. Unlike the optimized disassembly where the helper id is encoded in
|
why. Unlike the optimized disassembly where the helper id is encoded in
|
||||||
the instruction, here the value 47 (0x2f) is encoded in the data section:
|
the instruction, here the value 32 (0x20) is encoded in the data section:
|
||||||
|
|
||||||
```
|
```
|
||||||
> llvm-objdump --triple bpf -s helpers.o --section .data
|
> llvm-objdump --triple bpf -s helpers.o --section .data
|
||||||
|
@ -697,7 +741,7 @@ the instruction, here the value 47 (0x2f) is encoded in the data section:
|
||||||
helpers.o: file format ELF64-BPF
|
helpers.o: file format ELF64-BPF
|
||||||
|
|
||||||
Contents of section .data:
|
Contents of section .data:
|
||||||
0000 2f000000 00000000 /.......
|
0000 02000000 00000000
|
||||||
```
|
```
|
||||||
|
|
||||||
An entry also appears in the relocation section, which we can see as follows.
|
An entry also appears in the relocation section, which we can see as follows.
|
||||||
|
@ -708,14 +752,14 @@ where without it llvm-objdump will dump all of them.
|
||||||
```
|
```
|
||||||
> llvm-objdump --triple bpf --section .rel.text -r helpers.o
|
> llvm-objdump --triple bpf --section .rel.text -r helpers.o
|
||||||
|
|
||||||
helpers.o: file format ELF64-BPF
|
helpers.o: file format ELF64-BPF
|
||||||
|
|
||||||
RELOCATION RECORDS FOR [.rel.text]:
|
RELOCATION RECORDS FOR [.rel.text]:
|
||||||
0000000000000010 R_BPF_64_64 bpf_get_socket_uid
|
0000000000000000 R_BPF_64_64 .data
|
||||||
```
|
```
|
||||||
|
|
||||||
However the verifier's ELF parser only handles relocation records for
|
However the verifier's ELF parser only handles relocation records for
|
||||||
maps, not helper functions, since in "correct" eBPF bytecode (i.e.,
|
maps (which we'll cover next), not helper functions, since in "correct" eBPF bytecode (i.e.,
|
||||||
bytecode conforming to the eBPF spec), relocation records are always for
|
bytecode conforming to the eBPF spec), relocation records are always for
|
||||||
maps. So if you forget to compile with -O2, it will fail elf parsing even
|
maps. So if you forget to compile with -O2, it will fail elf parsing even
|
||||||
before trying to verify the bytecode.
|
before trying to verify the bytecode.
|
||||||
|
@ -789,8 +833,8 @@ Contents of section maps:
|
||||||
Now to make use of the map, we have to use helper functions to access it:
|
Now to make use of the map, we have to use helper functions to access it:
|
||||||
```
|
```
|
||||||
void *ebpf_map_lookup_elem(struct ebpf_map* map, const void* key);
|
void *ebpf_map_lookup_elem(struct ebpf_map* map, const void* key);
|
||||||
long ebpf_map_update_elem(struct ebpf_map* map, const void* key, const void* value, uint64_t flags);
|
int ebpf_map_update_elem(struct ebpf_map* map, const void* key, const void* value, uint64_t flags);
|
||||||
long ebpf_map_delete_elem(struct ebpf_map* map, const void* key);
|
int ebpf_map_delete_elem(struct ebpf_map* map, const void* key);
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's update the program to write the value "42" to the map section for the
|
Let's update the program to write the value "42" to the map section for the
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 745e514caef384bed8289e9eab55fedff2b253cc
|
Subproject commit 0b62d8264e1ffe44e89ba2501c7846f607244d9c
|
|
@ -50,9 +50,7 @@ allocate_error_string(const std::string& str)
|
||||||
static int
|
static int
|
||||||
analyze(raw_program& raw_prog, const char** error_message)
|
analyze(raw_program& raw_prog, const char** error_message)
|
||||||
{
|
{
|
||||||
const ebpf_platform_t* platform = &g_ebpf_platform_windows;
|
std::variant<InstructionSeq, std::string> prog_or_error = unmarshal(raw_prog);
|
||||||
|
|
||||||
std::variant<InstructionSeq, std::string> prog_or_error = unmarshal(raw_prog, platform);
|
|
||||||
if (!std::holds_alternative<InstructionSeq>(prog_or_error)) {
|
if (!std::holds_alternative<InstructionSeq>(prog_or_error)) {
|
||||||
*error_message = allocate_error_string(std::get<std::string>(prog_or_error));
|
*error_message = allocate_error_string(std::get<std::string>(prog_or_error));
|
||||||
return 1; // Error;
|
return 1; // Error;
|
||||||
|
@ -154,7 +152,7 @@ ebpf_api_elf_enumerate_sections(
|
||||||
for (const auto& raw_program : raw_programs) {
|
for (const auto& raw_program : raw_programs) {
|
||||||
tlv_sequence stats_sequence;
|
tlv_sequence stats_sequence;
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program, platform);
|
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program);
|
||||||
if (std::holds_alternative<std::string>(programOrError)) {
|
if (std::holds_alternative<std::string>(programOrError)) {
|
||||||
std::cout << "parse failure: " << std::get<std::string>(programOrError) << "\n";
|
std::cout << "parse failure: " << std::get<std::string>(programOrError) << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -198,7 +196,7 @@ ebpf_api_elf_disassemble_section(
|
||||||
try {
|
try {
|
||||||
auto raw_programs = read_elf(file, section, &verifier_options, platform);
|
auto raw_programs = read_elf(file, section, &verifier_options, platform);
|
||||||
raw_program raw_program = raw_programs.back();
|
raw_program raw_program = raw_programs.back();
|
||||||
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program, platform);
|
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program);
|
||||||
if (std::holds_alternative<std::string>(programOrError)) {
|
if (std::holds_alternative<std::string>(programOrError)) {
|
||||||
error << "parse failure: " << std::get<std::string>(programOrError);
|
error << "parse failure: " << std::get<std::string>(programOrError);
|
||||||
*error_message = allocate_error_string(error.str());
|
*error_message = allocate_error_string(error.str());
|
||||||
|
@ -235,7 +233,7 @@ ebpf_api_elf_verify_section(
|
||||||
|
|
||||||
auto raw_programs = read_elf(file, section, &verifier_options, platform);
|
auto raw_programs = read_elf(file, section, &verifier_options, platform);
|
||||||
raw_program raw_program = raw_programs.back();
|
raw_program raw_program = raw_programs.back();
|
||||||
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program, platform);
|
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program);
|
||||||
if (std::holds_alternative<std::string>(programOrError)) {
|
if (std::holds_alternative<std::string>(programOrError)) {
|
||||||
error << "parse failure: " << std::get<std::string>(programOrError);
|
error << "parse failure: " << std::get<std::string>(programOrError);
|
||||||
*error_message = allocate_error_string(error.str());
|
*error_message = allocate_error_string(error.str());
|
||||||
|
|
|
@ -42,18 +42,6 @@ const struct EbpfHelperPrototype windows_helper_prototypes[] = {
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
EbpfHelperArgumentType::DONTCARE,
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
EbpfHelperArgumentType::DONTCARE,
|
||||||
}},
|
}},
|
||||||
{// Just for a tutorial, can probably be removed.
|
|
||||||
// int ebpf_get_tick_count(void* ctx);
|
|
||||||
.name = "ebpf_get_tick_count",
|
|
||||||
.return_type = EbpfHelperReturnType::INTEGER,
|
|
||||||
.argument_type =
|
|
||||||
{
|
|
||||||
EbpfHelperArgumentType::PTR_TO_CTX,
|
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
|
||||||
EbpfHelperArgumentType::DONTCARE,
|
|
||||||
}},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check whether a given integer is a valid helper ID.
|
// Check whether a given integer is a valid helper ID.
|
||||||
|
|
|
@ -29,16 +29,17 @@
|
||||||
// the preprocessor treat a prefix list as one macro argument.
|
// the preprocessor treat a prefix list as one macro argument.
|
||||||
#define COMMA ,
|
#define COMMA ,
|
||||||
|
|
||||||
constexpr EbpfContextDescriptor xdp_context_descriptor = {
|
const EbpfContextDescriptor g_xdp_context_descriptor = {
|
||||||
24, // Size of ctx struct.
|
24, // Size of ctx struct.
|
||||||
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
||||||
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
||||||
16, // Offset into ctx struct of pointer to metadata, or -1 if none.
|
16, // Offset into ctx struct of pointer to metadata, or -1 if none.
|
||||||
};
|
};
|
||||||
|
|
||||||
const EbpfProgramType windows_xdp_program_type = PTYPE("xdp", xdp_context_descriptor, EBPF_PROGRAM_TYPE_XDP, {"xdp"});
|
const EbpfProgramType windows_xdp_program_type =
|
||||||
|
PTYPE("xdp", &g_xdp_context_descriptor, EBPF_PROGRAM_TYPE_XDP, {"xdp"});
|
||||||
|
|
||||||
constexpr EbpfContextDescriptor bind_context_descriptor = {
|
const EbpfContextDescriptor g_bind_context_descriptor = {
|
||||||
43, // Size of ctx struct.
|
43, // Size of ctx struct.
|
||||||
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
||||||
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
||||||
|
@ -46,7 +47,7 @@ constexpr EbpfContextDescriptor bind_context_descriptor = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const EbpfProgramType windows_bind_program_type =
|
const EbpfProgramType windows_bind_program_type =
|
||||||
PTYPE("bind", bind_context_descriptor, EBPF_PROGRAM_TYPE_BIND, {"bind"});
|
PTYPE("bind", &g_bind_context_descriptor, EBPF_PROGRAM_TYPE_BIND, {"bind"});
|
||||||
|
|
||||||
const std::vector<EbpfProgramType> windows_program_types = {
|
const std::vector<EbpfProgramType> windows_program_types = {
|
||||||
PTYPE("unspecified", {0}, EBPF_PROGRAM_TYPE_UNSPECIFIED, {}),
|
PTYPE("unspecified", {0}, EBPF_PROGRAM_TYPE_UNSPECIFIED, {}),
|
||||||
|
|
Загрузка…
Ссылка в новой задаче