@@ -31,8 +31,6 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format,
31
31
if (DEBUG_LIBBPF_RUNTIME) return vfprintf (stderr, format, args);
32
32
return 0 ;
33
33
}
34
- using bpf_program_manager =
35
- std::unordered_map<uint64_t , std::unique_ptr<wasm_bpf_program>>;
36
34
37
35
// / @brief initialize libbpf library
38
36
void init_libbpf (void ) {
@@ -45,14 +43,6 @@ static void perfbuf_sample_fn(void *ctx, int cpu, void *data, __u32 size) {
45
43
bpf_buffer_sample (ctx, data, size);
46
44
}
47
45
48
- // / @brief get the bpf map in a object by fd
49
- static struct bpf_map *bpf_obj_get_map_by_fd (int fd, bpf_object *obj) {
50
- bpf_map *map;
51
- bpf_object__for_each_map (map, obj) {
52
- if (bpf_map__fd (map) == fd) return map;
53
- }
54
- return NULL ;
55
- }
56
46
57
47
#define PERF_BUFFER_PAGES 64
58
48
@@ -124,6 +114,26 @@ int bpf_buffer::bpf_buffer_sample(void *data, size_t size) {
124
114
return 0 ;
125
115
}
126
116
117
+ // / @brief verify that if an native address is valid in the wasm memory space
118
+ static inline bool verify_wasm_buffer_by_native_addr (wasm_exec_env_t exec_env,
119
+ void * ptr,
120
+ uint32_t length) {
121
+ wasm_module_inst_t module = wasm_runtime_get_module_inst (exec_env);
122
+ if (!module)
123
+ return false ;
124
+
125
+ return wasm_runtime_validate_native_addr (module, ptr, length);
126
+ }
127
+ // / @brief verify that if a all chars of a zero-terminated string sit in the valid wasm memory space
128
+ static inline bool verify_wasm_string_by_native_addr (wasm_exec_env_t exec_env,
129
+ const char * str) {
130
+ wasm_module_inst_t module = wasm_runtime_get_module_inst (exec_env);
131
+ if (!module)
132
+ return false ;
133
+ uint32_t wasm_addr = wasm_runtime_addr_native_to_app (module, (void *)str);
134
+ return wasm_runtime_validate_app_str_addr (module, wasm_addr);
135
+ }
136
+
127
137
// / @brief sample the perf buffer and ring buffer
128
138
static int bpf_buffer_sample (void *ctx, void *data, size_t size) {
129
139
bpf_buffer *buffer = (bpf_buffer *)ctx;
@@ -145,6 +155,17 @@ std::unique_ptr<bpf_buffer> bpf_buffer__new(struct bpf_map *events) {
145
155
int wasm_bpf_program::bpf_map_fd_by_name (const char *name) {
146
156
return bpf_object__find_map_fd_by_name (obj.get (), name);
147
157
}
158
+ // / @brief get map pointer by fd through iterating over all maps
159
+ bpf_map* wasm_bpf_program::map_ptr_by_fd (int fd) {
160
+ bpf_map* curr = nullptr ;
161
+ bpf_map__for_each (curr, obj.get ()) {
162
+ if (bpf_map__fd (curr) == fd) {
163
+ return curr;
164
+ }
165
+ }
166
+ return nullptr ;
167
+ }
168
+
148
169
// / @brief load all bpf programs and maps in a object file.
149
170
int wasm_bpf_program::load_bpf_object (const void *obj_buf, size_t obj_buf_sz) {
150
171
auto object = bpf_object__open_mem (obj_buf, obj_buf_sz, NULL );
@@ -212,7 +233,7 @@ int wasm_bpf_program::bpf_buffer_poll(wasm_exec_env_t exec_env, int fd,
212
233
int timeout_ms) {
213
234
if (buffer.get () == nullptr ) {
214
235
// create buffer
215
- auto map = bpf_obj_get_map_by_fd (fd, obj. get () );
236
+ auto map = this -> map_ptr_by_fd (fd);
216
237
buffer = bpf_buffer__new (map);
217
238
buffer->bpf_buffer__open (fd, bpf_buffer_sample, buffer.get ());
218
239
return 0 ;
@@ -228,16 +249,47 @@ int wasm_bpf_program::bpf_buffer_poll(wasm_exec_env_t exec_env, int fd,
228
249
}
229
250
230
251
// / a wrapper function to call the bpf syscall
231
- int bpf_map_operate (int fd, int cmd, void *key, void *value, void *next_key,
252
+ int bpf_map_operate (wasm_exec_env_t exec_env,
253
+ int fd,
254
+ int cmd,
255
+ void * key,
256
+ void * value,
257
+ void * next_key,
232
258
uint64_t flags) {
259
+ bpf_map_info map_info;
260
+ memset (&map_info, 0 , sizeof (map_info));
261
+ __u32 info_len = sizeof (map_info);
262
+ int err;
263
+ if ((err = bpf_map_get_info_by_fd (fd, &map_info, &info_len)) != 0 ) {
264
+ // Invalid map fd
265
+ return err;
266
+ }
267
+ auto key_size = map_info.key_size ;
268
+ auto value_size = map_info.value_size ;
269
+
270
+ auto verify_size = [&](void * ptr, uint32_t size) -> bool {
271
+ return verify_wasm_buffer_by_native_addr (exec_env, ptr, size);
272
+ };
233
273
switch (cmd) {
234
274
case BPF_MAP_GET_NEXT_KEY:
275
+ if (!verify_size (key, key_size) || !verify_size (next_key, key_size))
276
+ return -EFAULT;
277
+
235
278
return bpf_map_get_next_key (fd, key, next_key);
236
279
case BPF_MAP_LOOKUP_ELEM:
280
+ if (!verify_size (key, key_size) || !verify_size (value, value_size))
281
+ return -EFAULT;
282
+
237
283
return bpf_map_lookup_elem_flags (fd, key, value, flags);
238
284
case BPF_MAP_UPDATE_ELEM:
285
+ if (!verify_size (key, key_size) || !verify_size (value, value_size))
286
+ return -EFAULT;
287
+
239
288
return bpf_map_update_elem (fd, key, value, flags);
240
289
case BPF_MAP_DELETE_ELEM:
290
+ if (!verify_size (key, key_size))
291
+ return -EFAULT;
292
+
241
293
return bpf_map_delete_elem_flags (fd, key, flags);
242
294
default : // More syscall commands can be allowed here
243
295
return -EINVAL;
@@ -249,28 +301,39 @@ extern "C" {
249
301
uint64_t wasm_load_bpf_object (wasm_exec_env_t exec_env, void *obj_buf,
250
302
int obj_buf_sz) {
251
303
if (obj_buf_sz <= 0 ) return 0 ;
304
+ // Ensure that the buffer passed from wasm program is valid
305
+ if (!verify_wasm_buffer_by_native_addr (exec_env, obj_buf,
306
+ (uint32_t )obj_buf_sz)) {
307
+ return 0 ;
308
+ }
252
309
bpf_program_manager *bpf_programs =
253
310
(bpf_program_manager *)wasm_runtime_get_user_data (exec_env);
254
311
auto program = std::make_unique<wasm_bpf_program>();
255
312
int res = program->load_bpf_object (obj_buf, (size_t )obj_buf_sz);
256
313
if (res < 0 ) return 0 ;
257
314
auto key = (uint64_t )program.get ();
258
- bpf_programs->emplace (key, std::move (program));
315
+ bpf_programs->programs . emplace (key, std::move (program));
259
316
return key;
260
317
}
261
318
262
319
int wasm_close_bpf_object (wasm_exec_env_t exec_env, uint64_t program) {
263
- bpf_program_manager *bpf_programs =
264
- (bpf_program_manager *)wasm_runtime_get_user_data (exec_env);
265
- return !bpf_programs->erase (program);
320
+ bpf_program_manager* bpf_programs =
321
+ (bpf_program_manager*)wasm_runtime_get_user_data (exec_env);
322
+ if (!bpf_programs->programs .count (program))
323
+ return 0 ;
324
+ return !bpf_programs->programs .erase (program);
266
325
}
267
326
268
327
int wasm_attach_bpf_program (wasm_exec_env_t exec_env, uint64_t program,
269
328
char *name, char *attach_target) {
270
- bpf_program_manager *bpf_programs =
271
- (bpf_program_manager *)wasm_runtime_get_user_data (exec_env);
272
- if (bpf_programs->find (program) != bpf_programs->end ()) {
273
- return (*bpf_programs)[program]->attach_bpf_program (name,
329
+ bpf_program_manager* bpf_programs =
330
+ (bpf_program_manager*)wasm_runtime_get_user_data (exec_env);
331
+ if (bpf_programs->programs .find (program) != bpf_programs->programs .end ()) {
332
+ // Ensure that the string pointer passed from wasm program is valid
333
+ if ((!verify_wasm_string_by_native_addr (exec_env, name)) ||
334
+ (!verify_wasm_string_by_native_addr (exec_env, attach_target)))
335
+ return -EFAULT;
336
+ return bpf_programs->programs [program]->attach_bpf_program (name,
274
337
attach_target);
275
338
}
276
339
return -EINVAL;
@@ -281,8 +344,11 @@ int wasm_bpf_buffer_poll(wasm_exec_env_t exec_env, uint64_t program, int fd,
281
344
int max_size, int timeout_ms) {
282
345
bpf_program_manager *bpf_programs =
283
346
(bpf_program_manager *)wasm_runtime_get_user_data (exec_env);
284
- if (bpf_programs->find (program) != bpf_programs->end ()) {
285
- return (*bpf_programs)[program]->bpf_buffer_poll (
347
+ if (bpf_programs->programs .find (program) != bpf_programs->programs .end ()) {
348
+ // Ensure that the buffer is valid and can hold the data received
349
+ if (!verify_wasm_buffer_by_native_addr (exec_env, data, (uint32_t )max_size))
350
+ return -EFAULT;
351
+ return bpf_programs->programs [program]->bpf_buffer_poll (
286
352
exec_env, fd, sample_func, ctx, data, (size_t )max_size, timeout_ms);
287
353
}
288
354
return -EINVAL;
@@ -292,16 +358,25 @@ int wasm_bpf_map_fd_by_name(wasm_exec_env_t exec_env, uint64_t program,
292
358
const char *name) {
293
359
bpf_program_manager *bpf_programs =
294
360
(bpf_program_manager *)wasm_runtime_get_user_data (exec_env);
295
- if (bpf_programs->find (program) != bpf_programs->end ()) {
296
- return (*bpf_programs)[program]->bpf_map_fd_by_name (name);
361
+ if (bpf_programs->programs .find (program) != bpf_programs->programs .end ()) {
362
+ // Ensure that the string is valid
363
+ if (!verify_wasm_string_by_native_addr (exec_env, name))
364
+ return -EFAULT;
365
+ return bpf_programs->programs [program]->bpf_map_fd_by_name (name);
297
366
}
298
367
return -EINVAL;
299
368
}
300
369
301
370
// / @brief a wrapper function to the bpf syscall to operate the bpf maps
302
- int wasm_bpf_map_operate (wasm_exec_env_t exec_env, int fd, int cmd, void *key,
303
- void *value, void *next_key, uint64_t flags) {
304
- return bpf_map_operate (fd, (bpf_map_cmd)cmd, key, value, next_key, flags);
371
+ int wasm_bpf_map_operate (wasm_exec_env_t exec_env,
372
+ int fd,
373
+ int cmd,
374
+ void * key,
375
+ void * value,
376
+ void * next_key,
377
+ uint64_t flags) {
378
+ return bpf_map_operate (
379
+ exec_env, fd, (bpf_map_cmd)cmd, key, value, next_key, flags);
305
380
}
306
381
}
307
382
@@ -354,8 +429,8 @@ int wasm_main(unsigned char *buf, unsigned int size, int argc, char *argv[]) {
354
429
printf (" Create wasm execution environment failed.\n " );
355
430
return -1 ;
356
431
}
357
- std::unordered_set<std::unique_ptr<wasm_bpf_program>> bpf_programs ;
358
- wasm_runtime_set_user_data (exec_env, &bpf_programs );
432
+ bpf_program_manager prog_manager ;
433
+ wasm_runtime_set_user_data (exec_env, &prog_manager );
359
434
wasm_runtime_set_module_inst (exec_env, module_inst);
360
435
if (!(start_func = wasm_runtime_lookup_wasi_start_function (module_inst))) {
361
436
printf (" The start wasm function is not found.\n " );
@@ -367,7 +442,7 @@ int wasm_main(unsigned char *buf, unsigned int size, int argc, char *argv[]) {
367
442
wasm_runtime_get_exception (module_inst));
368
443
return -1 ;
369
444
}
370
- exit_code = wasm_runtime_get_wasi_exit_code (module_inst);
445
+ exit_code = ( int ) wasm_runtime_get_wasi_exit_code (module_inst);
371
446
if (exec_env) wasm_runtime_destroy_exec_env (exec_env);
372
447
if (module_inst) {
373
448
if (wasm_buffer) {
0 commit comments