LCOV - code coverage report
Current view: top level - lib/bpf - bpf_load_elf.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 107 0.0 %
Date: 2024-12-01 18:57:19 Functions: 0 8 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 86 0.0 %

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

Generated by: LCOV version 1.14