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 : : }
|