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 */
|