LCOV - code coverage report
Current view: top level - bpfilter - ctx.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 87.0 % 184 160
Test Date: 2025-11-24 12:34:34 Functions: 100.0 % 27 27
Branches: 47.1 % 170 80

             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 "ctx.h"
       7                 :             : 
       8                 :             : #include <errno.h>
       9                 :             : #include <fcntl.h>
      10                 :             : #include <stdbool.h>
      11                 :             : #include <stdlib.h>
      12                 :             : #include <unistd.h>
      13                 :             : 
      14                 :             : #include <bpfilter/bpf.h>
      15                 :             : #include <bpfilter/btf.h>
      16                 :             : #include <bpfilter/chain.h>
      17                 :             : #include <bpfilter/dump.h>
      18                 :             : #include <bpfilter/front.h>
      19                 :             : #include <bpfilter/helper.h>
      20                 :             : #include <bpfilter/hook.h>
      21                 :             : #include <bpfilter/io.h>
      22                 :             : #include <bpfilter/list.h>
      23                 :             : #include <bpfilter/logger.h>
      24                 :             : #include <bpfilter/ns.h>
      25                 :             : #include <bpfilter/pack.h>
      26                 :             : 
      27                 :             : #include "cgen/cgen.h"
      28                 :             : #include "cgen/elfstub.h"
      29                 :             : #include "opts.h"
      30                 :             : 
      31                 :             : #define _free_bf_ctx_ __attribute__((cleanup(_bf_ctx_free)))
      32                 :             : 
      33                 :             : /**
      34                 :             :  * @struct bf_ctx
      35                 :             :  *
      36                 :             :  * bpfilter working context. Only one context is used during the daemon's
      37                 :             :  * lifetime.
      38                 :             :  */
      39                 :             : struct bf_ctx
      40                 :             : {
      41                 :             :     /// Namespaces the daemon was started in.
      42                 :             :     struct bf_ns ns;
      43                 :             : 
      44                 :             :     /// BPF token file descriptor
      45                 :             :     int token_fd;
      46                 :             : 
      47                 :             :     bf_list cgens;
      48                 :             : 
      49                 :             :     struct bf_elfstub *stubs[_BF_ELFSTUB_MAX];
      50                 :             : };
      51                 :             : 
      52                 :             : static void _bf_ctx_free(struct bf_ctx **ctx);
      53                 :             : 
      54                 :             : /// Global daemon context. Hidden in this translation unit.
      55                 :             : static struct bf_ctx *_bf_global_ctx = NULL;
      56                 :             : 
      57                 :          20 : static int _bf_ctx_gen_token(void)
      58                 :             : {
      59                 :          20 :     _cleanup_close_ int mnt_fd = -1;
      60                 :          20 :     _cleanup_close_ int bpffs_fd = -1;
      61                 :          20 :     _cleanup_close_ int token_fd = -1;
      62                 :             : 
      63                 :          20 :     mnt_fd = open(bf_opts_bpffs_path(), O_DIRECTORY);
      64         [ -  + ]:          20 :     if (mnt_fd < 0)
      65         [ #  # ]:           0 :         return bf_err_r(errno, "failed to open '%s'", bf_opts_bpffs_path());
      66                 :             : 
      67                 :          20 :     bpffs_fd = openat(mnt_fd, ".", 0, O_RDWR);
      68         [ -  + ]:          20 :     if (bpffs_fd < 0)
      69         [ #  # ]:           0 :         return bf_err_r(errno, "failed to get bpffs FD from '%s'",
      70                 :             :                         bf_opts_bpffs_path());
      71                 :             : 
      72                 :          20 :     token_fd = bf_bpf_token_create(bpffs_fd);
      73         [ -  + ]:          20 :     if (token_fd < 0) {
      74         [ #  # ]:           0 :         return bf_err_r(token_fd, "failed to create BPF token for '%s'",
      75                 :             :                         bf_opts_bpffs_path());
      76                 :             :     }
      77                 :             : 
      78                 :          20 :     return TAKE_FD(token_fd);
      79                 :             : }
      80                 :             : 
      81                 :             : /**
      82                 :             :  * Create and initialize a new context.
      83                 :             :  *
      84                 :             :  * On failure, @p ctx is left unchanged.
      85                 :             :  *
      86                 :             :  * @param ctx New context to create. Can't be NULL.
      87                 :             :  * @return 0 on success, negative errno value on failure.
      88                 :             :  */
      89                 :          20 : static int _bf_ctx_new(struct bf_ctx **ctx)
      90                 :             : {
      91                 :          20 :     _free_bf_ctx_ struct bf_ctx *_ctx = NULL;
      92                 :             :     int r;
      93                 :             : 
      94                 :             :     bf_assert(ctx);
      95                 :             : 
      96                 :          20 :     _ctx = calloc(1, sizeof(*_ctx));
      97         [ +  - ]:          20 :     if (!_ctx)
      98                 :             :         return -ENOMEM;
      99                 :             : 
     100                 :          20 :     r = bf_ns_init(&_ctx->ns, getpid());
     101         [ -  + ]:          20 :     if (r)
     102         [ #  # ]:           0 :         return bf_err_r(r, "failed to initialise current bf_ns");
     103                 :             : 
     104                 :          20 :     _ctx->token_fd = -1;
     105         [ +  - ]:          20 :     if (bf_opts_with_bpf_token()) {
     106                 :           0 :         _cleanup_close_ int token_fd = -1;
     107                 :             : 
     108                 :          20 :         r = bf_btf_kernel_has_token();
     109         [ -  + ]:          20 :         if (r == -ENOENT) {
     110         [ #  # ]:           0 :             bf_err(
     111                 :             :                 "--with-bpf-token requested, but this kernel doesn't support BPF token");
     112                 :           0 :             return r;
     113                 :             :         }
     114         [ -  + ]:          20 :         if (r)
     115         [ #  # ]:           0 :             return bf_err_r(r, "failed to check for BPF token support");
     116                 :             : 
     117                 :          20 :         token_fd = _bf_ctx_gen_token();
     118         [ -  + ]:          20 :         if (token_fd < 0)
     119         [ #  # ]:           0 :             return bf_err_r(token_fd, "failed to generate a BPF token");
     120                 :             : 
     121                 :          20 :         _ctx->token_fd = TAKE_FD(token_fd);
     122                 :             :     }
     123                 :             : 
     124                 :          20 :     _ctx->cgens = bf_list_default(bf_cgen_free, bf_cgen_pack);
     125                 :             : 
     126         [ +  + ]:         100 :     for (enum bf_elfstub_id id = 0; id < _BF_ELFSTUB_MAX; ++id) {
     127                 :          80 :         r = bf_elfstub_new(&_ctx->stubs[id], id);
     128         [ -  + ]:          80 :         if (r)
     129         [ #  # ]:           0 :             return bf_err_r(r, "failed to create ELF stub ID %u", id);
     130                 :             :     }
     131                 :             : 
     132                 :          20 :     *ctx = TAKE_PTR(_ctx);
     133                 :             : 
     134                 :          20 :     return 0;
     135                 :             : }
     136                 :             : 
     137                 :             : /**
     138                 :             :  * @brief Allocate and initialize a new context from serialized data.
     139                 :             :  *
     140                 :             :  * @param ctx Context object to allocate and initialize from the serialized
     141                 :             :  *        data. The caller will own the object. On failure, `*ctx` is
     142                 :             :  *        unchanged. Can't be NULL.
     143                 :             :  * @param node Node containing the serialized matcher.
     144                 :             :  * @return 0 on success, or a negative errno value on failure.
     145                 :             :  */
     146                 :           2 : static int _bf_ctx_new_from_pack(struct bf_ctx **ctx, bf_rpack_node_t node)
     147                 :             : {
     148                 :           2 :     _free_bf_ctx_ struct bf_ctx *_ctx = NULL;
     149                 :             :     bf_rpack_node_t child, array_node;
     150                 :             :     int r;
     151                 :             : 
     152                 :             :     bf_assert(ctx);
     153                 :             : 
     154                 :           2 :     r = _bf_ctx_new(&_ctx);
     155         [ +  - ]:           2 :     if (r < 0)
     156                 :             :         return r;
     157                 :             : 
     158                 :           2 :     r = bf_rpack_kv_array(node, "cgens", &child);
     159         [ +  - ]:           2 :     if (r)
     160                 :             :         return r;
     161   [ +  -  -  +  :           8 :     bf_rpack_array_foreach (child, array_node) {
                   +  + ]
     162                 :           0 :         _free_bf_cgen_ struct bf_cgen *cgen = NULL;
     163                 :             : 
     164   [ +  -  +  -  :           2 :         r = bf_list_emplace(&_ctx->cgens, bf_cgen_new_from_pack, cgen,
             -  -  -  - ]
     165                 :             :                             array_node);
     166                 :             :         if (r)
     167                 :             :             return r;
     168                 :             :     }
     169                 :             : 
     170                 :           2 :     *ctx = TAKE_PTR(_ctx);
     171                 :             : 
     172                 :           2 :     return 0;
     173                 :             : }
     174                 :             : 
     175                 :             : /**
     176                 :             :  * Free a context.
     177                 :             :  *
     178                 :             :  * If @p ctx points to a NULL pointer, this function does nothing. Once
     179                 :             :  * the function returns, @p ctx points to a NULL pointer.
     180                 :             :  *
     181                 :             :  * @param ctx Context to free. Can't be NULL.
     182                 :             :  */
     183                 :          61 : static void _bf_ctx_free(struct bf_ctx **ctx)
     184                 :             : {
     185                 :             :     bf_assert(ctx);
     186                 :             : 
     187         [ +  + ]:          61 :     if (!*ctx)
     188                 :             :         return;
     189                 :             : 
     190                 :          19 :     bf_ns_clean(&(*ctx)->ns);
     191                 :          19 :     closep(&(*ctx)->token_fd);
     192                 :          19 :     bf_list_clean(&(*ctx)->cgens);
     193                 :             : 
     194         [ +  + ]:          95 :     for (enum bf_elfstub_id id = 0; id < _BF_ELFSTUB_MAX; ++id)
     195                 :          76 :         bf_elfstub_free(&(*ctx)->stubs[id]);
     196                 :             : 
     197                 :             :     freep((void *)ctx);
     198                 :             : }
     199                 :             : 
     200                 :             : /**
     201                 :             :  * See @ref bf_ctx_dump for details.
     202                 :             :  */
     203                 :          20 : static void _bf_ctx_dump(const struct bf_ctx *ctx, prefix_t *prefix)
     204                 :             : {
     205         [ +  - ]:          20 :     DUMP(prefix, "struct bf_ctx at %p", ctx);
     206                 :             : 
     207                 :          20 :     bf_dump_prefix_push(prefix);
     208                 :             : 
     209                 :             :     // Namespaces
     210         [ +  - ]:          20 :     DUMP(prefix, "ns: struct bf_ns")
     211                 :          20 :     bf_dump_prefix_push(prefix);
     212                 :             : 
     213         [ +  - ]:          20 :     DUMP(prefix, "net: struct bf_ns_info");
     214                 :          20 :     bf_dump_prefix_push(prefix);
     215         [ +  - ]:          20 :     DUMP(prefix, "fd: %d", ctx->ns.net.fd);
     216         [ +  - ]:          20 :     DUMP(bf_dump_prefix_last(prefix), "inode: %u", ctx->ns.net.inode);
     217                 :          20 :     bf_dump_prefix_pop(prefix);
     218                 :             : 
     219         [ +  - ]:          20 :     DUMP(bf_dump_prefix_last(prefix), "mnt: struct bf_ns_info");
     220                 :          20 :     bf_dump_prefix_push(prefix);
     221         [ +  - ]:          20 :     DUMP(prefix, "fd: %d", ctx->ns.mnt.fd);
     222         [ +  - ]:          20 :     DUMP(bf_dump_prefix_last(prefix), "inode: %u", ctx->ns.mnt.inode);
     223                 :          20 :     bf_dump_prefix_pop(prefix);
     224                 :             : 
     225                 :          20 :     bf_dump_prefix_pop(prefix);
     226                 :             : 
     227         [ +  - ]:          20 :     DUMP(prefix, "token_fd: %d", ctx->token_fd);
     228                 :             : 
     229                 :             :     // Codegens
     230         [ +  - ]:          20 :     DUMP(bf_dump_prefix_last(prefix), "cgens: bf_list<struct bf_cgen>[%lu]",
     231                 :             :          bf_list_size(&ctx->cgens));
     232                 :          20 :     bf_dump_prefix_push(prefix);
     233   [ +  +  -  +  :          44 :     bf_list_foreach (&ctx->cgens, cgen_node) {
                   +  + ]
     234                 :             :         struct bf_cgen *cgen = bf_list_node_get_data(cgen_node);
     235                 :             : 
     236         [ +  - ]:           2 :         if (bf_list_is_tail(&ctx->cgens, cgen_node))
     237                 :           2 :             bf_dump_prefix_last(prefix);
     238                 :             : 
     239                 :           2 :         bf_cgen_dump(cgen, prefix);
     240                 :             :     }
     241                 :          20 :     bf_dump_prefix_pop(prefix);
     242                 :             : 
     243                 :          20 :     bf_dump_prefix_pop(prefix);
     244                 :          20 : }
     245                 :             : 
     246                 :             : /**
     247                 :             :  * @brief Serialize a context.
     248                 :             :  *
     249                 :             :  * The context is serialized as:
     250                 :             :  * @code
     251                 :             :  * {
     252                 :             :  *   "cgens": [
     253                 :             :  *     { bf_codegen },
     254                 :             :  *     // ...
     255                 :             :  *   ]
     256                 :             :  * }
     257                 :             :  * @endcode
     258                 :             :  *
     259                 :             :  * @param ctx Context to serialize. Can't be NULL.
     260                 :             :  * @param pack `bf_wpack_t` object to serialize the context into. Can't be NULL.
     261                 :             :  * @return 0 on success, or a negative error value on failure.
     262                 :             :  */
     263                 :          77 : static int _bf_ctx_pack(const struct bf_ctx *ctx, bf_wpack_t *pack)
     264                 :             : {
     265                 :             :     bf_assert(ctx);
     266                 :             :     bf_assert(pack);
     267                 :             : 
     268                 :          77 :     bf_wpack_kv_list(pack, "cgens", &ctx->cgens);
     269                 :             : 
     270         [ -  + ]:          77 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     271                 :             : }
     272                 :             : 
     273                 :             : /**
     274                 :             :  * See @ref bf_ctx_get_cgen for details.
     275                 :             :  */
     276                 :         142 : static struct bf_cgen *_bf_ctx_get_cgen(const struct bf_ctx *ctx,
     277                 :             :                                         const char *name)
     278                 :             : {
     279                 :             :     bf_assert(ctx && name);
     280                 :             : 
     281   [ +  +  +  +  :         524 :     bf_list_foreach (&ctx->cgens, cgen_node) {
                   +  + ]
     282                 :             :         struct bf_cgen *cgen = bf_list_node_get_data(cgen_node);
     283                 :             : 
     284         [ +  + ]:         194 :         if (bf_streq(cgen->chain->name, name))
     285                 :             :             return cgen;
     286                 :             :     }
     287                 :             : 
     288                 :             :     return NULL;
     289                 :             : }
     290                 :             : 
     291                 :             : /**
     292                 :             :  * See @ref bf_ctx_get_cgens_for_front for details.
     293                 :             :  */
     294                 :           4 : static int _bf_ctx_get_cgens_for_front(const struct bf_ctx *ctx, bf_list *cgens,
     295                 :             :                                        enum bf_front front)
     296                 :             : {
     297                 :           4 :     _clean_bf_list_ bf_list _cgens =
     298                 :           4 :         bf_list_default(cgens->ops.free, cgens->ops.pack);
     299                 :             :     int r;
     300                 :             : 
     301                 :             :     bf_assert(ctx && cgens);
     302                 :             : 
     303   [ +  -  +  +  :          18 :     bf_list_foreach (&ctx->cgens, cgen_node) {
                   +  + ]
     304                 :             :         struct bf_cgen *cgen = bf_list_node_get_data(cgen_node);
     305                 :             : 
     306         [ -  + ]:           5 :         if (cgen->front != front)
     307                 :           0 :             continue;
     308                 :             : 
     309                 :           5 :         r = bf_list_add_tail(&_cgens, cgen);
     310         [ -  + ]:           5 :         if (r)
     311         [ #  # ]:           0 :             return bf_err_r(r, "failed to insert codegen into list");
     312                 :             :     }
     313                 :             : 
     314                 :           4 :     *cgens = bf_list_move(_cgens);
     315                 :             : 
     316                 :           4 :     return 0;
     317                 :             : }
     318                 :             : 
     319                 :             : /**
     320                 :             :  * See @ref bf_ctx_set_cgen for details.
     321                 :             :  */
     322                 :          55 : static int _bf_ctx_set_cgen(struct bf_ctx *ctx, struct bf_cgen *cgen)
     323                 :             : {
     324                 :             :     bf_assert(ctx && cgen);
     325                 :             : 
     326         [ -  + ]:          55 :     if (_bf_ctx_get_cgen(ctx, cgen->chain->name))
     327         [ #  # ]:           0 :         return bf_err_r(-EEXIST, "codegen already exists in context");
     328                 :             : 
     329                 :          55 :     return bf_list_add_tail(&ctx->cgens, cgen);
     330                 :             : }
     331                 :             : 
     332                 :          30 : static int _bf_ctx_delete_cgen(struct bf_ctx *ctx, struct bf_cgen *cgen,
     333                 :             :                                bool unload)
     334                 :             : {
     335   [ +  -  +  - ]:          66 :     bf_list_foreach (&ctx->cgens, cgen_node) {
     336                 :             :         struct bf_cgen *_cgen = bf_list_node_get_data(cgen_node);
     337                 :             : 
     338   [ +  +  -  + ]:          33 :         if (_cgen != cgen)
     339                 :             :             continue;
     340                 :             : 
     341         [ +  - ]:          30 :         if (unload)
     342                 :          30 :             bf_cgen_unload(_cgen);
     343                 :             : 
     344                 :          30 :         bf_list_delete(&ctx->cgens, cgen_node);
     345                 :             : 
     346                 :          30 :         return 0;
     347                 :             :     }
     348                 :             : 
     349                 :             :     return -ENOENT;
     350                 :             : }
     351                 :             : 
     352                 :          18 : int bf_ctx_setup(void)
     353                 :             : {
     354                 :          18 :     _free_bf_ctx_ struct bf_ctx *_ctx = NULL;
     355                 :             :     int r;
     356                 :             : 
     357                 :             :     bf_assert(!_ctx);
     358                 :             : 
     359                 :          18 :     r = _bf_ctx_new(&_ctx);
     360         [ -  + ]:          18 :     if (r)
     361         [ #  # ]:           0 :         return bf_err_r(r, "failed to create new context");
     362                 :             : 
     363                 :          18 :     _bf_global_ctx = TAKE_PTR(_ctx);
     364                 :             : 
     365                 :          18 :     return 0;
     366                 :             : }
     367                 :             : 
     368                 :          19 : void bf_ctx_teardown(bool clear)
     369                 :             : {
     370         [ -  + ]:          19 :     if (clear) {
     371   [ #  #  #  #  :           0 :         bf_list_foreach (&_bf_global_ctx->cgens, cgen_node)
                   #  # ]
     372                 :           0 :             bf_cgen_unload(bf_list_node_get_data(cgen_node));
     373                 :             :     }
     374                 :             : 
     375                 :          19 :     _bf_ctx_free(&_bf_global_ctx);
     376                 :          19 : }
     377                 :             : 
     378                 :          77 : int bf_ctx_save(bf_wpack_t *pack)
     379                 :             : {
     380                 :             :     int r;
     381                 :             : 
     382                 :             :     bf_assert(pack);
     383                 :             : 
     384                 :          77 :     r = _bf_ctx_pack(_bf_global_ctx, pack);
     385         [ -  + ]:          77 :     if (r)
     386         [ #  # ]:           0 :         return bf_err_r(r, "failed to serialize context");
     387                 :             : 
     388                 :             :     return 0;
     389                 :             : }
     390                 :             : 
     391                 :           2 : int bf_ctx_load(bf_rpack_node_t node)
     392                 :             : {
     393                 :           2 :     _free_bf_ctx_ struct bf_ctx *ctx = NULL;
     394                 :             :     int r;
     395                 :             : 
     396                 :           2 :     r = _bf_ctx_new_from_pack(&ctx, node);
     397         [ -  + ]:           2 :     if (r)
     398         [ #  # ]:           0 :         return bf_err_r(r, "failed to deserialize context");
     399                 :             : 
     400                 :           2 :     _bf_global_ctx = TAKE_PTR(ctx);
     401                 :             : 
     402                 :           2 :     return 0;
     403                 :             : }
     404                 :             : 
     405                 :          12 : static void _bf_ctx_flush(struct bf_ctx *ctx, enum bf_front front)
     406                 :             : {
     407                 :             :     bf_assert(ctx);
     408                 :             : 
     409   [ +  +  +  +  :          36 :     bf_list_foreach (&ctx->cgens, cgen_node) {
                   +  + ]
     410                 :             :         struct bf_cgen *cgen = bf_list_node_get_data(cgen_node);
     411                 :             : 
     412         [ -  + ]:           6 :         if (cgen->front != front)
     413                 :           0 :             continue;
     414                 :             : 
     415                 :           6 :         bf_cgen_unload(cgen);
     416                 :           6 :         bf_list_delete(&ctx->cgens, cgen_node);
     417                 :             :     }
     418                 :          12 : }
     419                 :             : 
     420                 :          12 : void bf_ctx_flush(enum bf_front front)
     421                 :             : {
     422                 :          12 :     _bf_ctx_flush(_bf_global_ctx, front);
     423                 :          12 : }
     424                 :             : 
     425                 :         108 : bool bf_ctx_is_empty(void)
     426                 :             : {
     427                 :         108 :     return bf_list_is_empty(&_bf_global_ctx->cgens);
     428                 :             : }
     429                 :             : 
     430                 :          20 : void bf_ctx_dump(prefix_t *prefix)
     431                 :             : {
     432                 :          20 :     _bf_ctx_dump(_bf_global_ctx, prefix);
     433                 :          20 : }
     434                 :             : 
     435                 :          87 : struct bf_cgen *bf_ctx_get_cgen(const char *name)
     436                 :             : {
     437                 :          87 :     return _bf_ctx_get_cgen(_bf_global_ctx, name);
     438                 :             : }
     439                 :             : 
     440                 :           4 : int bf_ctx_get_cgens_for_front(bf_list *cgens, enum bf_front front)
     441                 :             : {
     442                 :           4 :     return _bf_ctx_get_cgens_for_front(_bf_global_ctx, cgens, front);
     443                 :             : }
     444                 :             : 
     445                 :          55 : int bf_ctx_set_cgen(struct bf_cgen *cgen)
     446                 :             : {
     447                 :          55 :     return _bf_ctx_set_cgen(_bf_global_ctx, cgen);
     448                 :             : }
     449                 :             : 
     450                 :          30 : int bf_ctx_delete_cgen(struct bf_cgen *cgen, bool unload)
     451                 :             : {
     452                 :          30 :     return _bf_ctx_delete_cgen(_bf_global_ctx, cgen, unload);
     453                 :             : }
     454                 :             : 
     455                 :          46 : struct bf_ns *bf_ctx_get_ns(void)
     456                 :             : {
     457                 :          46 :     return &_bf_global_ctx->ns;
     458                 :             : }
     459                 :             : 
     460                 :         380 : int bf_ctx_token(void)
     461                 :             : {
     462                 :         380 :     return _bf_global_ctx->token_fd;
     463                 :             : }
     464                 :             : 
     465                 :         166 : int bf_ctx_get_pindir_fd(void)
     466                 :             : {
     467                 :         166 :     _cleanup_close_ int bpffs_fd = -1;
     468                 :         166 :     _cleanup_close_ int pindir_fd = -1;
     469                 :             : 
     470                 :         166 :     bpffs_fd = bf_opendir(bf_opts_bpffs_path());
     471         [ -  + ]:         166 :     if (bpffs_fd < 0) {
     472         [ #  # ]:           0 :         return bf_err_r(bpffs_fd, "failed to open bpffs at %s",
     473                 :             :                         bf_opts_bpffs_path());
     474                 :             :     }
     475                 :             : 
     476                 :         166 :     pindir_fd = bf_opendir_at(bpffs_fd, "bpfilter", true);
     477         [ -  + ]:         166 :     if (pindir_fd < 0) {
     478         [ #  # ]:           0 :         return bf_err_r(pindir_fd, "failed to open pin directory %s/bpfilter",
     479                 :             :                         bf_opts_bpffs_path());
     480                 :             :     }
     481                 :             : 
     482                 :         166 :     return TAKE_FD(pindir_fd);
     483                 :             : }
     484                 :             : 
     485                 :          19 : int bf_ctx_rm_pindir(void)
     486                 :             : {
     487                 :          19 :     _cleanup_close_ int bpffs_fd = -1;
     488                 :             :     int r;
     489                 :             : 
     490                 :          19 :     bpffs_fd = bf_opendir(bf_opts_bpffs_path());
     491         [ -  + ]:          19 :     if (bpffs_fd < 0) {
     492         [ #  # ]:           0 :         return bf_err_r(bpffs_fd, "failed to open bpffs at %s",
     493                 :             :                         bf_opts_bpffs_path());
     494                 :             :     }
     495                 :             : 
     496                 :          19 :     r = bf_rmdir_at(bpffs_fd, "bpfilter", false);
     497   [ +  +  -  + ]:          19 :     if (r < 0 && r != -ENOTEMPTY && r != -ENOENT)
     498         [ #  # ]:           0 :         return bf_err_r(r, "failed to remove bpfilter bpffs directory");
     499                 :             : 
     500                 :             :     return 0;
     501                 :             : }
     502                 :             : 
     503                 :         144 : const struct bf_elfstub *bf_ctx_get_elfstub(enum bf_elfstub_id id)
     504                 :             : {
     505                 :         144 :     return _bf_global_ctx->stubs[id];
     506                 :             : }
        

Generated by: LCOV version 2.0-1