|
7 | 7 |
|
8 | 8 | #include "alloc-util.h" |
9 | 9 | #include "bpf-program.h" |
| 10 | +#include "escape.h" |
10 | 11 | #include "fd-util.h" |
11 | 12 | #include "memory-util.h" |
12 | 13 | #include "missing_syscall.h" |
13 | 14 | #include "path-util.h" |
| 15 | +#include "serialize.h" |
14 | 16 | #include "string-table.h" |
15 | 17 |
|
16 | 18 | static const char *const bpf_cgroup_attach_type_table[__MAX_BPF_ATTACH_TYPE] = { |
@@ -362,3 +364,139 @@ int bpf_program_get_id_by_fd(int prog_fd, uint32_t *ret_id) { |
362 | 364 |
|
363 | 365 | return 0; |
364 | 366 | }; |
| 367 | + |
| 368 | +int bpf_program_serialize_attachment( |
| 369 | + FILE *f, |
| 370 | + FDSet *fds, |
| 371 | + const char *key, |
| 372 | + BPFProgram *p) { |
| 373 | + |
| 374 | + _cleanup_free_ char *escaped = NULL; |
| 375 | + int copy, r; |
| 376 | + |
| 377 | + if (!p || !p->attached_path) |
| 378 | + return 0; |
| 379 | + |
| 380 | + assert(p->kernel_fd >= 0); |
| 381 | + |
| 382 | + escaped = cescape(p->attached_path); |
| 383 | + if (!escaped) |
| 384 | + return -ENOMEM; |
| 385 | + |
| 386 | + copy = fdset_put_dup(fds, p->kernel_fd); |
| 387 | + if (copy < 0) |
| 388 | + return log_error_errno(copy, "Failed to add BPF kernel fd to serialize: %m"); |
| 389 | + |
| 390 | + r = serialize_item_format( |
| 391 | + f, |
| 392 | + key, |
| 393 | + "%i %s %s", |
| 394 | + copy, |
| 395 | + bpf_cgroup_attach_type_to_string(p->attached_type), |
| 396 | + escaped); |
| 397 | + if (r < 0) |
| 398 | + return r; |
| 399 | + |
| 400 | + /* After serialization, let's forget the fact that this program is attached. The attachment — if you |
| 401 | + * so will — is now 'owned' by the serialization, and not us anymore. Why does that matter? Because |
| 402 | + * of BPF's less-than-ideal lifecycle handling: to detach a program from a cgroup we have to |
| 403 | + * explicitly do so, it's not done implicitly on close(). Now, since we are serializing here we don't |
| 404 | + * want the program to be detached while freeing things, so that the attachment can be retained after |
| 405 | + * deserializing again. bpf_program_free() implicitly detaches things, if attached_path is non-NULL, |
| 406 | + * hence we set it to NULL here. */ |
| 407 | + |
| 408 | + p->attached_path = mfree(p->attached_path); |
| 409 | + return 0; |
| 410 | +} |
| 411 | + |
| 412 | +int bpf_program_serialize_attachment_set(FILE *f, FDSet *fds, const char *key, Set *set) { |
| 413 | + BPFProgram *p; |
| 414 | + int r; |
| 415 | + |
| 416 | + SET_FOREACH(p, set) { |
| 417 | + r = bpf_program_serialize_attachment(f, fds, key, p); |
| 418 | + if (r < 0) |
| 419 | + return r; |
| 420 | + } |
| 421 | + |
| 422 | + return 0; |
| 423 | +} |
| 424 | + |
| 425 | +int bpf_program_deserialize_attachment(const char *v, FDSet *fds, BPFProgram **bpfp) { |
| 426 | + _cleanup_free_ char *sfd = NULL, *sat = NULL, *unescaped = NULL; |
| 427 | + _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL; |
| 428 | + _cleanup_close_ int fd = -1; |
| 429 | + int ifd, at, r; |
| 430 | + |
| 431 | + assert(v); |
| 432 | + assert(bpfp); |
| 433 | + |
| 434 | + /* Extract first word: the fd number */ |
| 435 | + r = extract_first_word(&v, &sfd, NULL, 0); |
| 436 | + if (r < 0) |
| 437 | + return r; |
| 438 | + if (r == 0) |
| 439 | + return -EINVAL; |
| 440 | + |
| 441 | + r = safe_atoi(sfd, &ifd); |
| 442 | + if (r < 0) |
| 443 | + return r; |
| 444 | + if (ifd < 0) |
| 445 | + return -EBADF; |
| 446 | + |
| 447 | + /* Extract second word: the attach type */ |
| 448 | + r = extract_first_word(&v, &sat, NULL, 0); |
| 449 | + if (r < 0) |
| 450 | + return r; |
| 451 | + if (r == 0) |
| 452 | + return -EINVAL; |
| 453 | + |
| 454 | + at = bpf_cgroup_attach_type_from_string(sat); |
| 455 | + if (at < 0) |
| 456 | + return at; |
| 457 | + |
| 458 | + /* The rest is the path */ |
| 459 | + r = cunescape(v, 0, &unescaped); |
| 460 | + if (r < 0) |
| 461 | + return r; |
| 462 | + |
| 463 | + fd = fdset_remove(fds, ifd); |
| 464 | + if (fd < 0) |
| 465 | + return fd; |
| 466 | + |
| 467 | + p = new(BPFProgram, 1); |
| 468 | + if (!p) |
| 469 | + return -ENOMEM; |
| 470 | + |
| 471 | + *p = (BPFProgram) { |
| 472 | + .n_ref = 1, |
| 473 | + .kernel_fd = TAKE_FD(fd), |
| 474 | + .prog_type = BPF_PROG_TYPE_UNSPEC, |
| 475 | + .attached_path = TAKE_PTR(unescaped), |
| 476 | + .attached_type = at, |
| 477 | + }; |
| 478 | + |
| 479 | + if (*bpfp) |
| 480 | + bpf_program_unref(*bpfp); |
| 481 | + |
| 482 | + *bpfp = TAKE_PTR(p); |
| 483 | + return 0; |
| 484 | +} |
| 485 | + |
| 486 | +int bpf_program_deserialize_attachment_set(const char *v, FDSet *fds, Set **bpfsetp) { |
| 487 | + BPFProgram *p = NULL; |
| 488 | + int r; |
| 489 | + |
| 490 | + assert(v); |
| 491 | + assert(bpfsetp); |
| 492 | + |
| 493 | + r = bpf_program_deserialize_attachment(v, fds, &p); |
| 494 | + if (r < 0) |
| 495 | + return r; |
| 496 | + |
| 497 | + r = set_ensure_consume(bpfsetp, &bpf_program_hash_ops, p); |
| 498 | + if (r < 0) |
| 499 | + return r; |
| 500 | + |
| 501 | + return 0; |
| 502 | +} |
0 commit comments