199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2018 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <stdarg.h>
699a2dd95SBruce Richardson #include <stdio.h>
799a2dd95SBruce Richardson #include <string.h>
899a2dd95SBruce Richardson #include <errno.h>
999a2dd95SBruce Richardson #include <stdint.h>
1099a2dd95SBruce Richardson #include <unistd.h>
1199a2dd95SBruce Richardson #include <inttypes.h>
1299a2dd95SBruce Richardson
1399a2dd95SBruce Richardson #include <sys/types.h>
1499a2dd95SBruce Richardson #include <sys/stat.h>
1599a2dd95SBruce Richardson #include <sys/queue.h>
1699a2dd95SBruce Richardson #include <fcntl.h>
1799a2dd95SBruce Richardson
1899a2dd95SBruce Richardson #include <libelf.h>
1999a2dd95SBruce Richardson
2099a2dd95SBruce Richardson #include <rte_common.h>
2199a2dd95SBruce Richardson #include <rte_log.h>
2299a2dd95SBruce Richardson #include <rte_debug.h>
2399a2dd95SBruce Richardson #include <rte_memory.h>
2499a2dd95SBruce Richardson #include <rte_eal.h>
2599a2dd95SBruce Richardson #include <rte_byteorder.h>
2699a2dd95SBruce Richardson #include <rte_errno.h>
2799a2dd95SBruce Richardson
2899a2dd95SBruce Richardson #include "bpf_impl.h"
2999a2dd95SBruce Richardson
3099a2dd95SBruce Richardson /* To overcome compatibility issue */
3199a2dd95SBruce Richardson #ifndef EM_BPF
3299a2dd95SBruce Richardson #define EM_BPF 247
3399a2dd95SBruce Richardson #endif
3499a2dd95SBruce Richardson
3599a2dd95SBruce Richardson static uint32_t
bpf_find_xsym(const char * sn,enum rte_bpf_xtype type,const struct rte_bpf_xsym fp[],uint32_t fn)3699a2dd95SBruce Richardson bpf_find_xsym(const char *sn, enum rte_bpf_xtype type,
3799a2dd95SBruce Richardson const struct rte_bpf_xsym fp[], uint32_t fn)
3899a2dd95SBruce Richardson {
3999a2dd95SBruce Richardson uint32_t i;
4099a2dd95SBruce Richardson
4199a2dd95SBruce Richardson if (sn == NULL || fp == NULL)
4299a2dd95SBruce Richardson return UINT32_MAX;
4399a2dd95SBruce Richardson
4499a2dd95SBruce Richardson for (i = 0; i != fn; i++) {
4599a2dd95SBruce Richardson if (fp[i].type == type && strcmp(sn, fp[i].name) == 0)
4699a2dd95SBruce Richardson break;
4799a2dd95SBruce Richardson }
4899a2dd95SBruce Richardson
4999a2dd95SBruce Richardson return (i != fn) ? i : UINT32_MAX;
5099a2dd95SBruce Richardson }
5199a2dd95SBruce Richardson
5299a2dd95SBruce Richardson /*
5399a2dd95SBruce Richardson * update BPF code at offset *ofs* with a proper address(index) for external
5499a2dd95SBruce Richardson * symbol *sn*
5599a2dd95SBruce Richardson */
5699a2dd95SBruce Richardson static int
resolve_xsym(const char * sn,size_t ofs,struct ebpf_insn * ins,size_t ins_sz,const struct rte_bpf_prm * prm)5799a2dd95SBruce Richardson resolve_xsym(const char *sn, size_t ofs, struct ebpf_insn *ins, size_t ins_sz,
5899a2dd95SBruce Richardson const struct rte_bpf_prm *prm)
5999a2dd95SBruce Richardson {
6099a2dd95SBruce Richardson uint32_t idx, fidx;
6199a2dd95SBruce Richardson enum rte_bpf_xtype type;
6299a2dd95SBruce Richardson
6399a2dd95SBruce Richardson if (ofs % sizeof(ins[0]) != 0 || ofs >= ins_sz)
6499a2dd95SBruce Richardson return -EINVAL;
6599a2dd95SBruce Richardson
6699a2dd95SBruce Richardson idx = ofs / sizeof(ins[0]);
6799a2dd95SBruce Richardson if (ins[idx].code == (BPF_JMP | EBPF_CALL))
6899a2dd95SBruce Richardson type = RTE_BPF_XTYPE_FUNC;
6999a2dd95SBruce Richardson else if (ins[idx].code == (BPF_LD | BPF_IMM | EBPF_DW) &&
7099a2dd95SBruce Richardson ofs < ins_sz - sizeof(ins[idx]))
7199a2dd95SBruce Richardson type = RTE_BPF_XTYPE_VAR;
7299a2dd95SBruce Richardson else
7399a2dd95SBruce Richardson return -EINVAL;
7499a2dd95SBruce Richardson
7599a2dd95SBruce Richardson fidx = bpf_find_xsym(sn, type, prm->xsym, prm->nb_xsym);
7699a2dd95SBruce Richardson if (fidx == UINT32_MAX)
7799a2dd95SBruce Richardson return -ENOENT;
7899a2dd95SBruce Richardson
7999a2dd95SBruce Richardson /* for function we just need an index in our xsym table */
8099a2dd95SBruce Richardson if (type == RTE_BPF_XTYPE_FUNC) {
8199a2dd95SBruce Richardson
8299a2dd95SBruce Richardson /* we don't support multiple functions per BPF module,
834a6672c2SStephen Hemminger * so treat EBPF_PSEUDO_CALL to external function
8499a2dd95SBruce Richardson * as an ordinary EBPF_CALL.
8599a2dd95SBruce Richardson */
8699a2dd95SBruce Richardson if (ins[idx].src_reg == EBPF_PSEUDO_CALL) {
87*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(INFO, "%s(%u): "
88*0e21c7c0SDavid Marchand "EBPF_PSEUDO_CALL to external function: %s",
8999a2dd95SBruce Richardson __func__, idx, sn);
9099a2dd95SBruce Richardson ins[idx].src_reg = EBPF_REG_0;
9199a2dd95SBruce Richardson }
9299a2dd95SBruce Richardson ins[idx].imm = fidx;
9399a2dd95SBruce Richardson /* for variable we need to store its absolute address */
9499a2dd95SBruce Richardson } else {
9599a2dd95SBruce Richardson ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val;
9699a2dd95SBruce Richardson ins[idx + 1].imm =
9799a2dd95SBruce Richardson (uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32;
9899a2dd95SBruce Richardson }
9999a2dd95SBruce Richardson
10099a2dd95SBruce Richardson return 0;
10199a2dd95SBruce Richardson }
10299a2dd95SBruce Richardson
10399a2dd95SBruce Richardson static int
check_elf_header(const Elf64_Ehdr * eh)10499a2dd95SBruce Richardson check_elf_header(const Elf64_Ehdr *eh)
10599a2dd95SBruce Richardson {
10699a2dd95SBruce Richardson const char *err;
10799a2dd95SBruce Richardson
10899a2dd95SBruce Richardson err = NULL;
10999a2dd95SBruce Richardson
11099a2dd95SBruce Richardson #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
11199a2dd95SBruce Richardson if (eh->e_ident[EI_DATA] != ELFDATA2LSB)
11299a2dd95SBruce Richardson #else
11399a2dd95SBruce Richardson if (eh->e_ident[EI_DATA] != ELFDATA2MSB)
11499a2dd95SBruce Richardson #endif
11599a2dd95SBruce Richardson err = "not native byte order";
11699a2dd95SBruce Richardson else if (eh->e_ident[EI_OSABI] != ELFOSABI_NONE)
11799a2dd95SBruce Richardson err = "unexpected OS ABI";
11899a2dd95SBruce Richardson else if (eh->e_type != ET_REL)
11999a2dd95SBruce Richardson err = "unexpected ELF type";
12099a2dd95SBruce Richardson else if (eh->e_machine != EM_NONE && eh->e_machine != EM_BPF)
12199a2dd95SBruce Richardson err = "unexpected machine type";
12299a2dd95SBruce Richardson
12399a2dd95SBruce Richardson if (err != NULL) {
124*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(): %s", __func__, err);
12599a2dd95SBruce Richardson return -EINVAL;
12699a2dd95SBruce Richardson }
12799a2dd95SBruce Richardson
12899a2dd95SBruce Richardson return 0;
12999a2dd95SBruce Richardson }
13099a2dd95SBruce Richardson
13199a2dd95SBruce Richardson /*
13299a2dd95SBruce Richardson * helper function, find executable section by name.
13399a2dd95SBruce Richardson */
13499a2dd95SBruce Richardson static int
find_elf_code(Elf * elf,const char * section,Elf_Data ** psd,size_t * pidx)13599a2dd95SBruce Richardson find_elf_code(Elf *elf, const char *section, Elf_Data **psd, size_t *pidx)
13699a2dd95SBruce Richardson {
13799a2dd95SBruce Richardson Elf_Scn *sc;
13899a2dd95SBruce Richardson const Elf64_Ehdr *eh;
13999a2dd95SBruce Richardson const Elf64_Shdr *sh;
14099a2dd95SBruce Richardson Elf_Data *sd;
14199a2dd95SBruce Richardson const char *sn;
14299a2dd95SBruce Richardson int32_t rc;
14399a2dd95SBruce Richardson
14499a2dd95SBruce Richardson eh = elf64_getehdr(elf);
14599a2dd95SBruce Richardson if (eh == NULL) {
14699a2dd95SBruce Richardson rc = elf_errno();
147*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(%p, %s) error code: %d(%s)",
14899a2dd95SBruce Richardson __func__, elf, section, rc, elf_errmsg(rc));
14999a2dd95SBruce Richardson return -EINVAL;
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson
15299a2dd95SBruce Richardson if (check_elf_header(eh) != 0)
15399a2dd95SBruce Richardson return -EINVAL;
15499a2dd95SBruce Richardson
15599a2dd95SBruce Richardson /* find given section by name */
15699a2dd95SBruce Richardson for (sc = elf_nextscn(elf, NULL); sc != NULL;
15799a2dd95SBruce Richardson sc = elf_nextscn(elf, sc)) {
15899a2dd95SBruce Richardson sh = elf64_getshdr(sc);
15999a2dd95SBruce Richardson sn = elf_strptr(elf, eh->e_shstrndx, sh->sh_name);
16099a2dd95SBruce Richardson if (sn != NULL && strcmp(section, sn) == 0 &&
16199a2dd95SBruce Richardson sh->sh_type == SHT_PROGBITS &&
16299a2dd95SBruce Richardson sh->sh_flags == (SHF_ALLOC | SHF_EXECINSTR))
16399a2dd95SBruce Richardson break;
16499a2dd95SBruce Richardson }
16599a2dd95SBruce Richardson
16699a2dd95SBruce Richardson sd = elf_getdata(sc, NULL);
16799a2dd95SBruce Richardson if (sd == NULL || sd->d_size == 0 ||
16899a2dd95SBruce Richardson sd->d_size % sizeof(struct ebpf_insn) != 0) {
16999a2dd95SBruce Richardson rc = elf_errno();
170*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(%p, %s) error code: %d(%s)",
17199a2dd95SBruce Richardson __func__, elf, section, rc, elf_errmsg(rc));
17299a2dd95SBruce Richardson return -EINVAL;
17399a2dd95SBruce Richardson }
17499a2dd95SBruce Richardson
17599a2dd95SBruce Richardson *psd = sd;
17699a2dd95SBruce Richardson *pidx = elf_ndxscn(sc);
17799a2dd95SBruce Richardson return 0;
17899a2dd95SBruce Richardson }
17999a2dd95SBruce Richardson
18099a2dd95SBruce Richardson /*
18199a2dd95SBruce Richardson * helper function to process data from relocation table.
18299a2dd95SBruce Richardson */
18399a2dd95SBruce Richardson static int
process_reloc(Elf * elf,size_t sym_idx,Elf64_Rel * re,size_t re_sz,struct ebpf_insn * ins,size_t ins_sz,const struct rte_bpf_prm * prm)18499a2dd95SBruce Richardson process_reloc(Elf *elf, size_t sym_idx, Elf64_Rel *re, size_t re_sz,
18599a2dd95SBruce Richardson struct ebpf_insn *ins, size_t ins_sz, const struct rte_bpf_prm *prm)
18699a2dd95SBruce Richardson {
18799a2dd95SBruce Richardson int32_t rc;
18899a2dd95SBruce Richardson uint32_t i, n;
18999a2dd95SBruce Richardson size_t ofs, sym;
19099a2dd95SBruce Richardson const char *sn;
19199a2dd95SBruce Richardson const Elf64_Ehdr *eh;
19299a2dd95SBruce Richardson Elf_Scn *sc;
19399a2dd95SBruce Richardson const Elf_Data *sd;
19499a2dd95SBruce Richardson Elf64_Sym *sm;
19599a2dd95SBruce Richardson
19699a2dd95SBruce Richardson eh = elf64_getehdr(elf);
19799a2dd95SBruce Richardson
19899a2dd95SBruce Richardson /* get symtable by section index */
19999a2dd95SBruce Richardson sc = elf_getscn(elf, sym_idx);
20099a2dd95SBruce Richardson sd = elf_getdata(sc, NULL);
20199a2dd95SBruce Richardson if (sd == NULL)
20299a2dd95SBruce Richardson return -EINVAL;
20399a2dd95SBruce Richardson sm = sd->d_buf;
20499a2dd95SBruce Richardson
20599a2dd95SBruce Richardson n = re_sz / sizeof(re[0]);
20699a2dd95SBruce Richardson for (i = 0; i != n; i++) {
20799a2dd95SBruce Richardson
20899a2dd95SBruce Richardson ofs = re[i].r_offset;
20999a2dd95SBruce Richardson
21099a2dd95SBruce Richardson /* retrieve index in the symtable */
21199a2dd95SBruce Richardson sym = ELF64_R_SYM(re[i].r_info);
21299a2dd95SBruce Richardson if (sym * sizeof(sm[0]) >= sd->d_size)
21399a2dd95SBruce Richardson return -EINVAL;
21499a2dd95SBruce Richardson
21599a2dd95SBruce Richardson sn = elf_strptr(elf, eh->e_shstrndx, sm[sym].st_name);
21699a2dd95SBruce Richardson
21799a2dd95SBruce Richardson rc = resolve_xsym(sn, ofs, ins, ins_sz, prm);
21899a2dd95SBruce Richardson if (rc != 0) {
219*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR,
220*0e21c7c0SDavid Marchand "resolve_xsym(%s, %zu) error code: %d",
22199a2dd95SBruce Richardson sn, ofs, rc);
22299a2dd95SBruce Richardson return rc;
22399a2dd95SBruce Richardson }
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson
22699a2dd95SBruce Richardson return 0;
22799a2dd95SBruce Richardson }
22899a2dd95SBruce Richardson
22999a2dd95SBruce Richardson /*
23099a2dd95SBruce Richardson * helper function, find relocation information (if any)
23199a2dd95SBruce Richardson * and update bpf code.
23299a2dd95SBruce Richardson */
23399a2dd95SBruce Richardson static int
elf_reloc_code(Elf * elf,Elf_Data * ed,size_t sidx,const struct rte_bpf_prm * prm)23499a2dd95SBruce Richardson elf_reloc_code(Elf *elf, Elf_Data *ed, size_t sidx,
23599a2dd95SBruce Richardson const struct rte_bpf_prm *prm)
23699a2dd95SBruce Richardson {
23799a2dd95SBruce Richardson Elf64_Rel *re;
23899a2dd95SBruce Richardson Elf_Scn *sc;
23999a2dd95SBruce Richardson const Elf64_Shdr *sh;
24099a2dd95SBruce Richardson const Elf_Data *sd;
24199a2dd95SBruce Richardson int32_t rc;
24299a2dd95SBruce Richardson
24399a2dd95SBruce Richardson rc = 0;
24499a2dd95SBruce Richardson
24599a2dd95SBruce Richardson /* walk through all sections */
24699a2dd95SBruce Richardson for (sc = elf_nextscn(elf, NULL); sc != NULL && rc == 0;
24799a2dd95SBruce Richardson sc = elf_nextscn(elf, sc)) {
24899a2dd95SBruce Richardson
24999a2dd95SBruce Richardson sh = elf64_getshdr(sc);
25099a2dd95SBruce Richardson
25199a2dd95SBruce Richardson /* relocation data for our code section */
25299a2dd95SBruce Richardson if (sh->sh_type == SHT_REL && sh->sh_info == sidx) {
25399a2dd95SBruce Richardson sd = elf_getdata(sc, NULL);
25499a2dd95SBruce Richardson if (sd == NULL || sd->d_size == 0 ||
25599a2dd95SBruce Richardson sd->d_size % sizeof(re[0]) != 0)
25699a2dd95SBruce Richardson return -EINVAL;
25799a2dd95SBruce Richardson rc = process_reloc(elf, sh->sh_link,
25899a2dd95SBruce Richardson sd->d_buf, sd->d_size, ed->d_buf, ed->d_size,
25999a2dd95SBruce Richardson prm);
26099a2dd95SBruce Richardson }
26199a2dd95SBruce Richardson }
26299a2dd95SBruce Richardson
26399a2dd95SBruce Richardson return rc;
26499a2dd95SBruce Richardson }
26599a2dd95SBruce Richardson
26699a2dd95SBruce Richardson static struct rte_bpf *
bpf_load_elf(const struct rte_bpf_prm * prm,int32_t fd,const char * section)26799a2dd95SBruce Richardson bpf_load_elf(const struct rte_bpf_prm *prm, int32_t fd, const char *section)
26899a2dd95SBruce Richardson {
26999a2dd95SBruce Richardson Elf *elf;
27099a2dd95SBruce Richardson Elf_Data *sd;
27199a2dd95SBruce Richardson size_t sidx;
27299a2dd95SBruce Richardson int32_t rc;
27399a2dd95SBruce Richardson struct rte_bpf *bpf;
27499a2dd95SBruce Richardson struct rte_bpf_prm np;
27599a2dd95SBruce Richardson
27699a2dd95SBruce Richardson elf_version(EV_CURRENT);
27799a2dd95SBruce Richardson elf = elf_begin(fd, ELF_C_READ, NULL);
27899a2dd95SBruce Richardson
27999a2dd95SBruce Richardson rc = find_elf_code(elf, section, &sd, &sidx);
28099a2dd95SBruce Richardson if (rc == 0)
28199a2dd95SBruce Richardson rc = elf_reloc_code(elf, sd, sidx, prm);
28299a2dd95SBruce Richardson
28399a2dd95SBruce Richardson if (rc == 0) {
28499a2dd95SBruce Richardson np = prm[0];
28599a2dd95SBruce Richardson np.ins = sd->d_buf;
28699a2dd95SBruce Richardson np.nb_ins = sd->d_size / sizeof(struct ebpf_insn);
28799a2dd95SBruce Richardson bpf = rte_bpf_load(&np);
28899a2dd95SBruce Richardson } else {
28999a2dd95SBruce Richardson bpf = NULL;
29099a2dd95SBruce Richardson rte_errno = -rc;
29199a2dd95SBruce Richardson }
29299a2dd95SBruce Richardson
29399a2dd95SBruce Richardson elf_end(elf);
29499a2dd95SBruce Richardson return bpf;
29599a2dd95SBruce Richardson }
29699a2dd95SBruce Richardson
29799a2dd95SBruce Richardson struct rte_bpf *
rte_bpf_elf_load(const struct rte_bpf_prm * prm,const char * fname,const char * sname)29899a2dd95SBruce Richardson rte_bpf_elf_load(const struct rte_bpf_prm *prm, const char *fname,
29999a2dd95SBruce Richardson const char *sname)
30099a2dd95SBruce Richardson {
30199a2dd95SBruce Richardson int32_t fd, rc;
30299a2dd95SBruce Richardson struct rte_bpf *bpf;
30399a2dd95SBruce Richardson
30499a2dd95SBruce Richardson if (prm == NULL || fname == NULL || sname == NULL) {
30599a2dd95SBruce Richardson rte_errno = EINVAL;
30699a2dd95SBruce Richardson return NULL;
30799a2dd95SBruce Richardson }
30899a2dd95SBruce Richardson
30999a2dd95SBruce Richardson fd = open(fname, O_RDONLY);
31099a2dd95SBruce Richardson if (fd < 0) {
31199a2dd95SBruce Richardson rc = errno;
312*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(%s) error code: %d(%s)",
31399a2dd95SBruce Richardson __func__, fname, rc, strerror(rc));
31499a2dd95SBruce Richardson rte_errno = EINVAL;
31599a2dd95SBruce Richardson return NULL;
31699a2dd95SBruce Richardson }
31799a2dd95SBruce Richardson
31899a2dd95SBruce Richardson bpf = bpf_load_elf(prm, fd, sname);
31999a2dd95SBruce Richardson close(fd);
32099a2dd95SBruce Richardson
32199a2dd95SBruce Richardson if (bpf == NULL) {
322*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR,
32399a2dd95SBruce Richardson "%s(fname=\"%s\", sname=\"%s\") failed, "
324*0e21c7c0SDavid Marchand "error code: %d",
32599a2dd95SBruce Richardson __func__, fname, sname, rte_errno);
32699a2dd95SBruce Richardson return NULL;
32799a2dd95SBruce Richardson }
32899a2dd95SBruce Richardson
329*0e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(INFO, "%s(fname=\"%s\", sname=\"%s\") "
330*0e21c7c0SDavid Marchand "successfully creates %p(jit={.func=%p,.sz=%zu});",
33199a2dd95SBruce Richardson __func__, fname, sname, bpf, bpf->jit.func, bpf->jit.sz);
33299a2dd95SBruce Richardson return bpf;
33399a2dd95SBruce Richardson }
334