LCOV - code coverage report
Current view: top level - libbpfilter/cgen - handle.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 80.2 % 212 170
Test Date: 2026-05-11 12:01:08 Functions: 100.0 % 11 11
Branches: 45.7 % 208 95

             Branch data     Line data    Source code
       1                 :             : /* SPDX-License-Identifier: GPL-2.0-only */
       2                 :             : /*
       3                 :             :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4                 :             :  */
       5                 :             : 
       6                 :             : #include "cgen/handle.h"
       7                 :             : 
       8                 :             : #include <assert.h>
       9                 :             : #include <errno.h>
      10                 :             : #include <stdlib.h>
      11                 :             : #include <string.h>
      12                 :             : #include <unistd.h>
      13                 :             : 
      14                 :             : #include <bpfilter/bpf.h>
      15                 :             : #include <bpfilter/core/list.h>
      16                 :             : #include <bpfilter/counter.h>
      17                 :             : #include <bpfilter/dump.h>
      18                 :             : #include <bpfilter/helper.h>
      19                 :             : #include <bpfilter/hook.h>
      20                 :             : #include <bpfilter/logger.h>
      21                 :             : #include <bpfilter/pack.h>
      22                 :             : 
      23                 :             : #include "cgen/prog/link.h"
      24                 :             : #include "cgen/prog/map.h"
      25                 :             : #include "core/lock.h"
      26                 :             : 
      27                 :             : #define _BF_LINK_NAME "bf_link"
      28                 :             : 
      29                 :        6637 : int bf_handle_new(struct bf_handle **handle, const char *prog_name)
      30                 :             : {
      31                 :        6637 :     _free_bf_handle_ struct bf_handle *_handle = NULL;
      32                 :             : 
      33                 :             :     assert(handle);
      34                 :             :     assert(prog_name);
      35                 :             : 
      36                 :        6637 :     _handle = calloc(1, sizeof(*_handle));
      37         [ +  - ]:        6637 :     if (!_handle)
      38                 :             :         return -ENOMEM;
      39                 :             : 
      40                 :        6637 :     (void)snprintf(_handle->prog_name, BPF_OBJ_NAME_LEN, "%s", prog_name);
      41                 :        6637 :     _handle->prog_fd = -1;
      42                 :        6637 :     _handle->sets = bf_list_default(bf_map_free, bf_map_pack);
      43                 :             : 
      44                 :        6637 :     *handle = TAKE_PTR(_handle);
      45                 :             : 
      46                 :        6637 :     return 0;
      47                 :             : }
      48                 :             : 
      49                 :        5327 : int bf_handle_new_from_pack(struct bf_handle **handle, struct bf_lock *lock,
      50                 :             :                             bf_rpack_node_t node)
      51                 :             : {
      52                 :        5327 :     _free_bf_handle_ struct bf_handle *_handle = NULL;
      53                 :        5327 :     _cleanup_free_ char *name = NULL;
      54                 :             :     bf_rpack_node_t child, array_node;
      55                 :             :     int dir_fd;
      56                 :             :     int r;
      57                 :             : 
      58                 :             :     assert(handle);
      59                 :             :     assert(lock);
      60                 :             : 
      61                 :        5327 :     dir_fd = lock->chain_fd;
      62                 :             : 
      63                 :        5327 :     r = bf_rpack_kv_str(node, "prog_name", &name);
      64         [ -  + ]:        5327 :     if (r)
      65         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.name");
      66                 :             : 
      67                 :        5327 :     r = bf_handle_new(&_handle, name);
      68         [ +  - ]:        5327 :     if (r)
      69                 :             :         return r;
      70                 :             : 
      71                 :        5327 :     r = bf_bpf_obj_get(_handle->prog_name, dir_fd, &_handle->prog_fd);
      72         [ -  + ]:        5327 :     if (r < 0)
      73         [ #  # ]:           0 :         return bf_err_r(r, "failed to restore bf_handle.prog_fd from pin");
      74                 :             : 
      75                 :        5327 :     r = bf_rpack_kv_node(node, "link", &child);
      76         [ -  + ]:        5327 :     if (r)
      77         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.link");
      78         [ +  + ]:        5327 :     if (!bf_rpack_is_nil(child)) {
      79                 :         158 :         r = bf_link_new_from_pack(&_handle->link, dir_fd, child);
      80         [ -  + ]:         158 :         if (r)
      81         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.link");
      82                 :             :     }
      83                 :             : 
      84                 :        5327 :     r = bf_rpack_kv_node(node, "cmap", &child);
      85         [ -  + ]:        5327 :     if (r)
      86         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.cmap");
      87         [ +  - ]:        5327 :     if (!bf_rpack_is_nil(child)) {
      88                 :        5327 :         r = bf_map_new_from_pack(&_handle->cmap, dir_fd, child);
      89         [ -  + ]:        5327 :         if (r)
      90         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.cmap");
      91                 :             :     }
      92                 :             : 
      93                 :        5327 :     r = bf_rpack_kv_node(node, "pmap", &child);
      94         [ -  + ]:        5327 :     if (r)
      95         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.pmap");
      96         [ +  - ]:        5327 :     if (!bf_rpack_is_nil(child)) {
      97                 :        5327 :         r = bf_map_new_from_pack(&_handle->pmap, dir_fd, child);
      98         [ -  + ]:        5327 :         if (r)
      99         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.pmap");
     100                 :             :     }
     101                 :             : 
     102                 :        5327 :     r = bf_rpack_kv_node(node, "lmap", &child);
     103         [ -  + ]:        5327 :     if (r)
     104         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.lmap");
     105         [ +  + ]:        5327 :     if (!bf_rpack_is_nil(child)) {
     106                 :          20 :         r = bf_map_new_from_pack(&_handle->lmap, dir_fd, child);
     107         [ -  + ]:          20 :         if (r)
     108         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.lmap");
     109                 :             :     }
     110                 :             : 
     111                 :        5327 :     r = bf_rpack_kv_array(node, "sets", &child);
     112         [ -  + ]:        5327 :     if (r)
     113         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.sets");
     114   [ +  +  -  +  :       12666 :     bf_rpack_array_foreach (child, array_node) {
                   +  + ]
     115                 :           0 :         _free_bf_map_ struct bf_map *map = NULL;
     116                 :             : 
     117         [ -  + ]:        1006 :         if (bf_rpack_is_nil(array_node)) {
     118                 :           0 :             r = bf_list_add_tail(&_handle->sets, NULL);
     119         [ #  # ]:           0 :             if (r)
     120                 :             :                 return r;
     121                 :             :             continue;
     122                 :             :         }
     123                 :             : 
     124   [ +  -  +  -  :        1006 :         r = bf_list_emplace(&_handle->sets, bf_map_new_from_pack, map, dir_fd,
             -  -  -  - ]
     125                 :             :                             array_node);
     126                 :             :         if (r)
     127         [ #  # ]:           0 :             return bf_err_r(r, "failed to unpack bf_map into bf_handle.sets");
     128                 :             :     }
     129                 :             : 
     130                 :        5327 :     *handle = TAKE_PTR(_handle);
     131                 :             : 
     132                 :        5327 :     return 0;
     133                 :             : }
     134                 :             : 
     135                 :       18601 : void bf_handle_free(struct bf_handle **handle)
     136                 :             : {
     137                 :             :     assert(handle);
     138                 :             : 
     139         [ +  + ]:       18601 :     if (!*handle)
     140                 :             :         return;
     141                 :             : 
     142                 :        6637 :     closep(&(*handle)->prog_fd);
     143                 :             : 
     144                 :        6637 :     bf_link_free(&(*handle)->link);
     145                 :        6637 :     bf_map_free(&(*handle)->cmap);
     146                 :        6637 :     bf_map_free(&(*handle)->pmap);
     147                 :        6637 :     bf_map_free(&(*handle)->lmap);
     148                 :        6637 :     bf_list_clean(&(*handle)->sets);
     149                 :             : 
     150                 :        6637 :     free(*handle);
     151                 :        6637 :     *handle = NULL;
     152                 :             : }
     153                 :             : 
     154                 :        1329 : int bf_handle_pack(const struct bf_handle *handle, bf_wpack_t *pack)
     155                 :             : {
     156                 :             :     assert(handle);
     157                 :             :     assert(pack);
     158                 :             : 
     159                 :        1329 :     bf_wpack_kv_str(pack, "prog_name", handle->prog_name);
     160                 :             : 
     161         [ +  + ]:        1329 :     if (handle->link) {
     162                 :         143 :         bf_wpack_open_object(pack, "link");
     163                 :         143 :         bf_link_pack(handle->link, pack);
     164                 :         143 :         bf_wpack_close_object(pack);
     165                 :             :     } else {
     166                 :             :         bf_wpack_kv_nil(pack, "link");
     167                 :             :     }
     168                 :             : 
     169         [ +  - ]:        1329 :     if (handle->cmap) {
     170                 :        1329 :         bf_wpack_open_object(pack, "cmap");
     171                 :        1329 :         bf_map_pack(handle->cmap, pack);
     172                 :        1329 :         bf_wpack_close_object(pack);
     173                 :             :     } else {
     174                 :             :         bf_wpack_kv_nil(pack, "cmap");
     175                 :             :     }
     176                 :             : 
     177         [ +  - ]:        1329 :     if (handle->pmap) {
     178                 :        1329 :         bf_wpack_open_object(pack, "pmap");
     179                 :        1329 :         bf_map_pack(handle->pmap, pack);
     180                 :        1329 :         bf_wpack_close_object(pack);
     181                 :             :     } else {
     182                 :             :         bf_wpack_kv_nil(pack, "pmap");
     183                 :             :     }
     184                 :             : 
     185         [ +  + ]:        1329 :     if (handle->lmap) {
     186                 :          31 :         bf_wpack_open_object(pack, "lmap");
     187                 :          31 :         bf_map_pack(handle->lmap, pack);
     188                 :          31 :         bf_wpack_close_object(pack);
     189                 :             :     } else {
     190                 :             :         bf_wpack_kv_nil(pack, "lmap");
     191                 :             :     }
     192                 :             : 
     193                 :        1329 :     bf_wpack_kv_list(pack, "sets", &handle->sets);
     194                 :             : 
     195         [ -  + ]:        1329 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     196                 :             : }
     197                 :             : 
     198                 :          16 : void bf_handle_dump(const struct bf_handle *handle, prefix_t *prefix)
     199                 :             : {
     200                 :             :     assert(handle);
     201                 :             :     assert(prefix);
     202                 :             : 
     203         [ -  + ]:          16 :     DUMP(prefix, "struct bf_handle at %p", handle);
     204                 :             : 
     205                 :          16 :     bf_dump_prefix_push(prefix);
     206                 :             : 
     207         [ -  + ]:          16 :     DUMP(prefix, "prog_name: %s", handle->prog_name);
     208         [ -  + ]:          16 :     DUMP(prefix, "prog_fd: %d", handle->prog_fd);
     209                 :             : 
     210         [ -  + ]:          16 :     if (handle->link) {
     211         [ #  # ]:           0 :         DUMP(prefix, "link: struct bf_link *");
     212                 :           0 :         bf_dump_prefix_push(prefix);
     213                 :           0 :         bf_link_dump(handle->link, bf_dump_prefix_last(prefix));
     214                 :           0 :         bf_dump_prefix_pop(prefix);
     215                 :             :     } else {
     216         [ -  + ]:          16 :         DUMP(prefix, "link: struct bf_link * (NULL)");
     217                 :             :     }
     218                 :             : 
     219         [ +  - ]:          16 :     if (handle->cmap) {
     220         [ -  + ]:          16 :         DUMP(prefix, "cmap: struct bf_map *");
     221                 :          16 :         bf_dump_prefix_push(prefix);
     222                 :          16 :         bf_map_dump(handle->cmap, bf_dump_prefix_last(prefix));
     223                 :          16 :         bf_dump_prefix_pop(prefix);
     224                 :             :     } else {
     225         [ #  # ]:           0 :         DUMP(prefix, "cmap: struct bf_map * (NULL)");
     226                 :             :     }
     227                 :             : 
     228         [ +  - ]:          16 :     if (handle->pmap) {
     229         [ -  + ]:          16 :         DUMP(prefix, "pmap: struct bf_map *");
     230                 :          16 :         bf_dump_prefix_push(prefix);
     231                 :          16 :         bf_map_dump(handle->pmap, bf_dump_prefix_last(prefix));
     232                 :          16 :         bf_dump_prefix_pop(prefix);
     233                 :             :     } else {
     234         [ #  # ]:           0 :         DUMP(prefix, "pmap: struct bf_map * (NULL)");
     235                 :             :     }
     236                 :             : 
     237         [ +  + ]:          16 :     if (handle->lmap) {
     238         [ -  + ]:           3 :         DUMP(prefix, "lmap: struct bf_map *");
     239                 :           3 :         bf_dump_prefix_push(prefix);
     240                 :           3 :         bf_map_dump(handle->lmap, bf_dump_prefix_last(prefix));
     241                 :           3 :         bf_dump_prefix_pop(prefix);
     242                 :             :     } else {
     243         [ -  + ]:          13 :         DUMP(prefix, "lmap: struct bf_map * (NULL)");
     244                 :             :     }
     245                 :             : 
     246         [ -  + ]:          16 :     DUMP(bf_dump_prefix_last(prefix), "sets: bf_list<bf_map>[%lu]",
     247                 :             :          bf_list_size(&handle->sets));
     248                 :          16 :     bf_dump_prefix_push(prefix);
     249   [ -  +  -  -  :          32 :     bf_list_foreach (&handle->sets, map_node) {
                   -  + ]
     250                 :             :         struct bf_map *map = bf_list_node_get_data(map_node);
     251                 :             : 
     252         [ #  # ]:           0 :         if (bf_list_is_tail(&handle->sets, map_node))
     253                 :           0 :             bf_dump_prefix_last(prefix);
     254                 :             : 
     255         [ #  # ]:           0 :         if (!map) {
     256         [ #  # ]:           0 :             DUMP(prefix, "struct bf_map * (NULL)");
     257                 :           0 :             continue;
     258                 :             :         }
     259                 :             : 
     260                 :           0 :         bf_map_dump(map, prefix);
     261                 :             :     }
     262                 :          16 :     bf_dump_prefix_pop(prefix);
     263                 :             : 
     264                 :          16 :     bf_dump_prefix_pop(prefix);
     265                 :          16 : }
     266                 :             : 
     267                 :        1305 : int bf_handle_pin(struct bf_handle *handle, struct bf_lock *lock)
     268                 :             : {
     269                 :             :     int dir_fd;
     270                 :             :     int r;
     271                 :             : 
     272                 :             :     assert(handle);
     273                 :             :     assert(lock);
     274                 :             : 
     275                 :        1305 :     dir_fd = lock->chain_fd;
     276                 :             : 
     277                 :        1305 :     r = bf_bpf_obj_pin(handle->prog_name, handle->prog_fd, dir_fd);
     278         [ +  + ]:        1305 :     if (r) {
     279         [ +  - ]:           2 :         bf_err_r(r, "failed to pin BPF program");
     280                 :           2 :         goto err_unpin_all;
     281                 :             :     }
     282                 :             : 
     283         [ +  - ]:        1303 :     if (handle->cmap) {
     284                 :        1303 :         r = bf_map_pin(handle->cmap, dir_fd);
     285         [ -  + ]:        1303 :         if (r) {
     286         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF counters map");
     287                 :           0 :             goto err_unpin_all;
     288                 :             :         }
     289                 :             :     }
     290                 :             : 
     291         [ +  - ]:        1303 :     if (handle->pmap) {
     292                 :        1303 :         r = bf_map_pin(handle->pmap, dir_fd);
     293         [ -  + ]:        1303 :         if (r) {
     294         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF printer map");
     295                 :           0 :             goto err_unpin_all;
     296                 :             :         }
     297                 :             :     }
     298                 :             : 
     299         [ +  + ]:        1303 :     if (handle->lmap) {
     300                 :          27 :         r = bf_map_pin(handle->lmap, dir_fd);
     301         [ -  + ]:          27 :         if (r) {
     302         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF log map");
     303                 :           0 :             goto err_unpin_all;
     304                 :             :         }
     305                 :             :     }
     306                 :             : 
     307   [ +  +  +  +  :        3206 :     bf_list_foreach (&handle->sets, set_node) {
                   +  + ]
     308                 :             :         struct bf_map *map = bf_list_node_get_data(set_node);
     309                 :             : 
     310         [ -  + ]:         300 :         if (!map)
     311                 :           0 :             continue;
     312                 :             : 
     313                 :         300 :         r = bf_map_pin(map, dir_fd);
     314         [ -  + ]:         300 :         if (r) {
     315         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF set map");
     316                 :           0 :             goto err_unpin_all;
     317                 :             :         }
     318                 :             :     }
     319                 :             : 
     320         [ +  + ]:        1303 :     if (handle->link) {
     321                 :         119 :         r = bf_link_pin(handle->link, lock);
     322         [ +  - ]:         119 :         if (r) {
     323         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF link");
     324                 :           0 :             goto err_unpin_all;
     325                 :             :         }
     326                 :             :     }
     327                 :             : 
     328                 :             :     return 0;
     329                 :             : 
     330                 :           2 : err_unpin_all:
     331                 :           2 :     bf_handle_unpin(handle, lock);
     332                 :           2 :     return r;
     333                 :             : }
     334                 :             : 
     335                 :        1279 : void bf_handle_unpin(struct bf_handle *handle, struct bf_lock *lock)
     336                 :             : {
     337                 :             :     int dir_fd;
     338                 :             : 
     339                 :             :     assert(handle);
     340                 :             :     assert(lock);
     341                 :             : 
     342                 :        1279 :     dir_fd = lock->chain_fd;
     343                 :             : 
     344         [ +  - ]:        1279 :     if (handle->cmap)
     345                 :        1279 :         bf_map_unpin(handle->cmap, dir_fd);
     346         [ +  - ]:        1279 :     if (handle->pmap)
     347                 :        1279 :         bf_map_unpin(handle->pmap, dir_fd);
     348         [ +  + ]:        1279 :     if (handle->lmap)
     349                 :          16 :         bf_map_unpin(handle->lmap, dir_fd);
     350                 :             : 
     351   [ +  +  -  +  :        3002 :     bf_list_foreach (&handle->sets, set_node) {
                   +  + ]
     352                 :             :         struct bf_map *map = bf_list_node_get_data(set_node);
     353                 :             : 
     354         [ -  + ]:         222 :         if (!map)
     355                 :           0 :             continue;
     356                 :             : 
     357                 :         222 :         bf_map_unpin(map, dir_fd);
     358                 :             :     }
     359                 :             : 
     360         [ +  + ]:        1279 :     if (handle->link)
     361                 :         122 :         bf_link_unpin(handle->link, lock);
     362                 :             : 
     363                 :        1279 :     unlinkat(dir_fd, handle->prog_name, 0);
     364                 :        1279 : }
     365                 :             : 
     366                 :        3479 : int bf_handle_get_counter(const struct bf_handle *handle, uint32_t counter_idx,
     367                 :             :                           struct bf_counter *counter)
     368                 :             : {
     369                 :             :     int r;
     370                 :             : 
     371                 :             :     assert(handle);
     372                 :             :     assert(counter);
     373                 :             : 
     374         [ -  + ]:        3479 :     if (!handle->cmap)
     375         [ #  # ]:           0 :         return bf_err_r(-ENOENT, "handle has no counters map");
     376                 :             : 
     377                 :        3479 :     r = bf_bpf_map_lookup_elem(handle->cmap->fd, &counter_idx, counter);
     378         [ -  + ]:        3479 :     if (r < 0)
     379         [ #  # ]:           0 :         return bf_err_r(r, "failed to lookup counters map");
     380                 :             : 
     381                 :             :     return 0;
     382                 :             : }
     383                 :             : 
     384                 :         123 : int bf_handle_attach(struct bf_handle *handle, enum bf_hook hook,
     385                 :             :                      struct bf_hookopts **hookopts)
     386                 :             : {
     387                 :             :     int r;
     388                 :             : 
     389                 :             :     assert(handle);
     390                 :             :     assert(hookopts);
     391                 :             : 
     392         [ -  + ]:         123 :     if (handle->link)
     393         [ #  # ]:           0 :         return bf_err_r(-EEXIST, "program is already attached");
     394                 :             : 
     395                 :         123 :     r = bf_link_new(&handle->link, _BF_LINK_NAME, hook, hookopts,
     396                 :             :                     handle->prog_fd);
     397         [ +  + ]:         123 :     if (r)
     398         [ +  - ]:           4 :         return bf_err_r(r, "failed to attach bf_link");
     399                 :             : 
     400                 :             :     return 0;
     401                 :             : }
     402                 :             : 
     403                 :        1263 : void bf_handle_detach(struct bf_handle *handle)
     404                 :             : {
     405                 :             :     assert(handle);
     406                 :             : 
     407         [ +  + ]:        1263 :     if (handle->link) {
     408                 :         110 :         (void)bf_bpf_link_detach(handle->link->fd);
     409         [ +  + ]:         110 :         if (handle->link->fd_extra >= 0)
     410                 :           6 :             (void)bf_bpf_link_detach(handle->link->fd_extra);
     411                 :             :     }
     412                 :             : 
     413                 :        1263 :     bf_link_free(&handle->link);
     414                 :        1263 : }
     415                 :             : 
     416                 :        1263 : void bf_handle_unload(struct bf_handle *handle)
     417                 :             : {
     418                 :             :     assert(handle);
     419                 :             : 
     420                 :        1263 :     closep(&handle->prog_fd);
     421                 :             : 
     422                 :             :     /* Explicitly detach the BPF link before closing it. Relying solely on
     423                 :             :      * close() is not sufficient when the link is pinned (the pin holds a
     424                 :             :      * kernel reference that keeps the link alive). Using BPF_LINK_DETACH
     425                 :             :      * ensures the program is removed from the hook immediately. */
     426                 :        1263 :     bf_handle_detach(handle);
     427                 :             : 
     428                 :        1263 :     bf_link_free(&handle->link);
     429                 :        1263 :     bf_map_free(&handle->cmap);
     430                 :        1263 :     bf_map_free(&handle->pmap);
     431                 :        1263 :     bf_map_free(&handle->lmap);
     432                 :        1263 :     bf_list_clean(&handle->sets);
     433                 :        1263 : }
        

Generated by: LCOV version 2.0-1