LCOV - code coverage report
Current view: top level - lib/bpf - bpf_load_elf.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 4 119 3.4 %
Date: 2026-07-01 18:02:41 Functions: 1 10 10.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 100 1.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2018 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "bpf_impl.h"
       6                 :            : 
       7                 :            : #include <errno.h>
       8                 :            : 
       9                 :            : #ifdef RTE_LIBRTE_BPF_ELF
      10                 :            : 
      11                 :            : #include <stdarg.h>
      12                 :            : #include <stdio.h>
      13                 :            : #include <string.h>
      14                 :            : #include <stdint.h>
      15                 :            : #include <unistd.h>
      16                 :            : #include <inttypes.h>
      17                 :            : 
      18                 :            : #include <sys/types.h>
      19                 :            : #include <sys/stat.h>
      20                 :            : #include <sys/queue.h>
      21                 :            : #include <fcntl.h>
      22                 :            : 
      23                 :            : #include <libelf.h>
      24                 :            : 
      25                 :            : #include <eal_export.h>
      26                 :            : #include <rte_common.h>
      27                 :            : #include <rte_log.h>
      28                 :            : #include <rte_debug.h>
      29                 :            : #include <rte_memory.h>
      30                 :            : #include <rte_eal.h>
      31                 :            : #include <rte_byteorder.h>
      32                 :            : #include <rte_errno.h>
      33                 :            : 
      34                 :            : /* To overcome compatibility issue */
      35                 :            : #ifndef EM_BPF
      36                 :            : #define EM_BPF  247
      37                 :            : #endif
      38                 :            : 
      39                 :            : static uint32_t
      40                 :          0 : bpf_find_xsym(const char *sn, enum rte_bpf_xtype type,
      41                 :            :         const struct rte_bpf_xsym fp[], uint32_t fn)
      42                 :            : {
      43                 :            :         uint32_t i;
      44                 :            : 
      45         [ #  # ]:          0 :         if (sn == NULL || fp == NULL)
      46                 :            :                 return UINT32_MAX;
      47                 :            : 
      48         [ #  # ]:          0 :         for (i = 0; i != fn; i++) {
      49   [ #  #  #  # ]:          0 :                 if (fp[i].type == type && strcmp(sn, fp[i].name) == 0)
      50                 :            :                         break;
      51                 :            :         }
      52                 :            : 
      53         [ #  # ]:          0 :         return (i != fn) ? i : UINT32_MAX;
      54                 :            : }
      55                 :            : 
      56                 :            : /*
      57                 :            :  * update BPF code at offset *ofs* with a proper address(index) for external
      58                 :            :  * symbol *sn*
      59                 :            :  */
      60                 :            : static int
      61                 :          0 : resolve_xsym(const char *sn, size_t ofs, struct ebpf_insn *ins, size_t ins_sz,
      62                 :            :         const struct rte_bpf_prm_ex *prm)
      63                 :            : {
      64                 :            :         uint32_t idx, fidx;
      65                 :            :         enum rte_bpf_xtype type;
      66                 :            : 
      67   [ #  #  #  # ]:          0 :         if (ofs % sizeof(ins[0]) != 0 || ofs >= ins_sz)
      68                 :            :                 return -EINVAL;
      69                 :            : 
      70                 :          0 :         idx = ofs / sizeof(ins[0]);
      71         [ #  # ]:          0 :         if (ins[idx].code == (BPF_JMP | EBPF_CALL))
      72                 :            :                 type = RTE_BPF_XTYPE_FUNC;
      73         [ #  # ]:          0 :         else if (ins[idx].code == (BPF_LD | BPF_IMM | EBPF_DW) &&
      74         [ #  # ]:          0 :                         ofs < ins_sz - sizeof(ins[idx]))
      75                 :            :                 type = RTE_BPF_XTYPE_VAR;
      76                 :            :         else
      77                 :            :                 return -EINVAL;
      78                 :            : 
      79                 :          0 :         fidx = bpf_find_xsym(sn, type, prm->xsym, prm->nb_xsym);
      80         [ #  # ]:          0 :         if (fidx == UINT32_MAX)
      81                 :            :                 return -ENOENT;
      82                 :            : 
      83                 :            :         /* for function we just need an index in our xsym table */
      84         [ #  # ]:          0 :         if (type == RTE_BPF_XTYPE_FUNC) {
      85                 :            : 
      86                 :            :                 /* we don't support multiple functions per BPF module,
      87                 :            :                  * so treat EBPF_PSEUDO_CALL to external function
      88                 :            :                  * as an ordinary EBPF_CALL.
      89                 :            :                  */
      90         [ #  # ]:          0 :                 if (ins[idx].src_reg == EBPF_PSEUDO_CALL) {
      91                 :          0 :                         RTE_BPF_LOG_LINE(INFO, "%s(%u): "
      92                 :            :                                 "EBPF_PSEUDO_CALL to external function: %s",
      93                 :            :                                 __func__, idx, sn);
      94                 :          0 :                         ins[idx].src_reg = EBPF_REG_0;
      95                 :            :                 }
      96                 :          0 :                 ins[idx].imm = fidx;
      97                 :            :         /* for variable we need to store its absolute address */
      98                 :            :         } else {
      99                 :          0 :                 ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val;
     100                 :          0 :                 ins[idx + 1].imm =
     101                 :          0 :                         (uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32;
     102                 :            :         }
     103                 :            : 
     104                 :            :         return 0;
     105                 :            : }
     106                 :            : 
     107                 :            : static int
     108                 :          0 : check_elf_header(const Elf64_Ehdr *eh)
     109                 :            : {
     110                 :            :         const char *err;
     111                 :            : 
     112                 :            :         err = NULL;
     113                 :            : 
     114                 :            : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
     115         [ #  # ]:          0 :         if (eh->e_ident[EI_DATA] != ELFDATA2LSB)
     116                 :            : #else
     117                 :            :         if (eh->e_ident[EI_DATA] != ELFDATA2MSB)
     118                 :            : #endif
     119                 :            :                 err = "not native byte order";
     120         [ #  # ]:          0 :         else if (eh->e_ident[EI_OSABI] != ELFOSABI_NONE)
     121                 :            :                 err = "unexpected OS ABI";
     122         [ #  # ]:          0 :         else if (eh->e_type != ET_REL)
     123                 :            :                 err = "unexpected ELF type";
     124         [ #  # ]:          0 :         else if (eh->e_machine != EM_NONE && eh->e_machine != EM_BPF)
     125                 :            :                 err = "unexpected machine type";
     126                 :            : 
     127                 :            :         if (err != NULL) {
     128                 :          0 :                 RTE_BPF_LOG_FUNC_LINE(ERR, "%s", err);
     129                 :          0 :                 return -EINVAL;
     130                 :            :         }
     131                 :            : 
     132                 :            :         return 0;
     133                 :            : }
     134                 :            : 
     135                 :            : /*
     136                 :            :  * helper function, find executable section by name.
     137                 :            :  */
     138                 :            : static int
     139                 :          0 : find_elf_code(Elf *elf, const char *section, Elf_Data **psd, size_t *pidx)
     140                 :            : {
     141                 :            :         Elf_Scn *sc;
     142                 :            :         const Elf64_Ehdr *eh;
     143                 :            :         const Elf64_Shdr *sh;
     144                 :            :         Elf_Data *sd;
     145                 :            :         const char *sn;
     146                 :            :         int32_t rc;
     147                 :            : 
     148                 :          0 :         eh = elf64_getehdr(elf);
     149         [ #  # ]:          0 :         if (eh == NULL) {
     150                 :          0 :                 rc = elf_errno();
     151                 :          0 :                 RTE_BPF_LOG_LINE(ERR, "%s(%p, %s) error code: %d(%s)",
     152                 :            :                         __func__, elf, section, rc, elf_errmsg(rc));
     153                 :          0 :                 return -EINVAL;
     154                 :            :         }
     155                 :            : 
     156         [ #  # ]:          0 :         if (check_elf_header(eh) != 0)
     157                 :            :                 return -EINVAL;
     158                 :            : 
     159                 :            :         /* find given section by name */
     160         [ #  # ]:          0 :         for (sc = elf_nextscn(elf, NULL); sc != NULL;
     161                 :          0 :                         sc = elf_nextscn(elf, sc)) {
     162                 :          0 :                 sh = elf64_getshdr(sc);
     163                 :          0 :                 sn = elf_strptr(elf, eh->e_shstrndx, sh->sh_name);
     164   [ #  #  #  # ]:          0 :                 if (sn != NULL && strcmp(section, sn) == 0 &&
     165         [ #  # ]:          0 :                                 sh->sh_type == SHT_PROGBITS &&
     166         [ #  # ]:          0 :                                 sh->sh_flags == (SHF_ALLOC | SHF_EXECINSTR))
     167                 :            :                         break;
     168                 :            :         }
     169                 :            : 
     170                 :          0 :         sd = elf_getdata(sc, NULL);
     171   [ #  #  #  # ]:          0 :         if (sd == NULL || sd->d_size == 0 ||
     172         [ #  # ]:          0 :                         sd->d_size % sizeof(struct ebpf_insn) != 0) {
     173                 :          0 :                 rc = elf_errno();
     174                 :          0 :                 RTE_BPF_LOG_LINE(ERR, "%s(%p, %s) error code: %d(%s)",
     175                 :            :                         __func__, elf, section, rc, elf_errmsg(rc));
     176                 :          0 :                 return -EINVAL;
     177                 :            :         }
     178                 :            : 
     179                 :          0 :         *psd = sd;
     180                 :          0 :         *pidx = elf_ndxscn(sc);
     181                 :          0 :         return 0;
     182                 :            : }
     183                 :            : 
     184                 :            : /*
     185                 :            :  * helper function to process data from relocation table.
     186                 :            :  */
     187                 :            : static int
     188                 :          0 : process_reloc(Elf *elf, size_t sym_idx, Elf64_Rel *re, size_t re_sz,
     189                 :            :         struct ebpf_insn *ins, size_t ins_sz, const struct rte_bpf_prm_ex *prm)
     190                 :            : {
     191                 :            :         int32_t rc;
     192                 :            :         uint32_t i, n;
     193                 :            :         size_t ofs, sym;
     194                 :            :         const char *sn;
     195                 :            :         const Elf64_Ehdr *eh;
     196                 :            :         Elf_Scn *sc;
     197                 :            :         const Elf_Data *sd;
     198                 :            :         Elf64_Sym *sm;
     199                 :            : 
     200                 :          0 :         eh = elf64_getehdr(elf);
     201                 :            : 
     202                 :            :         /* get symtable by section index */
     203                 :          0 :         sc = elf_getscn(elf, sym_idx);
     204                 :          0 :         sd = elf_getdata(sc, NULL);
     205         [ #  # ]:          0 :         if (sd == NULL)
     206                 :            :                 return -EINVAL;
     207                 :          0 :         sm = sd->d_buf;
     208                 :            : 
     209                 :          0 :         n = re_sz / sizeof(re[0]);
     210         [ #  # ]:          0 :         for (i = 0; i != n; i++) {
     211                 :            : 
     212                 :          0 :                 ofs = re[i].r_offset;
     213                 :            : 
     214                 :            :                 /* retrieve index in the symtable */
     215                 :          0 :                 sym = ELF64_R_SYM(re[i].r_info);
     216         [ #  # ]:          0 :                 if (sym * sizeof(sm[0]) >= sd->d_size)
     217                 :            :                         return -EINVAL;
     218                 :            : 
     219                 :          0 :                 sn = elf_strptr(elf, eh->e_shstrndx, sm[sym].st_name);
     220                 :            : 
     221                 :          0 :                 rc = resolve_xsym(sn, ofs, ins, ins_sz, prm);
     222         [ #  # ]:          0 :                 if (rc != 0) {
     223                 :          0 :                         RTE_BPF_LOG_LINE(ERR,
     224                 :            :                                 "resolve_xsym(%s, %zu) error code: %d",
     225                 :            :                                 sn, ofs, rc);
     226                 :          0 :                         return rc;
     227                 :            :                 }
     228                 :            :         }
     229                 :            : 
     230                 :            :         return 0;
     231                 :            : }
     232                 :            : 
     233                 :            : /*
     234                 :            :  * helper function, find relocation information (if any)
     235                 :            :  * and update bpf code.
     236                 :            :  */
     237                 :            : static int
     238                 :          0 : elf_reloc_code(Elf *elf, struct ebpf_insn *ins, size_t ins_sz, size_t sidx,
     239                 :            :         const struct rte_bpf_prm_ex *prm)
     240                 :            : {
     241                 :            :         Elf64_Rel *re;
     242                 :            :         Elf_Scn *sc;
     243                 :            :         const Elf64_Shdr *sh;
     244                 :            :         const Elf_Data *sd;
     245                 :            :         int32_t rc;
     246                 :            : 
     247                 :            :         rc = 0;
     248                 :            : 
     249                 :            :         /* walk through all sections */
     250         [ #  # ]:          0 :         for (sc = elf_nextscn(elf, NULL); sc != NULL && rc == 0;
     251                 :          0 :                         sc = elf_nextscn(elf, sc)) {
     252                 :            : 
     253                 :          0 :                 sh = elf64_getshdr(sc);
     254                 :            : 
     255                 :            :                 /* relocation data for our code section */
     256   [ #  #  #  # ]:          0 :                 if (sh->sh_type == SHT_REL && sh->sh_info == sidx) {
     257                 :          0 :                         sd = elf_getdata(sc, NULL);
     258   [ #  #  #  # ]:          0 :                         if (sd == NULL || sd->d_size == 0 ||
     259         [ #  # ]:          0 :                                         sd->d_size % sizeof(re[0]) != 0)
     260                 :            :                                 return -EINVAL;
     261                 :          0 :                         rc = process_reloc(elf, sh->sh_link,
     262                 :          0 :                                 sd->d_buf, sd->d_size, ins, ins_sz,
     263                 :            :                                 prm);
     264                 :            :                 }
     265                 :            :         }
     266                 :            : 
     267                 :            :         return rc;
     268                 :            : }
     269                 :            : 
     270                 :            : void
     271                 :        425 : __rte_bpf_load_elf_cleanup(struct __rte_bpf_load *load)
     272                 :            : {
     273                 :        425 :         elf_end(load->elf);
     274                 :            : 
     275   [ -  +  -  - ]:        425 :         if (load->elf_fd >= 0 && close(load->elf_fd) < 0) {
     276                 :          0 :                 const int close_errno = errno;
     277                 :          0 :                 RTE_BPF_LOG_FUNC_LINE(ERR, "error %d closing: %s",
     278                 :            :                         close_errno, strerror(close_errno));
     279                 :            :         }
     280                 :        425 : }
     281                 :            : 
     282                 :            : int
     283                 :          0 : __rte_bpf_load_elf_file(struct __rte_bpf_load *load)
     284                 :            : {
     285                 :            :         const struct rte_bpf_prm_ex *const prm = &load->prm;
     286                 :            : 
     287                 :            :         RTE_ASSERT(prm->origin == RTE_BPF_ORIGIN_ELF_FILE);
     288                 :            : 
     289   [ #  #  #  # ]:          0 :         if (prm->elf_file.path == NULL || prm->elf_file.section == NULL)
     290                 :            :                 return -EINVAL;
     291                 :            : 
     292         [ #  # ]:          0 :         if (elf_version(EV_CURRENT) == EV_NONE)
     293                 :            :                 return -ENOTSUP;
     294                 :            : 
     295                 :          0 :         load->elf_fd = open(prm->elf_file.path, O_RDONLY);
     296         [ #  # ]:          0 :         if (load->elf_fd < 0) {
     297                 :          0 :                 const int open_errno = errno;
     298                 :          0 :                 RTE_BPF_LOG_FUNC_LINE(ERR, "error %d opening \"%s\": %s",
     299                 :            :                         open_errno, prm->elf_file.path, strerror(open_errno));
     300                 :          0 :                 return -open_errno;
     301                 :            :         }
     302                 :            : 
     303                 :          0 :         load->elf = elf_begin(load->elf_fd, ELF_C_READ, NULL);
     304         [ #  # ]:          0 :         if (load->elf == NULL) {
     305                 :          0 :                 const int rc = elf_errno();
     306                 :          0 :                 RTE_BPF_LOG_FUNC_LINE(ERR, "error %d opening ELF \"%s\": %s",
     307                 :            :                         rc, prm->elf_file.path, elf_errmsg(rc));
     308                 :          0 :                 return -EINVAL;
     309                 :            :         }
     310                 :            : 
     311                 :          0 :         load->elf_section = prm->elf_file.section;
     312                 :            : 
     313                 :          0 :         return 0;
     314                 :            : }
     315                 :            : 
     316                 :            : int
     317                 :          0 : __rte_bpf_load_elf_memory(struct __rte_bpf_load *load)
     318                 :            : {
     319                 :            :         const struct rte_bpf_prm_ex *const prm = &load->prm;
     320                 :            : 
     321                 :            :         RTE_ASSERT(prm->origin == RTE_BPF_ORIGIN_ELF_MEMORY);
     322                 :            : 
     323   [ #  #  #  # ]:          0 :         if (prm->elf_memory.data == NULL || prm->elf_memory.section == NULL)
     324                 :            :                 return -EINVAL;
     325                 :            : 
     326         [ #  # ]:          0 :         if (elf_version(EV_CURRENT) == EV_NONE)
     327                 :            :                 return -ENOTSUP;
     328                 :            : 
     329                 :          0 :         load->elf = elf_memory(
     330                 :            :                 /* Cast away const, we are not going to modify the ELF image. */
     331                 :          0 :                 (char *)(uintptr_t)prm->elf_memory.data, prm->elf_memory.size);
     332         [ #  # ]:          0 :         if (load->elf == NULL) {
     333                 :          0 :                 const int rc = elf_errno();
     334                 :          0 :                 RTE_BPF_LOG_FUNC_LINE(ERR, "error %d opening ELF image: %s",
     335                 :            :                         rc, elf_errmsg(rc));
     336                 :          0 :                 return -EINVAL;
     337                 :            :         }
     338                 :            : 
     339                 :          0 :         load->elf_section = prm->elf_memory.section;
     340                 :            : 
     341                 :          0 :         return 0;
     342                 :            : }
     343                 :            : 
     344                 :            : int
     345                 :          0 : __rte_bpf_load_elf_code(struct __rte_bpf_load *load)
     346                 :            : {
     347                 :          0 :         struct rte_bpf_prm_ex *const prm = &load->prm;
     348                 :            :         Elf_Data *sd;
     349                 :            :         size_t sidx;
     350                 :            :         int rc;
     351                 :            : 
     352                 :          0 :         rc = find_elf_code(load->elf, load->elf_section, &sd, &sidx);
     353         [ #  # ]:          0 :         if (rc < 0)
     354                 :            :                 return rc;
     355                 :            : 
     356                 :          0 :         prm->origin = RTE_BPF_ORIGIN_RAW;
     357                 :          0 :         prm->raw.ins = sd->d_buf;
     358                 :          0 :         prm->raw.nb_ins = sd->d_size / sizeof(struct ebpf_insn);
     359                 :            : 
     360                 :          0 :         rc = elf_reloc_code(load->elf, sd->d_buf, sd->d_size, sidx, prm);
     361         [ #  # ]:          0 :         if (rc < 0)
     362                 :          0 :                 return -EINVAL;
     363                 :            : 
     364                 :            :         return 0;
     365                 :            : }
     366                 :            : 
     367                 :            : #else /* RTE_LIBRTE_BPF_ELF */
     368                 :            : 
     369                 :            : void
     370                 :            : __rte_bpf_load_elf_cleanup(struct __rte_bpf_load *load)
     371                 :            : {
     372                 :            :         RTE_ASSERT(load->elf == NULL);
     373                 :            :         RTE_ASSERT(load->elf_fd < 0);
     374                 :            : }
     375                 :            : 
     376                 :            : int
     377                 :            : __rte_bpf_load_elf_file(struct __rte_bpf_load *load)
     378                 :            : {
     379                 :            :         RTE_SET_USED(load);
     380                 :            :         RTE_BPF_LOG_FUNC_LINE(ERR, "not supported, rebuild with libelf installed");
     381                 :            :         return -ENOTSUP;
     382                 :            : }
     383                 :            : 
     384                 :            : int
     385                 :            : __rte_bpf_load_elf_memory(struct __rte_bpf_load *load)
     386                 :            : {
     387                 :            :         RTE_SET_USED(load);
     388                 :            :         RTE_BPF_LOG_FUNC_LINE(ERR, "not supported, rebuild with libelf installed");
     389                 :            :         return -ENOTSUP;
     390                 :            : }
     391                 :            : 
     392                 :            : int
     393                 :            : __rte_bpf_load_elf_code(struct __rte_bpf_load *load)
     394                 :            : {
     395                 :            :         RTE_SET_USED(load);
     396                 :            :         RTE_BPF_LOG_FUNC_LINE(ERR, "not supported, rebuild with libelf installed");
     397                 :            :         return -ENOTSUP;
     398                 :            : }
     399                 :            : 
     400                 :            : #endif /* RTE_LIBRTE_BPF_ELF */

Generated by: LCOV version 1.14