-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathjbpf_platform.cpp
180 lines (160 loc) · 5.84 KB
/
jbpf_platform.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright (c) Microsoft Corporation. All rights reserved.
#include <stdexcept>
#define PTYPE(name, descr, native_type, prefixes) \
{ \
name, descr, native_type, prefixes \
}
#define PTYPE_PRIVILEGED(name, descr, native_type, prefixes) \
{ \
name, descr, native_type, prefixes, true \
}
#include "crab_verifier.hpp"
#include "helpers.hpp"
#include "platform.hpp"
#include "jbpf_platform.hpp"
#include "specs/spec_type_descriptors.hpp"
#include "jbpf_defs.h"
static int
create_map_jbpf(
uint32_t map_type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, ebpf_verifier_options_t options);
// Allow for comma as a separator between multiple prefixes, to make
// the preprocessor treat a prefix list as one macro argument.
#define COMMA ,
const EbpfProgramType jbpf_unspec_program_type = PTYPE("unspec", &g_jbpf_unspec_descr, JBPF_PROG_TYPE_UNSPEC, {});
std::vector<EbpfProgramType> jbpf_program_types = {
jbpf_unspec_program_type,
PTYPE("jbpf_generic", &g_jbpf_generic_descr, JBPF_PROG_TYPE_GENERIC, {"jbpf_generic"}),
PTYPE("jbpf_stats", &g_jbpf_stats_descr, JBPF_PROG_TYPE_STATS, {"jbpf_stats"}),
};
void
jbpf_verifier_register_program_type(int prog_type_id, EbpfProgramType program_type)
{
if (prog_type_id >= jbpf_program_types.size()) {
jbpf_program_types.resize(prog_type_id + 1);
}
jbpf_program_types[prog_type_id] = program_type;
}
static EbpfProgramType
jbpf_verifier_get_program_type(const std::string& section, const std::string& path)
{
for (const EbpfProgramType& t : jbpf_program_types) {
auto it =
std::find_if(t.section_prefixes.begin(), t.section_prefixes.end(), [§ion](const std::string& prefix) {
return section.find(prefix) == 0;
});
if (it != t.section_prefixes.end()) {
return t;
}
}
return jbpf_unspec_program_type;
}
#ifdef __linux__
#define JBPF_MAP_TYPE(x) JBPF_MAP_TYPE_##x, #x
#else
#define JBPF_MAP_TYPE(x) 0, #x
#endif
std::vector<EbpfMapType> jbpf_map_types = {
{JBPF_MAP_TYPE(UNSPEC)},
{JBPF_MAP_TYPE(ARRAY), true}, // True means that key is integer in range [0, max_entries-1]
{JBPF_MAP_TYPE(HASHMAP)},
{JBPF_MAP_TYPE(RINGBUF)},
{JBPF_MAP_TYPE(CONTROL_INPUT)},
{JBPF_MAP_TYPE(PER_THREAD_ARRAY), true},
{JBPF_MAP_TYPE(PER_THREAD_HASHMAP)},
{JBPF_MAP_TYPE(OUTPUT)},
};
int
jbpf_verifier_register_map_type(int map_id, EbpfMapType map_type)
{
// EbpfMapValueType::PROGRAM is not currently supported
if (map_type.value_type == EbpfMapValueType::PROGRAM) {
return -1;
}
if (map_id >= jbpf_map_types.size()) {
jbpf_map_types.resize(map_id + 1);
}
jbpf_map_types[map_id] = map_type;
return 0;
}
EbpfMapType
jbpf_verifier_get_map_type(uint32_t platform_specific_type)
{
uint32_t index = platform_specific_type;
if ((index == 0) || (index >= jbpf_map_types.size())) {
return jbpf_map_types[0];
}
EbpfMapType type = jbpf_map_types[index];
#ifdef __linux__
assert(type.platform_specific_type == platform_specific_type);
#else
type.platform_specific_type = platform_specific_type;
#endif
return type;
}
void
jbpf_verifier_parse_maps_section(
std::vector<EbpfMapDescriptor>& map_descriptors,
const char* data,
size_t map_def_size,
int map_count,
const ebpf_platform_t* platform,
ebpf_verifier_options_t options)
{
auto mapdefs = std::vector<jbpf_load_map_def>();
for (int i = 0; i < map_count; i++) {
jbpf_load_map_def def = {0};
memcpy(&def, data + i * map_def_size, std::min(map_def_size, sizeof(def)));
mapdefs.emplace_back(def);
}
for (auto const& s : mapdefs) {
EbpfMapType type = jbpf_verifier_get_map_type(s.type);
map_descriptors.emplace_back(EbpfMapDescriptor{
.original_fd = create_map_jbpf(s.type, s.key_size, s.value_size, s.max_entries, options),
.type = s.type,
.key_size = s.key_size,
.value_size = s.value_size,
.max_entries = s.max_entries});
}
for (size_t i = 0; i < mapdefs.size(); i++) {
unsigned int inner = mapdefs[i].inner_map_idx;
if (inner >= map_descriptors.size())
throw std::runtime_error(
std::string("bad inner map index ") + std::to_string(inner) + " for map " + std::to_string(i));
map_descriptors[i].inner_map_fd = map_descriptors.at(inner).original_fd;
}
}
static int
create_map_jbpf(
uint32_t map_type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, ebpf_verifier_options_t options)
{
if (options.mock_map_fds) {
EbpfMapType type = jbpf_verifier_get_map_type(map_type);
return create_map_crab(type, key_size, value_size, max_entries, options);
} else {
throw std::runtime_error(std::string("cannot create a Linux map"));
}
}
EbpfMapDescriptor&
jbpf_verifier_get_map_descriptor(int map_fd)
{
// First check if we already have the map descriptor cached.
EbpfMapDescriptor* map = find_map_descriptor(map_fd);
if (map != nullptr) {
return *map;
}
// This fd was not created from the maps section of an ELF file,
// but it may be an fd created by an app before calling the verifier.
// In this case, we would like to query the map descriptor info
// (key size, value size) from the execution context, but this is
// not yet supported.
throw std::runtime_error(std::string("map_fd not found"));
}
const ebpf_platform_t g_ebpf_platform_jbpf = {
jbpf_verifier_get_program_type,
jbpf_verifier_get_helper_prototype,
jbpf_verifier_is_helper_usable,
sizeof(jbpf_load_map_def),
jbpf_verifier_parse_maps_section,
jbpf_verifier_get_map_descriptor,
jbpf_verifier_get_map_type,
};