blob: 05a5067774198561d789a1ea6eae436c351674ff [file] [log] [blame]
Joel Fernandesd76a2002018-10-16 13:19:58 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "LibBpfLoader"
18
19#include <errno.h>
20#include <linux/bpf.h>
21#include <linux/elf.h>
22#include <log/log.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
Maciej Żenczykowski83f29772020-01-27 03:11:51 -080027#include <sys/stat.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070028#include <sys/utsname.h>
29#include <unistd.h>
30
Maciej Żenczykowski730a3862020-01-27 01:10:48 -080031#include "../progs/include/bpf_map_def.h"
Joel Fernandesd76a2002018-10-16 13:19:58 -070032#include "LoaderUtils.h"
Maciej Żenczykowski07375e22020-02-19 14:23:59 -080033#include "bpf/BpfUtils.h"
Joel Fernandesd76a2002018-10-16 13:19:58 -070034#include "include/libbpf_android.h"
35
36#include <cstdlib>
37#include <fstream>
38#include <iostream>
Connor O'Brien3278a162020-02-13 21:45:22 -080039#include <optional>
Joel Fernandesd76a2002018-10-16 13:19:58 -070040#include <string>
Christopher Ferrisc151c672019-02-01 15:31:26 -080041#include <vector>
Joel Fernandesd76a2002018-10-16 13:19:58 -070042
Steven Moreland4891e612020-01-10 15:35:52 -080043#include <android-base/properties.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070044#include <android-base/strings.h>
Connor O'Brien8d49fc72019-10-24 18:23:49 -070045#include <android-base/unique_fd.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070046
47#define BPF_FS_PATH "/sys/fs/bpf/"
48
49// Size of the BPF log buffer for verifier logging
50#define BPF_LOAD_LOG_SZ 0x1ffff
51
52using android::base::StartsWith;
Connor O'Brien8d49fc72019-10-24 18:23:49 -070053using android::base::unique_fd;
Joel Fernandesd76a2002018-10-16 13:19:58 -070054using std::ifstream;
55using std::ios;
Connor O'Brien3278a162020-02-13 21:45:22 -080056using std::optional;
Christopher Ferrisc151c672019-02-01 15:31:26 -080057using std::string;
Joel Fernandesd76a2002018-10-16 13:19:58 -070058using std::vector;
59
60namespace android {
61namespace bpf {
62
63typedef struct {
64 const char* name;
65 enum bpf_prog_type type;
66} sectionType;
67
68/*
69 * Map section name prefixes to program types, the section name will be:
70 * SEC(<prefix>/<name-of-program>)
71 * For example:
72 * SEC("tracepoint/sched_switch_func") where sched_switch_funcs
73 * is the name of the program, and tracepoint is the type.
74 */
75sectionType sectionNameTypes[] = {
Maciej Żenczykowskiaa462222021-01-07 14:24:45 -080076 {"kprobe", BPF_PROG_TYPE_KPROBE},
77 {"tracepoint", BPF_PROG_TYPE_TRACEPOINT},
78 {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER},
79 {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB},
80 {"schedcls", BPF_PROG_TYPE_SCHED_CLS},
81 {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK},
82 {"xdp", BPF_PROG_TYPE_XDP},
Joel Fernandesd76a2002018-10-16 13:19:58 -070083
Maciej Żenczykowskiaa462222021-01-07 14:24:45 -080084 /* End of table */
85 {"END", BPF_PROG_TYPE_UNSPEC},
Joel Fernandesd76a2002018-10-16 13:19:58 -070086};
87
88typedef struct {
89 enum bpf_prog_type type;
90 string name;
91 vector<char> data;
92 vector<char> rel_data;
Connor O'Brien3278a162020-02-13 21:45:22 -080093 optional<struct bpf_prog_def> prog_def;
Joel Fernandesd76a2002018-10-16 13:19:58 -070094
Connor O'Brien8d49fc72019-10-24 18:23:49 -070095 unique_fd prog_fd; /* fd after loading */
Joel Fernandesd76a2002018-10-16 13:19:58 -070096} codeSection;
97
Joel Fernandesd76a2002018-10-16 13:19:58 -070098static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) {
99 elfFile.seekg(0);
100 if (elfFile.fail()) return -1;
101
102 if (!elfFile.read((char*)eh, sizeof(*eh))) return -1;
103
104 return 0;
105}
106
107/* Reads all section header tables into an Shdr array */
108static int readSectionHeadersAll(ifstream& elfFile, vector<Elf64_Shdr>& shTable) {
109 Elf64_Ehdr eh;
110 int ret = 0;
111
112 ret = readElfHeader(elfFile, &eh);
113 if (ret) return ret;
114
115 elfFile.seekg(eh.e_shoff);
116 if (elfFile.fail()) return -1;
117
118 /* Read shdr table entries */
119 shTable.resize(eh.e_shnum);
120
121 if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM;
122
123 return 0;
124}
125
126/* Read a section by its index - for ex to get sec hdr strtab blob */
127static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) {
128 vector<Elf64_Shdr> shTable;
Maciej Żenczykowskid56ec052021-01-15 00:27:04 -0800129 int ret = readSectionHeadersAll(elfFile, shTable);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700130 if (ret) return ret;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700131
132 elfFile.seekg(shTable[id].sh_offset);
133 if (elfFile.fail()) return -1;
134
135 sec.resize(shTable[id].sh_size);
136 if (!elfFile.read(sec.data(), shTable[id].sh_size)) return -1;
137
138 return 0;
139}
140
141/* Read whole section header string table */
142static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
143 Elf64_Ehdr eh;
Maciej Żenczykowskid56ec052021-01-15 00:27:04 -0800144 int ret = readElfHeader(elfFile, &eh);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700145 if (ret) return ret;
146
147 ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
148 if (ret) return ret;
149
150 return 0;
151}
152
153/* Get name from offset in strtab */
154static int getSymName(ifstream& elfFile, int nameOff, string& name) {
155 int ret;
156 vector<char> secStrTab;
157
158 ret = readSectionHeaderStrtab(elfFile, secStrTab);
159 if (ret) return ret;
160
161 if (nameOff >= (int)secStrTab.size()) return -1;
162
163 name = string((char*)secStrTab.data() + nameOff);
164 return 0;
165}
166
167/* Reads a full section by name - example to get the GPL license */
168static int readSectionByName(const char* name, ifstream& elfFile, vector<char>& data) {
169 vector<char> secStrTab;
170 vector<Elf64_Shdr> shTable;
171 int ret;
172
173 ret = readSectionHeadersAll(elfFile, shTable);
174 if (ret) return ret;
175
176 ret = readSectionHeaderStrtab(elfFile, secStrTab);
177 if (ret) return ret;
178
179 for (int i = 0; i < (int)shTable.size(); i++) {
180 char* secname = secStrTab.data() + shTable[i].sh_name;
181 if (!secname) continue;
182
183 if (!strcmp(secname, name)) {
184 vector<char> dataTmp;
185 dataTmp.resize(shTable[i].sh_size);
186
187 elfFile.seekg(shTable[i].sh_offset);
188 if (elfFile.fail()) return -1;
189
190 if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
191
192 data = dataTmp;
193 return 0;
194 }
195 }
196 return -2;
197}
198
199static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) {
200 int ret;
201 vector<Elf64_Shdr> shTable;
202
203 ret = readSectionHeadersAll(elfFile, shTable);
204 if (ret) return ret;
205
206 for (int i = 0; i < (int)shTable.size(); i++) {
207 if ((int)shTable[i].sh_type != type) continue;
208
209 vector<char> dataTmp;
210 dataTmp.resize(shTable[i].sh_size);
211
212 elfFile.seekg(shTable[i].sh_offset);
213 if (elfFile.fail()) return -1;
214
215 if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
216
217 data = dataTmp;
218 return 0;
219 }
220 return -2;
221}
222
223static bool symCompare(Elf64_Sym a, Elf64_Sym b) {
224 return (a.st_value < b.st_value);
225}
226
227static int readSymTab(ifstream& elfFile, int sort, vector<Elf64_Sym>& data) {
228 int ret, numElems;
229 Elf64_Sym* buf;
230 vector<char> secData;
231
232 ret = readSectionByType(elfFile, SHT_SYMTAB, secData);
233 if (ret) return ret;
234
235 buf = (Elf64_Sym*)secData.data();
236 numElems = (secData.size() / sizeof(Elf64_Sym));
237 data.assign(buf, buf + numElems);
238
239 if (sort) std::sort(data.begin(), data.end(), symCompare);
240 return 0;
241}
242
243static enum bpf_prog_type getSectionType(string& name) {
244 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
245 if (StartsWith(name, sectionNameTypes[i].name)) return sectionNameTypes[i].type;
246
247 return BPF_PROG_TYPE_UNSPEC;
248}
249
250/* If ever needed
251static string getSectionName(enum bpf_prog_type type)
252{
253 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
254 if (sectionNameTypes[i].type == type)
255 return std::string(sectionNameTypes[i].name);
256
257 return NULL;
258}
259*/
260
261static bool isRelSection(codeSection& cs, string& name) {
262 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++) {
263 sectionType st = sectionNameTypes[i];
264
265 if (st.type != cs.type) continue;
266
267 if (StartsWith(name, std::string(".rel") + st.name + "/"))
268 return true;
269 else
270 return false;
271 }
272 return false;
273}
274
Connor O'Brien3278a162020-02-13 21:45:22 -0800275static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd) {
276 vector<char> pdData;
277 int ret = readSectionByName("progs", elfFile, pdData);
278 if (ret == -2) return 0;
279 if (ret) return ret;
280
281 pd.resize(pdData.size() / sizeof(struct bpf_prog_def));
282 memcpy(pd.data(), pdData.data(), pdData.size());
283 return 0;
284}
285
286static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names) {
287 int ret;
288 string name;
289 vector<Elf64_Sym> symtab;
290 vector<Elf64_Shdr> shTable;
291
292 ret = readSymTab(elfFile, 1 /* sort */, symtab);
293 if (ret) return ret;
294
295 /* Get index of section */
296 ret = readSectionHeadersAll(elfFile, shTable);
297 if (ret) return ret;
298
299 int sec_idx = -1;
300 for (int i = 0; i < (int)shTable.size(); i++) {
301 ret = getSymName(elfFile, shTable[i].sh_name, name);
302 if (ret) return ret;
303
304 if (!name.compare(sectionName)) {
305 sec_idx = i;
306 break;
307 }
308 }
309
310 /* No section found with matching name*/
311 if (sec_idx == -1) {
Maciej Żenczykowski21f34cb2020-07-20 18:44:33 -0700312 ALOGW("No %s section could be found in elf object\n", sectionName.c_str());
Connor O'Brien3278a162020-02-13 21:45:22 -0800313 return -1;
314 }
315
316 for (int i = 0; i < (int)symtab.size(); i++) {
317 if (symtab[i].st_shndx == sec_idx) {
318 string s;
319 ret = getSymName(elfFile, symtab[i].st_name, s);
320 if (ret) return ret;
321 names.push_back(s);
322 }
323 }
324
325 return 0;
326}
327
Joel Fernandesd76a2002018-10-16 13:19:58 -0700328/* Read a section by its index - for ex to get sec hdr strtab blob */
329static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs) {
330 vector<Elf64_Shdr> shTable;
331 int entries, ret = 0;
332
333 ret = readSectionHeadersAll(elfFile, shTable);
334 if (ret) return ret;
335 entries = shTable.size();
336
Connor O'Brien3278a162020-02-13 21:45:22 -0800337 vector<struct bpf_prog_def> pd;
338 ret = readProgDefs(elfFile, pd);
339 if (ret) return ret;
340 vector<string> progDefNames;
341 ret = getSectionSymNames(elfFile, "progs", progDefNames);
342 if (!pd.empty() && ret) return ret;
343
Joel Fernandesd76a2002018-10-16 13:19:58 -0700344 for (int i = 0; i < entries; i++) {
345 string name;
346 codeSection cs_temp;
347 cs_temp.type = BPF_PROG_TYPE_UNSPEC;
348
349 ret = getSymName(elfFile, shTable[i].sh_name, name);
350 if (ret) return ret;
351
352 enum bpf_prog_type ptype = getSectionType(name);
353 if (ptype != BPF_PROG_TYPE_UNSPEC) {
Connor O'Brien3278a162020-02-13 21:45:22 -0800354 string oldName = name;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700355 deslash(name);
356 cs_temp.type = ptype;
357 cs_temp.name = name;
358
359 ret = readSectionByIdx(elfFile, i, cs_temp.data);
360 if (ret) return ret;
361 ALOGD("Loaded code section %d (%s)\n", i, name.c_str());
Connor O'Brien3278a162020-02-13 21:45:22 -0800362
363 vector<string> csSymNames;
364 ret = getSectionSymNames(elfFile, oldName, csSymNames);
365 if (ret || !csSymNames.size()) return ret;
366 for (size_t i = 0; i < progDefNames.size(); ++i) {
367 if (!progDefNames[i].compare(csSymNames[0] + "_def")) {
368 cs_temp.prog_def = pd[i];
369 break;
370 }
371 }
Joel Fernandesd76a2002018-10-16 13:19:58 -0700372 }
373
374 /* Check for rel section */
375 if (cs_temp.data.size() > 0 && i < entries) {
376 ret = getSymName(elfFile, shTable[i + 1].sh_name, name);
377 if (ret) return ret;
378
379 if (isRelSection(cs_temp, name)) {
380 ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data);
381 if (ret) return ret;
382 ALOGD("Loaded relo section %d (%s)\n", i, name.c_str());
383 }
384 }
385
386 if (cs_temp.data.size() > 0) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700387 cs.push_back(std::move(cs_temp));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700388 ALOGD("Adding section %d to cs list\n", i);
389 }
390 }
391 return 0;
392}
393
394static int getSymNameByIdx(ifstream& elfFile, int index, string& name) {
395 vector<Elf64_Sym> symtab;
396 int ret = 0;
397
398 ret = readSymTab(elfFile, 0 /* !sort */, symtab);
399 if (ret) return ret;
400
401 if (index >= (int)symtab.size()) return -1;
402
403 return getSymName(elfFile, symtab[index].st_name, name);
404}
405
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800406static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
407 const char* prefix) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700408 int ret;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700409 vector<char> mdData;
410 vector<struct bpf_map_def> md;
411 vector<string> mapNames;
412 string fname = pathToFilename(string(elfPath), true);
413
414 ret = readSectionByName("maps", elfFile, mdData);
Steven Morelandc0905b42019-12-12 14:21:20 -0800415 if (ret == -2) return 0; // no maps to read
Joel Fernandesd76a2002018-10-16 13:19:58 -0700416 if (ret) return ret;
417 md.resize(mdData.size() / sizeof(struct bpf_map_def));
418 memcpy(md.data(), mdData.data(), mdData.size());
419
Connor O'Brien3278a162020-02-13 21:45:22 -0800420 ret = getSectionSymNames(elfFile, "maps", mapNames);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700421 if (ret) return ret;
422
Joel Fernandesd76a2002018-10-16 13:19:58 -0700423 for (int i = 0; i < (int)mapNames.size(); i++) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700424 unique_fd fd;
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800425 // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
Joel Fernandesd76a2002018-10-16 13:19:58 -0700426 string mapPinLoc;
427 bool reuse = false;
428
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800429 mapPinLoc = string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700430 if (access(mapPinLoc.c_str(), F_OK) == 0) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700431 fd.reset(bpf_obj_get(mapPinLoc.c_str()));
432 ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get());
Joel Fernandesd76a2002018-10-16 13:19:58 -0700433 reuse = true;
434 } else {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700435 fd.reset(bpf_create_map(md[i].type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
436 md[i].max_entries, md[i].map_flags));
437 ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get());
Joel Fernandesd76a2002018-10-16 13:19:58 -0700438 }
439
440 if (fd < 0) return fd;
441 if (fd == 0) return -EINVAL;
442
443 if (!reuse) {
444 ret = bpf_obj_pin(fd, mapPinLoc.c_str());
Maciej Żenczykowski83f29772020-01-27 03:11:51 -0800445 if (ret) return -errno;
446 ret = chown(mapPinLoc.c_str(), (uid_t)md[i].uid, (gid_t)md[i].gid);
447 if (ret) return -errno;
448 ret = chmod(mapPinLoc.c_str(), md[i].mode);
449 if (ret) return -errno;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700450 }
451
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700452 mapFds.push_back(std::move(fd));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700453 }
454
455 return ret;
456}
457
458/* For debugging, dump all instructions */
459static void dumpIns(char* ins, int size) {
460 for (int row = 0; row < size / 8; row++) {
461 ALOGE("%d: ", row);
462 for (int j = 0; j < 8; j++) {
463 ALOGE("%3x ", ins[(row * 8) + j]);
464 }
465 ALOGE("\n");
466 }
467}
468
469/* For debugging, dump all code sections from cs list */
470static void dumpAllCs(vector<codeSection>& cs) {
471 for (int i = 0; i < (int)cs.size(); i++) {
472 ALOGE("Dumping cs %d, name %s\n", int(i), cs[i].name.c_str());
473 dumpIns((char*)cs[i].data.data(), cs[i].data.size());
474 ALOGE("-----------\n");
475 }
476}
477
478static void applyRelo(void* insnsPtr, Elf64_Addr offset, int fd) {
479 int insnIndex;
480 struct bpf_insn *insn, *insns;
481
482 insns = (struct bpf_insn*)(insnsPtr);
483
484 insnIndex = offset / sizeof(struct bpf_insn);
485 insn = &insns[insnIndex];
486
487 ALOGD(
488 "applying relo to instruction at byte offset: %d, \
489 insn offset %d , insn %lx\n",
490 (int)offset, (int)insnIndex, *(unsigned long*)insn);
491
492 if (insn->code != (BPF_LD | BPF_IMM | BPF_DW)) {
493 ALOGE("Dumping all instructions till ins %d\n", insnIndex);
494 ALOGE("invalid relo for insn %d: code 0x%x\n", insnIndex, insn->code);
495 dumpIns((char*)insnsPtr, (insnIndex + 3) * 8);
496 return;
497 }
498
499 insn->imm = fd;
500 insn->src_reg = BPF_PSEUDO_MAP_FD;
501}
502
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700503static void applyMapRelo(ifstream& elfFile, vector<unique_fd> &mapFds, vector<codeSection>& cs) {
Joel Fernandesd76a2002018-10-16 13:19:58 -0700504 vector<string> mapNames;
505
Connor O'Brien3278a162020-02-13 21:45:22 -0800506 int ret = getSectionSymNames(elfFile, "maps", mapNames);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700507 if (ret) return;
508
509 for (int k = 0; k != (int)cs.size(); k++) {
510 Elf64_Rel* rel = (Elf64_Rel*)(cs[k].rel_data.data());
511 int n_rel = cs[k].rel_data.size() / sizeof(*rel);
512
513 for (int i = 0; i < n_rel; i++) {
514 int symIndex = ELF64_R_SYM(rel[i].r_info);
515 string symName;
516
517 ret = getSymNameByIdx(elfFile, symIndex, symName);
518 if (ret) return;
519
520 /* Find the map fd and apply relo */
521 for (int j = 0; j < (int)mapNames.size(); j++) {
522 if (!mapNames[j].compare(symName)) {
523 applyRelo(cs[k].data.data(), rel[i].r_offset, mapFds[j]);
524 break;
525 }
526 }
527 }
528 }
529}
530
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800531static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license,
532 const char* prefix) {
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800533 unsigned kvers = kernelVersion();
534 int ret, fd;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700535
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800536 if (!kvers) return -1;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700537
538 string fname = pathToFilename(string(elfPath), true);
539
540 for (int i = 0; i < (int)cs.size(); i++) {
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700541 string name = cs[i].name;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700542
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800543 if (cs[i].prog_def.has_value()) {
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700544 unsigned min_kver = cs[i].prog_def->min_kver;
545 unsigned max_kver = cs[i].prog_def->max_kver;
546 ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)\n", i, name.c_str(), min_kver,
547 max_kver, kvers);
548 if (kvers < min_kver) continue;
549 if (kvers >= max_kver) continue;
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800550 }
551
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700552 // strip any potential $foo suffix
553 // this can be used to provide duplicate programs
554 // conditionally loaded based on running kernel version
Maciej Żenczykowski428843d2020-04-23 12:43:44 -0700555 name = name.substr(0, name.find_last_of('$'));
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700556
557 bool reuse = false;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700558 // Format of pin location is
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800559 // /sys/fs/bpf/<prefix>prog_<filename>_<mapname>
560 string progPinLoc = BPF_FS_PATH;
561 progPinLoc += prefix;
562 progPinLoc += "prog_";
Maciej Żenczykowski6c7871b2020-04-23 12:46:00 -0700563 progPinLoc += fname;
564 progPinLoc += '_';
565 progPinLoc += name;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700566 if (access(progPinLoc.c_str(), F_OK) == 0) {
Maciej Żenczykowskiaa295c82020-06-16 17:02:48 -0700567 fd = retrieveProgram(progPinLoc.c_str());
568 ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)\n", progPinLoc.c_str(), fd,
569 (fd < 0 ? std::strerror(errno) : "no error"));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700570 reuse = true;
571 } else {
572 vector<char> log_buf(BPF_LOAD_LOG_SZ, 0);
573
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700574 fd = bpf_prog_load(cs[i].type, name.c_str(), (struct bpf_insn*)cs[i].data.data(),
575 cs[i].data.size(), license.c_str(), kvers, 0, log_buf.data(),
576 log_buf.size());
Steven Moreland804bca02019-12-12 17:21:23 -0800577 ALOGD("bpf_prog_load lib call for %s (%s) returned fd: %d (%s)\n", elfPath,
578 cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error"));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700579
Maciej Żenczykowski524deef2020-02-11 11:12:37 -0800580 if (fd < 0) {
581 std::vector<std::string> lines = android::base::Split(log_buf.data(), "\n");
582
Maciej Żenczykowskiaa295c82020-06-16 17:02:48 -0700583 ALOGW("bpf_prog_load - BEGIN log_buf contents:");
584 for (const auto& line : lines) ALOGW("%s", line.c_str());
585 ALOGW("bpf_prog_load - END log_buf contents.");
586
587 if (cs[i].prog_def->optional) {
588 ALOGW("failed program is marked optional - continuing...");
589 continue;
590 }
591 ALOGE("non-optional program failed to load.");
Maciej Żenczykowski524deef2020-02-11 11:12:37 -0800592 }
Joel Fernandesd76a2002018-10-16 13:19:58 -0700593 }
594
595 if (fd < 0) return fd;
596 if (fd == 0) return -EINVAL;
597
598 if (!reuse) {
599 ret = bpf_obj_pin(fd, progPinLoc.c_str());
Connor O'Brien3278a162020-02-13 21:45:22 -0800600 if (ret) return -errno;
601 if (cs[i].prog_def.has_value()) {
602 if (chown(progPinLoc.c_str(), (uid_t)cs[i].prog_def->uid,
603 (gid_t)cs[i].prog_def->gid)) {
604 return -errno;
605 }
606 }
607 if (chmod(progPinLoc.c_str(), 0440)) return -errno;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700608 }
609
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700610 cs[i].prog_fd.reset(fd);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700611 }
612
613 return 0;
614}
615
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800616int loadProg(const char* elfPath, bool* isCritical, const char* prefix) {
Joel Fernandesd76a2002018-10-16 13:19:58 -0700617 vector<char> license;
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700618 vector<char> critical;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700619 vector<codeSection> cs;
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700620 vector<unique_fd> mapFds;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700621 int ret;
622
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700623 if (!isCritical) return -1;
624 *isCritical = false;
625
Joel Fernandesd76a2002018-10-16 13:19:58 -0700626 ifstream elfFile(elfPath, ios::in | ios::binary);
627 if (!elfFile.is_open()) return -1;
628
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700629 ret = readSectionByName("critical", elfFile, critical);
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700630 *isCritical = !ret;
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700631
Joel Fernandesd76a2002018-10-16 13:19:58 -0700632 ret = readSectionByName("license", elfFile, license);
633 if (ret) {
634 ALOGE("Couldn't find license in %s\n", elfPath);
635 return ret;
636 } else {
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700637 ALOGD("Loading %s%s ELF object %s with license %s\n",
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700638 *isCritical ? "critical for " : "optional", *isCritical ? (char*)critical.data() : "",
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700639 elfPath, (char*)license.data());
Joel Fernandesd76a2002018-10-16 13:19:58 -0700640 }
641
642 ret = readCodeSections(elfFile, cs);
643 if (ret) {
644 ALOGE("Couldn't read all code sections in %s\n", elfPath);
645 return ret;
646 }
647
648 /* Just for future debugging */
649 if (0) dumpAllCs(cs);
650
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800651 ret = createMaps(elfPath, elfFile, mapFds, prefix);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700652 if (ret) {
653 ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath);
654 return ret;
655 }
656
657 for (int i = 0; i < (int)mapFds.size(); i++)
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700658 ALOGD("map_fd found at %d is %d in %s\n", i, mapFds[i].get(), elfPath);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700659
660 applyMapRelo(elfFile, mapFds, cs);
661
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800662 ret = loadCodeSections(elfPath, cs, string(license.data()), prefix);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700663 if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d\n", ret);
664
665 return ret;
666}
667
Maciej Żenczykowski2090e342020-06-16 17:56:16 -0700668static bool waitSecondsForProgsLoaded(int seconds) {
669 bool ok =
670 android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(seconds));
671 if (!ok) ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", seconds);
672 return ok;
673}
674
Steven Moreland4891e612020-01-10 15:35:52 -0800675void waitForProgsLoaded() {
Maciej Żenczykowski2090e342020-06-16 17:56:16 -0700676 if (waitSecondsForProgsLoaded(5)) return;
677 if (waitSecondsForProgsLoaded(10)) return;
678 if (waitSecondsForProgsLoaded(20)) return;
679 while (!waitSecondsForProgsLoaded(60))
680 ; // loop until success
Steven Moreland4891e612020-01-10 15:35:52 -0800681}
682
Joel Fernandesd76a2002018-10-16 13:19:58 -0700683} // namespace bpf
684} // namespace android