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