Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : : #include <errno.h>
8 : : #include <stdint.h>
9 : :
10 : : #include <eal_export.h>
11 : : #include <rte_log.h>
12 : : #include <rte_errno.h>
13 : :
14 : : #include "bpf_impl.h"
15 : :
16 : : static struct rte_bpf *
17 : 423 : bpf_load(const struct rte_bpf_prm_ex *prm)
18 : : {
19 : : uint8_t *buf;
20 : : struct rte_bpf *bpf;
21 : : size_t sz, bsz, insz, xsz;
22 : :
23 : 423 : xsz = prm->nb_xsym * sizeof(prm->xsym[0]);
24 : 423 : insz = prm->raw.nb_ins * sizeof(prm->raw.ins[0]);
25 : : bsz = sizeof(bpf[0]);
26 : 423 : sz = insz + xsz + bsz;
27 : :
28 : 423 : buf = mmap(NULL, sz, PROT_READ | PROT_WRITE,
29 : : MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
30 [ + - ]: 423 : if (buf == MAP_FAILED)
31 : : return NULL;
32 : :
33 : : bpf = (void *)buf;
34 : 423 : bpf->sz = sz;
35 : :
36 [ + + ]: 423 : memcpy(&bpf->prm, prm, sizeof(bpf->prm));
37 : :
38 [ + + ]: 423 : if (xsz > 0)
39 : 105 : memcpy(buf + bsz, prm->xsym, xsz);
40 : 423 : memcpy(buf + bsz + xsz, prm->raw.ins, insz);
41 : :
42 : 423 : bpf->prm.xsym = (void *)(buf + bsz);
43 : 423 : bpf->prm.raw.ins = (void *)(buf + bsz + xsz);
44 : :
45 : 423 : return bpf;
46 : : }
47 : :
48 : : /*
49 : : * Check that user provided external symbol.
50 : : */
51 : : static int
52 : 106 : bpf_check_xsym(const struct rte_bpf_xsym *xsym)
53 : : {
54 : : uint32_t i;
55 : :
56 [ + - ]: 106 : if (xsym->name == NULL)
57 : : return -EINVAL;
58 : :
59 [ - + ]: 106 : if (xsym->type == RTE_BPF_XTYPE_VAR) {
60 [ # # ]: 0 : if (xsym->var.desc.type == RTE_BPF_ARG_UNDEF)
61 : 0 : return -EINVAL;
62 [ + - ]: 106 : } else if (xsym->type == RTE_BPF_XTYPE_FUNC) {
63 : :
64 [ + - ]: 106 : if (xsym->func.nb_args > EBPF_FUNC_MAX_ARGS)
65 : : return -EINVAL;
66 : :
67 : : /* check function arguments */
68 [ + + ]: 220 : for (i = 0; i != xsym->func.nb_args; i++) {
69 [ + - ]: 114 : if (xsym->func.args[i].type == RTE_BPF_ARG_UNDEF)
70 : : return -EINVAL;
71 : : }
72 : :
73 : : /* check return value info */
74 [ + + ]: 106 : if (xsym->func.ret.type != RTE_BPF_ARG_UNDEF &&
75 [ - + ]: 104 : xsym->func.ret.size == 0)
76 : 0 : return -EINVAL;
77 : : } else
78 : : return -EINVAL;
79 : :
80 : : return 0;
81 : : }
82 : :
83 : : static int
84 : 424 : bpf_check_xsyms(const struct rte_bpf_xsym *xsym, uint32_t nb_xsym)
85 : : {
86 : : int32_t rc;
87 : : uint32_t i;
88 : :
89 [ + - ]: 424 : if (nb_xsym != 0 && xsym == NULL)
90 : : return -EINVAL;
91 : :
92 : : rc = 0;
93 [ + + ]: 530 : for (i = 0; i != nb_xsym && rc == 0; i++)
94 : 106 : rc = bpf_check_xsym(xsym + i);
95 : :
96 [ - + ]: 424 : if (rc != 0) {
97 : 0 : RTE_BPF_LOG_FUNC_LINE(ERR, "%d-th xsym is invalid", i);
98 : 0 : return rc;
99 : : }
100 : :
101 : : return 0;
102 : : }
103 : :
104 : : static int
105 : 424 : bpf_load_raw(struct __rte_bpf_load *load)
106 : : {
107 : 424 : const struct rte_bpf_prm_ex *const prm = &load->prm;
108 : : struct rte_bpf *bpf;
109 : : int32_t rc;
110 : :
111 : : RTE_ASSERT(prm->origin == RTE_BPF_ORIGIN_RAW);
112 : :
113 [ + - + + ]: 424 : if (prm->raw.ins == NULL || prm->raw.nb_ins == 0)
114 : : return -EINVAL;
115 : :
116 : 423 : bpf = bpf_load(prm);
117 [ + - ]: 423 : if (bpf == NULL)
118 : : return -ENOMEM;
119 : :
120 : 423 : rc = __rte_bpf_validate(&load->prm, &bpf->stack_sz);
121 [ + + ]: 423 : if (rc == 0) {
122 : 191 : __rte_bpf_jit(bpf);
123 [ + - ]: 191 : if (mprotect(bpf, bpf->sz, PROT_READ) != 0)
124 : : rc = -ENOMEM;
125 : : }
126 : :
127 [ + + ]: 423 : if (rc != 0) {
128 : 232 : rte_bpf_destroy(bpf);
129 : 232 : return rc;
130 : : }
131 : :
132 : 191 : load->bpf = bpf;
133 : 191 : return 0;
134 : : }
135 : :
136 : : RTE_EXPORT_SYMBOL(rte_bpf_load)
137 : : struct rte_bpf *
138 : 395 : rte_bpf_load(const struct rte_bpf_prm *prm)
139 : : {
140 [ + + ]: 395 : if (prm == NULL) {
141 : 1 : rte_errno = EINVAL;
142 : 1 : return NULL;
143 : : }
144 : :
145 : 394 : return rte_bpf_load_ex(&(struct rte_bpf_prm_ex){
146 : : .sz = sizeof(struct rte_bpf_prm_ex),
147 : : .origin = RTE_BPF_ORIGIN_RAW,
148 : 394 : .raw.ins = prm->ins,
149 : 394 : .raw.nb_ins = prm->nb_ins,
150 : 394 : .xsym = prm->xsym,
151 : 394 : .nb_xsym = prm->nb_xsym,
152 : : .prog_arg[0] = prm->prog_arg,
153 : : .nb_prog_arg = 1,
154 : : });
155 : : }
156 : :
157 : : RTE_EXPORT_SYMBOL(rte_bpf_elf_load)
158 : : struct rte_bpf *
159 : 1 : rte_bpf_elf_load(const struct rte_bpf_prm *prm, const char *fname,
160 : : const char *sname)
161 : : {
162 [ + - ]: 1 : if (prm == NULL) {
163 : 1 : rte_errno = EINVAL;
164 : 1 : return NULL;
165 : : }
166 : :
167 : 0 : return rte_bpf_load_ex(&(struct rte_bpf_prm_ex){
168 : : .sz = sizeof(struct rte_bpf_prm_ex),
169 : : .origin = RTE_BPF_ORIGIN_ELF_FILE,
170 : : .elf_file.path = fname,
171 : : .elf_file.section = sname,
172 : 0 : .xsym = prm->xsym,
173 : 0 : .nb_xsym = prm->nb_xsym,
174 : : .prog_arg[0] = prm->prog_arg,
175 : : .nb_prog_arg = 1,
176 : : });
177 : : }
178 : :
179 : : /*
180 : : * Check extensible opts for invalid size or non-zero unsupported members.
181 : : *
182 : : * This code provides forward compatibility with applications compiled against
183 : : * newer version of this library. `opts_sz` is the size of struct `opts` in the
184 : : * version used for compiling the application, read from the member `sz`;
185 : : * `type_sz` is the size of the same struct in the version used for compiling
186 : : * the library.
187 : : *
188 : : * If new fields were added to the struct in the application version, `opts_sz`
189 : : * will be greater than `type_sz`. In this case we are making sure all bytes we
190 : : * don't know how to interpret are zeroes, that is any new features that are
191 : : * there are not being used.
192 : : *
193 : : * This function can be used to check any struct following this convention.
194 : : */
195 : : static bool
196 : : opts_valid(const void *opts, size_t opts_sz, size_t type_sz)
197 : : {
198 : : if (opts == NULL)
199 : : return true;
200 : :
201 : 424 : if (opts_sz < sizeof(opts_sz))
202 : : /* Size of the struct is too small even for sz member. */
203 : : return false;
204 : :
205 : : /* Verify that all extra bytes are zeroed. */
206 [ - + ]: 424 : for (size_t offset = type_sz; offset < opts_sz; ++offset)
207 [ # # ]: 0 : if (((const char *)opts)[offset] != 0)
208 : : return false;
209 : :
210 : : return true;
211 : : }
212 : :
213 : : static int
214 : 425 : load_try(struct __rte_bpf_load *load, const struct rte_bpf_prm_ex *app_prm)
215 : : {
216 : : int rc;
217 : :
218 [ + + + - : 849 : if (app_prm == NULL || !opts_valid(app_prm, app_prm->sz, sizeof(load->prm)))
+ - ]
219 : : return -EINVAL;
220 : :
221 : : /*
222 : : * Convert extensible prm of application size to the size known to us.
223 : : *
224 : : * This code provides compatibility with applications compiled against
225 : : * different version of this library. `app_prm->sz` is the size of
226 : : * struct `rte_bpf_prm_ex` in the version used for compiling the
227 : : * application; `sizeof(load->prm)` is the size of the same struct in
228 : : * the version used for compiling the library.
229 : : *
230 : : * We are copying only the fields known to the application and leave
231 : : * the rest filled with zeroes. Any features not known to the
232 : : * application will have backward-compatible default behaviour.
233 : : */
234 : 424 : memcpy(&load->prm, app_prm, RTE_MIN(app_prm->sz, sizeof(load->prm)));
235 : 424 : load->prm.sz = sizeof(load->prm);
236 : :
237 : 424 : rc = bpf_check_xsyms(load->prm.xsym, load->prm.nb_xsym);
238 : :
239 : : /* Convert prm origin to raw unless it already is. */
240 [ + - - - : 424 : switch (load->prm.origin) {
+ ]
241 : : case RTE_BPF_ORIGIN_RAW:
242 : : break;
243 : 28 : case RTE_BPF_ORIGIN_CBPF:
244 [ + - ]: 28 : rc = rc < 0 ? rc : __rte_bpf_convert(load);
245 : : break;
246 : 0 : case RTE_BPF_ORIGIN_ELF_FILE:
247 [ # # ]: 0 : rc = rc < 0 ? rc : __rte_bpf_load_elf_file(load);
248 [ # # ]: 0 : rc = rc < 0 ? rc : __rte_bpf_load_elf_code(load);
249 : : break;
250 : 0 : case RTE_BPF_ORIGIN_ELF_MEMORY:
251 [ # # ]: 0 : rc = rc < 0 ? rc : __rte_bpf_load_elf_memory(load);
252 [ # # ]: 0 : rc = rc < 0 ? rc : __rte_bpf_load_elf_code(load);
253 : : break;
254 : 0 : default:
255 [ # # ]: 0 : rc = rc < 0 ? rc : -EINVAL;
256 : : }
257 : :
258 : : /* Now that it is raw load it as such. */
259 [ + - ]: 424 : rc = rc < 0 ? rc : bpf_load_raw(load);
260 : :
261 : : return rc;
262 : : }
263 : :
264 : : static void
265 : : load_cleanup(struct __rte_bpf_load *load)
266 : : {
267 : 425 : __rte_bpf_convert_cleanup(load);
268 : 425 : __rte_bpf_load_elf_cleanup(load);
269 : : }
270 : :
271 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_load_ex, 26.07)
272 : : struct rte_bpf *
273 : 425 : rte_bpf_load_ex(const struct rte_bpf_prm_ex *prm)
274 : : {
275 : 425 : struct __rte_bpf_load load = { .elf_fd = -1 };
276 : :
277 : 425 : const int rc = load_try(&load, prm);
278 : :
279 : : load_cleanup(&load);
280 : :
281 : : RTE_ASSERT((rc < 0) == (load.bpf == NULL));
282 : :
283 [ + + ]: 425 : if (rc < 0) {
284 : 234 : RTE_BPF_LOG_FUNC_LINE(ERR, "failed, error code: %d", -rc);
285 : 234 : rte_errno = -rc;
286 : 234 : return NULL;
287 : : }
288 : :
289 : 191 : RTE_BPF_LOG_FUNC_LINE(INFO, "successfully creates %p(jit={.func=%p,.sz=%zu});",
290 : : load.bpf, load.bpf->jit.raw, load.bpf->jit.sz);
291 : 191 : return load.bpf;
292 : : }
|