New upstream version 18.08
[deb_dpdk.git] / lib / librte_bpf / bpf_load_elf.c
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 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         if (sn == NULL || fp == NULL)
42                 return UINT32_MAX;
43
44         for (i = 0; i != fn; i++) {
45                 if (fp[i].type == type && strcmp(sn, fp[i].name) == 0)
46                         break;
47         }
48
49         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 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         if (ofs % sizeof(ins[0]) != 0 || ofs >= ins_sz)
64                 return -EINVAL;
65
66         idx = ofs / sizeof(ins[0]);
67         if (ins[idx].code == (BPF_JMP | EBPF_CALL))
68                 type = RTE_BPF_XTYPE_FUNC;
69         else if (ins[idx].code == (BPF_LD | BPF_IMM | EBPF_DW) &&
70                         ofs < ins_sz - sizeof(ins[idx]))
71                 type = RTE_BPF_XTYPE_VAR;
72         else
73                 return -EINVAL;
74
75         fidx = bpf_find_xsym(sn, type, prm->xsym, prm->nb_xsym);
76         if (fidx == UINT32_MAX)
77                 return -ENOENT;
78
79         /* for function we just need an index in our xsym table */
80         if (type == RTE_BPF_XTYPE_FUNC)
81                 ins[idx].imm = fidx;
82         /* for variable we need to store its absolute address */
83         else {
84                 ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val;
85                 ins[idx + 1].imm =
86                         (uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32;
87         }
88
89         return 0;
90 }
91
92 static int
93 check_elf_header(const Elf64_Ehdr *eh)
94 {
95         const char *err;
96
97         err = NULL;
98
99 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
100         if (eh->e_ident[EI_DATA] != ELFDATA2LSB)
101 #else
102         if (eh->e_ident[EI_DATA] != ELFDATA2MSB)
103 #endif
104                 err = "not native byte order";
105         else if (eh->e_ident[EI_OSABI] != ELFOSABI_NONE)
106                 err = "unexpected OS ABI";
107         else if (eh->e_type != ET_REL)
108                 err = "unexpected ELF type";
109         else if (eh->e_machine != EM_NONE && eh->e_machine != EM_BPF)
110                 err = "unexpected machine type";
111
112         if (err != NULL) {
113                 RTE_BPF_LOG(ERR, "%s(): %s\n", __func__, err);
114                 return -EINVAL;
115         }
116
117         return 0;
118 }
119
120 /*
121  * helper function, find executable section by name.
122  */
123 static int
124 find_elf_code(Elf *elf, const char *section, Elf_Data **psd, size_t *pidx)
125 {
126         Elf_Scn *sc;
127         const Elf64_Ehdr *eh;
128         const Elf64_Shdr *sh;
129         Elf_Data *sd;
130         const char *sn;
131         int32_t rc;
132
133         eh = elf64_getehdr(elf);
134         if (eh == NULL) {
135                 rc = elf_errno();
136                 RTE_BPF_LOG(ERR, "%s(%p, %s) error code: %d(%s)\n",
137                         __func__, elf, section, rc, elf_errmsg(rc));
138                 return -EINVAL;
139         }
140
141         if (check_elf_header(eh) != 0)
142                 return -EINVAL;
143
144         /* find given section by name */
145         for (sc = elf_nextscn(elf, NULL); sc != NULL;
146                         sc = elf_nextscn(elf, sc)) {
147                 sh = elf64_getshdr(sc);
148                 sn = elf_strptr(elf, eh->e_shstrndx, sh->sh_name);
149                 if (sn != NULL && strcmp(section, sn) == 0 &&
150                                 sh->sh_type == SHT_PROGBITS &&
151                                 sh->sh_flags == (SHF_ALLOC | SHF_EXECINSTR))
152                         break;
153         }
154
155         sd = elf_getdata(sc, NULL);
156         if (sd == NULL || sd->d_size == 0 ||
157                         sd->d_size % sizeof(struct ebpf_insn) != 0) {
158                 rc = elf_errno();
159                 RTE_BPF_LOG(ERR, "%s(%p, %s) error code: %d(%s)\n",
160                         __func__, elf, section, rc, elf_errmsg(rc));
161                 return -EINVAL;
162         }
163
164         *psd = sd;
165         *pidx = elf_ndxscn(sc);
166         return 0;
167 }
168
169 /*
170  * helper function to process data from relocation table.
171  */
172 static int
173 process_reloc(Elf *elf, size_t sym_idx, Elf64_Rel *re, size_t re_sz,
174         struct ebpf_insn *ins, size_t ins_sz, const struct rte_bpf_prm *prm)
175 {
176         int32_t rc;
177         uint32_t i, n;
178         size_t ofs, sym;
179         const char *sn;
180         const Elf64_Ehdr *eh;
181         Elf_Scn *sc;
182         const Elf_Data *sd;
183         Elf64_Sym *sm;
184
185         eh = elf64_getehdr(elf);
186
187         /* get symtable by section index */
188         sc = elf_getscn(elf, sym_idx);
189         sd = elf_getdata(sc, NULL);
190         if (sd == NULL)
191                 return -EINVAL;
192         sm = sd->d_buf;
193
194         n = re_sz / sizeof(re[0]);
195         for (i = 0; i != n; i++) {
196
197                 ofs = re[i].r_offset;
198
199                 /* retrieve index in the symtable */
200                 sym = ELF64_R_SYM(re[i].r_info);
201                 if (sym * sizeof(sm[0]) >= sd->d_size)
202                         return -EINVAL;
203
204                 sn = elf_strptr(elf, eh->e_shstrndx, sm[sym].st_name);
205
206                 rc = resolve_xsym(sn, ofs, ins, ins_sz, prm);
207                 if (rc != 0) {
208                         RTE_BPF_LOG(ERR,
209                                 "resolve_xsym(%s, %zu) error code: %d\n",
210                                 sn, ofs, rc);
211                         return rc;
212                 }
213         }
214
215         return 0;
216 }
217
218 /*
219  * helper function, find relocation information (if any)
220  * and update bpf code.
221  */
222 static int
223 elf_reloc_code(Elf *elf, Elf_Data *ed, size_t sidx,
224         const struct rte_bpf_prm *prm)
225 {
226         Elf64_Rel *re;
227         Elf_Scn *sc;
228         const Elf64_Shdr *sh;
229         const Elf_Data *sd;
230         int32_t rc;
231
232         rc = 0;
233
234         /* walk through all sections */
235         for (sc = elf_nextscn(elf, NULL); sc != NULL && rc == 0;
236                         sc = elf_nextscn(elf, sc)) {
237
238                 sh = elf64_getshdr(sc);
239
240                 /* relocation data for our code section */
241                 if (sh->sh_type == SHT_REL && sh->sh_info == sidx) {
242                         sd = elf_getdata(sc, NULL);
243                         if (sd == NULL || sd->d_size == 0 ||
244                                         sd->d_size % sizeof(re[0]) != 0)
245                                 return -EINVAL;
246                         rc = process_reloc(elf, sh->sh_link,
247                                 sd->d_buf, sd->d_size, ed->d_buf, ed->d_size,
248                                 prm);
249                 }
250         }
251
252         return rc;
253 }
254
255 static struct rte_bpf *
256 bpf_load_elf(const struct rte_bpf_prm *prm, int32_t fd, const char *section)
257 {
258         Elf *elf;
259         Elf_Data *sd;
260         size_t sidx;
261         int32_t rc;
262         struct rte_bpf *bpf;
263         struct rte_bpf_prm np;
264
265         elf_version(EV_CURRENT);
266         elf = elf_begin(fd, ELF_C_READ, NULL);
267
268         rc = find_elf_code(elf, section, &sd, &sidx);
269         if (rc == 0)
270                 rc = elf_reloc_code(elf, sd, sidx, prm);
271
272         if (rc == 0) {
273                 np = prm[0];
274                 np.ins = sd->d_buf;
275                 np.nb_ins = sd->d_size / sizeof(struct ebpf_insn);
276                 bpf = rte_bpf_load(&np);
277         } else {
278                 bpf = NULL;
279                 rte_errno = -rc;
280         }
281
282         elf_end(elf);
283         return bpf;
284 }
285
286 __rte_experimental struct rte_bpf *
287 rte_bpf_elf_load(const struct rte_bpf_prm *prm, const char *fname,
288         const char *sname)
289 {
290         int32_t fd, rc;
291         struct rte_bpf *bpf;
292
293         if (prm == NULL || fname == NULL || sname == NULL) {
294                 rte_errno = EINVAL;
295                 return NULL;
296         }
297
298         fd = open(fname, O_RDONLY);
299         if (fd < 0) {
300                 rc = errno;
301                 RTE_BPF_LOG(ERR, "%s(%s) error code: %d(%s)\n",
302                         __func__, fname, rc, strerror(rc));
303                 rte_errno = EINVAL;
304                 return NULL;
305         }
306
307         bpf = bpf_load_elf(prm, fd, sname);
308         close(fd);
309
310         if (bpf == NULL) {
311                 RTE_BPF_LOG(ERR,
312                         "%s(fname=\"%s\", sname=\"%s\") failed, "
313                         "error code: %d\n",
314                         __func__, fname, sname, rte_errno);
315                 return NULL;
316         }
317
318         RTE_BPF_LOG(INFO, "%s(fname=\"%s\", sname=\"%s\") "
319                 "successfully creates %p(jit={.func=%p,.sz=%zu});\n",
320                 __func__, fname, sname, bpf, bpf->jit.func, bpf->jit.sz);
321         return bpf;
322 }