blob: 01f896405ca6b8967160b8b62497de46035c502c [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"
Maciej Żenczykowski07375e22020-02-19 14:23:59 -080032#include "bpf/BpfUtils.h"
Joel Fernandesd76a2002018-10-16 13:19:58 -070033#include "include/libbpf_android.h"
34
35#include <cstdlib>
36#include <fstream>
37#include <iostream>
Connor O'Brien3278a162020-02-13 21:45:22 -080038#include <optional>
Joel Fernandesd76a2002018-10-16 13:19:58 -070039#include <string>
Christopher Ferrisc151c672019-02-01 15:31:26 -080040#include <vector>
Joel Fernandesd76a2002018-10-16 13:19:58 -070041
42#include <android-base/strings.h>
Connor O'Brien8d49fc72019-10-24 18:23:49 -070043#include <android-base/unique_fd.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070044
45#define BPF_FS_PATH "/sys/fs/bpf/"
46
47// Size of the BPF log buffer for verifier logging
48#define BPF_LOAD_LOG_SZ 0x1ffff
49
50using android::base::StartsWith;
Connor O'Brien8d49fc72019-10-24 18:23:49 -070051using android::base::unique_fd;
Joel Fernandesd76a2002018-10-16 13:19:58 -070052using std::ifstream;
53using std::ios;
Connor O'Brien3278a162020-02-13 21:45:22 -080054using std::optional;
Christopher Ferrisc151c672019-02-01 15:31:26 -080055using std::string;
Joel Fernandesd76a2002018-10-16 13:19:58 -070056using std::vector;
57
58namespace android {
59namespace bpf {
60
Maciej Żenczykowskif7c0d992021-01-21 16:01:04 -080061static string pathToFilename(const string& path, bool noext = false) {
62 vector<string> spath = android::base::Split(path, "/");
63 string ret = spath.back();
64
65 if (noext) {
66 size_t lastindex = ret.find_last_of('.');
67 return ret.substr(0, lastindex);
68 }
69 return ret;
70}
71
Joel Fernandesd76a2002018-10-16 13:19:58 -070072typedef struct {
73 const char* name;
74 enum bpf_prog_type type;
75} sectionType;
76
77/*
78 * Map section name prefixes to program types, the section name will be:
79 * SEC(<prefix>/<name-of-program>)
80 * For example:
81 * SEC("tracepoint/sched_switch_func") where sched_switch_funcs
82 * is the name of the program, and tracepoint is the type.
83 */
84sectionType sectionNameTypes[] = {
Maciej Żenczykowskiaa462222021-01-07 14:24:45 -080085 {"kprobe", BPF_PROG_TYPE_KPROBE},
86 {"tracepoint", BPF_PROG_TYPE_TRACEPOINT},
87 {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER},
88 {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB},
89 {"schedcls", BPF_PROG_TYPE_SCHED_CLS},
90 {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK},
91 {"xdp", BPF_PROG_TYPE_XDP},
Joel Fernandesd76a2002018-10-16 13:19:58 -070092
Maciej Żenczykowskiaa462222021-01-07 14:24:45 -080093 /* End of table */
94 {"END", BPF_PROG_TYPE_UNSPEC},
Joel Fernandesd76a2002018-10-16 13:19:58 -070095};
96
97typedef struct {
98 enum bpf_prog_type type;
99 string name;
100 vector<char> data;
101 vector<char> rel_data;
Connor O'Brien3278a162020-02-13 21:45:22 -0800102 optional<struct bpf_prog_def> prog_def;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700103
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700104 unique_fd prog_fd; /* fd after loading */
Joel Fernandesd76a2002018-10-16 13:19:58 -0700105} codeSection;
106
Joel Fernandesd76a2002018-10-16 13:19:58 -0700107static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) {
108 elfFile.seekg(0);
109 if (elfFile.fail()) return -1;
110
111 if (!elfFile.read((char*)eh, sizeof(*eh))) return -1;
112
113 return 0;
114}
115
116/* Reads all section header tables into an Shdr array */
117static int readSectionHeadersAll(ifstream& elfFile, vector<Elf64_Shdr>& shTable) {
118 Elf64_Ehdr eh;
119 int ret = 0;
120
121 ret = readElfHeader(elfFile, &eh);
122 if (ret) return ret;
123
124 elfFile.seekg(eh.e_shoff);
125 if (elfFile.fail()) return -1;
126
127 /* Read shdr table entries */
128 shTable.resize(eh.e_shnum);
129
130 if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM;
131
132 return 0;
133}
134
135/* Read a section by its index - for ex to get sec hdr strtab blob */
136static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) {
137 vector<Elf64_Shdr> shTable;
Maciej Żenczykowskid56ec052021-01-15 00:27:04 -0800138 int ret = readSectionHeadersAll(elfFile, shTable);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700139 if (ret) return ret;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700140
141 elfFile.seekg(shTable[id].sh_offset);
142 if (elfFile.fail()) return -1;
143
144 sec.resize(shTable[id].sh_size);
145 if (!elfFile.read(sec.data(), shTable[id].sh_size)) return -1;
146
147 return 0;
148}
149
150/* Read whole section header string table */
151static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
152 Elf64_Ehdr eh;
Maciej Żenczykowskid56ec052021-01-15 00:27:04 -0800153 int ret = readElfHeader(elfFile, &eh);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700154 if (ret) return ret;
155
156 ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
157 if (ret) return ret;
158
159 return 0;
160}
161
162/* Get name from offset in strtab */
163static int getSymName(ifstream& elfFile, int nameOff, string& name) {
164 int ret;
165 vector<char> secStrTab;
166
167 ret = readSectionHeaderStrtab(elfFile, secStrTab);
168 if (ret) return ret;
169
170 if (nameOff >= (int)secStrTab.size()) return -1;
171
172 name = string((char*)secStrTab.data() + nameOff);
173 return 0;
174}
175
176/* Reads a full section by name - example to get the GPL license */
177static int readSectionByName(const char* name, ifstream& elfFile, vector<char>& data) {
178 vector<char> secStrTab;
179 vector<Elf64_Shdr> shTable;
180 int ret;
181
182 ret = readSectionHeadersAll(elfFile, shTable);
183 if (ret) return ret;
184
185 ret = readSectionHeaderStrtab(elfFile, secStrTab);
186 if (ret) return ret;
187
188 for (int i = 0; i < (int)shTable.size(); i++) {
189 char* secname = secStrTab.data() + shTable[i].sh_name;
190 if (!secname) continue;
191
192 if (!strcmp(secname, name)) {
193 vector<char> dataTmp;
194 dataTmp.resize(shTable[i].sh_size);
195
196 elfFile.seekg(shTable[i].sh_offset);
197 if (elfFile.fail()) return -1;
198
199 if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
200
201 data = dataTmp;
202 return 0;
203 }
204 }
205 return -2;
206}
207
208static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) {
209 int ret;
210 vector<Elf64_Shdr> shTable;
211
212 ret = readSectionHeadersAll(elfFile, shTable);
213 if (ret) return ret;
214
215 for (int i = 0; i < (int)shTable.size(); i++) {
216 if ((int)shTable[i].sh_type != type) continue;
217
218 vector<char> dataTmp;
219 dataTmp.resize(shTable[i].sh_size);
220
221 elfFile.seekg(shTable[i].sh_offset);
222 if (elfFile.fail()) return -1;
223
224 if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
225
226 data = dataTmp;
227 return 0;
228 }
229 return -2;
230}
231
232static bool symCompare(Elf64_Sym a, Elf64_Sym b) {
233 return (a.st_value < b.st_value);
234}
235
236static int readSymTab(ifstream& elfFile, int sort, vector<Elf64_Sym>& data) {
237 int ret, numElems;
238 Elf64_Sym* buf;
239 vector<char> secData;
240
241 ret = readSectionByType(elfFile, SHT_SYMTAB, secData);
242 if (ret) return ret;
243
244 buf = (Elf64_Sym*)secData.data();
245 numElems = (secData.size() / sizeof(Elf64_Sym));
246 data.assign(buf, buf + numElems);
247
248 if (sort) std::sort(data.begin(), data.end(), symCompare);
249 return 0;
250}
251
252static enum bpf_prog_type getSectionType(string& name) {
253 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
254 if (StartsWith(name, sectionNameTypes[i].name)) return sectionNameTypes[i].type;
255
256 return BPF_PROG_TYPE_UNSPEC;
257}
258
259/* If ever needed
260static string getSectionName(enum bpf_prog_type type)
261{
262 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
263 if (sectionNameTypes[i].type == type)
Maciej Żenczykowskif7c0d992021-01-21 16:01:04 -0800264 return string(sectionNameTypes[i].name);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700265
266 return NULL;
267}
268*/
269
270static bool isRelSection(codeSection& cs, string& name) {
271 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++) {
272 sectionType st = sectionNameTypes[i];
273
274 if (st.type != cs.type) continue;
275
Maciej Żenczykowskif7c0d992021-01-21 16:01:04 -0800276 if (StartsWith(name, string(".rel") + st.name + "/"))
Joel Fernandesd76a2002018-10-16 13:19:58 -0700277 return true;
278 else
279 return false;
280 }
281 return false;
282}
283
Connor O'Brien3278a162020-02-13 21:45:22 -0800284static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd) {
285 vector<char> pdData;
286 int ret = readSectionByName("progs", elfFile, pdData);
287 if (ret == -2) return 0;
288 if (ret) return ret;
289
290 pd.resize(pdData.size() / sizeof(struct bpf_prog_def));
291 memcpy(pd.data(), pdData.data(), pdData.size());
292 return 0;
293}
294
295static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names) {
296 int ret;
297 string name;
298 vector<Elf64_Sym> symtab;
299 vector<Elf64_Shdr> shTable;
300
301 ret = readSymTab(elfFile, 1 /* sort */, symtab);
302 if (ret) return ret;
303
304 /* Get index of section */
305 ret = readSectionHeadersAll(elfFile, shTable);
306 if (ret) return ret;
307
308 int sec_idx = -1;
309 for (int i = 0; i < (int)shTable.size(); i++) {
310 ret = getSymName(elfFile, shTable[i].sh_name, name);
311 if (ret) return ret;
312
313 if (!name.compare(sectionName)) {
314 sec_idx = i;
315 break;
316 }
317 }
318
319 /* No section found with matching name*/
320 if (sec_idx == -1) {
Maciej Żenczykowski21f34cb2020-07-20 18:44:33 -0700321 ALOGW("No %s section could be found in elf object\n", sectionName.c_str());
Connor O'Brien3278a162020-02-13 21:45:22 -0800322 return -1;
323 }
324
325 for (int i = 0; i < (int)symtab.size(); i++) {
326 if (symtab[i].st_shndx == sec_idx) {
327 string s;
328 ret = getSymName(elfFile, symtab[i].st_name, s);
329 if (ret) return ret;
330 names.push_back(s);
331 }
332 }
333
334 return 0;
335}
336
Joel Fernandesd76a2002018-10-16 13:19:58 -0700337/* Read a section by its index - for ex to get sec hdr strtab blob */
338static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs) {
339 vector<Elf64_Shdr> shTable;
340 int entries, ret = 0;
341
342 ret = readSectionHeadersAll(elfFile, shTable);
343 if (ret) return ret;
344 entries = shTable.size();
345
Connor O'Brien3278a162020-02-13 21:45:22 -0800346 vector<struct bpf_prog_def> pd;
347 ret = readProgDefs(elfFile, pd);
348 if (ret) return ret;
349 vector<string> progDefNames;
350 ret = getSectionSymNames(elfFile, "progs", progDefNames);
351 if (!pd.empty() && ret) return ret;
352
Joel Fernandesd76a2002018-10-16 13:19:58 -0700353 for (int i = 0; i < entries; i++) {
354 string name;
355 codeSection cs_temp;
356 cs_temp.type = BPF_PROG_TYPE_UNSPEC;
357
358 ret = getSymName(elfFile, shTable[i].sh_name, name);
359 if (ret) return ret;
360
361 enum bpf_prog_type ptype = getSectionType(name);
362 if (ptype != BPF_PROG_TYPE_UNSPEC) {
Connor O'Brien3278a162020-02-13 21:45:22 -0800363 string oldName = name;
Maciej Żenczykowskif7c0d992021-01-21 16:01:04 -0800364
365 // convert all slashes to underscores
366 std::replace(name.begin(), name.end(), '/', '_');
367
Joel Fernandesd76a2002018-10-16 13:19:58 -0700368 cs_temp.type = ptype;
369 cs_temp.name = name;
370
371 ret = readSectionByIdx(elfFile, i, cs_temp.data);
372 if (ret) return ret;
373 ALOGD("Loaded code section %d (%s)\n", i, name.c_str());
Connor O'Brien3278a162020-02-13 21:45:22 -0800374
375 vector<string> csSymNames;
376 ret = getSectionSymNames(elfFile, oldName, csSymNames);
377 if (ret || !csSymNames.size()) return ret;
378 for (size_t i = 0; i < progDefNames.size(); ++i) {
379 if (!progDefNames[i].compare(csSymNames[0] + "_def")) {
380 cs_temp.prog_def = pd[i];
381 break;
382 }
383 }
Joel Fernandesd76a2002018-10-16 13:19:58 -0700384 }
385
386 /* Check for rel section */
387 if (cs_temp.data.size() > 0 && i < entries) {
388 ret = getSymName(elfFile, shTable[i + 1].sh_name, name);
389 if (ret) return ret;
390
391 if (isRelSection(cs_temp, name)) {
392 ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data);
393 if (ret) return ret;
394 ALOGD("Loaded relo section %d (%s)\n", i, name.c_str());
395 }
396 }
397
398 if (cs_temp.data.size() > 0) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700399 cs.push_back(std::move(cs_temp));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700400 ALOGD("Adding section %d to cs list\n", i);
401 }
402 }
403 return 0;
404}
405
406static int getSymNameByIdx(ifstream& elfFile, int index, string& name) {
407 vector<Elf64_Sym> symtab;
408 int ret = 0;
409
410 ret = readSymTab(elfFile, 0 /* !sort */, symtab);
411 if (ret) return ret;
412
413 if (index >= (int)symtab.size()) return -1;
414
415 return getSymName(elfFile, symtab[index].st_name, name);
416}
417
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800418static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
419 const char* prefix) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700420 int ret;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700421 vector<char> mdData;
422 vector<struct bpf_map_def> md;
423 vector<string> mapNames;
424 string fname = pathToFilename(string(elfPath), true);
425
426 ret = readSectionByName("maps", elfFile, mdData);
Steven Morelandc0905b42019-12-12 14:21:20 -0800427 if (ret == -2) return 0; // no maps to read
Joel Fernandesd76a2002018-10-16 13:19:58 -0700428 if (ret) return ret;
429 md.resize(mdData.size() / sizeof(struct bpf_map_def));
430 memcpy(md.data(), mdData.data(), mdData.size());
431
Connor O'Brien3278a162020-02-13 21:45:22 -0800432 ret = getSectionSymNames(elfFile, "maps", mapNames);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700433 if (ret) return ret;
434
Joel Fernandesd76a2002018-10-16 13:19:58 -0700435 for (int i = 0; i < (int)mapNames.size(); i++) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700436 unique_fd fd;
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800437 // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
Joel Fernandesd76a2002018-10-16 13:19:58 -0700438 string mapPinLoc;
439 bool reuse = false;
440
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800441 mapPinLoc = string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700442 if (access(mapPinLoc.c_str(), F_OK) == 0) {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700443 fd.reset(bpf_obj_get(mapPinLoc.c_str()));
444 ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get());
Joel Fernandesd76a2002018-10-16 13:19:58 -0700445 reuse = true;
446 } else {
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700447 fd.reset(bpf_create_map(md[i].type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
448 md[i].max_entries, md[i].map_flags));
449 ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get());
Joel Fernandesd76a2002018-10-16 13:19:58 -0700450 }
451
452 if (fd < 0) return fd;
453 if (fd == 0) return -EINVAL;
454
455 if (!reuse) {
456 ret = bpf_obj_pin(fd, mapPinLoc.c_str());
Maciej Żenczykowski83f29772020-01-27 03:11:51 -0800457 if (ret) return -errno;
458 ret = chown(mapPinLoc.c_str(), (uid_t)md[i].uid, (gid_t)md[i].gid);
459 if (ret) return -errno;
460 ret = chmod(mapPinLoc.c_str(), md[i].mode);
461 if (ret) return -errno;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700462 }
463
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700464 mapFds.push_back(std::move(fd));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700465 }
466
467 return ret;
468}
469
470/* For debugging, dump all instructions */
471static void dumpIns(char* ins, int size) {
472 for (int row = 0; row < size / 8; row++) {
473 ALOGE("%d: ", row);
474 for (int j = 0; j < 8; j++) {
475 ALOGE("%3x ", ins[(row * 8) + j]);
476 }
477 ALOGE("\n");
478 }
479}
480
481/* For debugging, dump all code sections from cs list */
482static void dumpAllCs(vector<codeSection>& cs) {
483 for (int i = 0; i < (int)cs.size(); i++) {
484 ALOGE("Dumping cs %d, name %s\n", int(i), cs[i].name.c_str());
485 dumpIns((char*)cs[i].data.data(), cs[i].data.size());
486 ALOGE("-----------\n");
487 }
488}
489
490static void applyRelo(void* insnsPtr, Elf64_Addr offset, int fd) {
491 int insnIndex;
492 struct bpf_insn *insn, *insns;
493
494 insns = (struct bpf_insn*)(insnsPtr);
495
496 insnIndex = offset / sizeof(struct bpf_insn);
497 insn = &insns[insnIndex];
498
499 ALOGD(
500 "applying relo to instruction at byte offset: %d, \
501 insn offset %d , insn %lx\n",
502 (int)offset, (int)insnIndex, *(unsigned long*)insn);
503
504 if (insn->code != (BPF_LD | BPF_IMM | BPF_DW)) {
505 ALOGE("Dumping all instructions till ins %d\n", insnIndex);
506 ALOGE("invalid relo for insn %d: code 0x%x\n", insnIndex, insn->code);
507 dumpIns((char*)insnsPtr, (insnIndex + 3) * 8);
508 return;
509 }
510
511 insn->imm = fd;
512 insn->src_reg = BPF_PSEUDO_MAP_FD;
513}
514
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700515static void applyMapRelo(ifstream& elfFile, vector<unique_fd> &mapFds, vector<codeSection>& cs) {
Joel Fernandesd76a2002018-10-16 13:19:58 -0700516 vector<string> mapNames;
517
Connor O'Brien3278a162020-02-13 21:45:22 -0800518 int ret = getSectionSymNames(elfFile, "maps", mapNames);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700519 if (ret) return;
520
521 for (int k = 0; k != (int)cs.size(); k++) {
522 Elf64_Rel* rel = (Elf64_Rel*)(cs[k].rel_data.data());
523 int n_rel = cs[k].rel_data.size() / sizeof(*rel);
524
525 for (int i = 0; i < n_rel; i++) {
526 int symIndex = ELF64_R_SYM(rel[i].r_info);
527 string symName;
528
529 ret = getSymNameByIdx(elfFile, symIndex, symName);
530 if (ret) return;
531
532 /* Find the map fd and apply relo */
533 for (int j = 0; j < (int)mapNames.size(); j++) {
534 if (!mapNames[j].compare(symName)) {
535 applyRelo(cs[k].data.data(), rel[i].r_offset, mapFds[j]);
536 break;
537 }
538 }
539 }
540 }
541}
542
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800543static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license,
544 const char* prefix) {
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800545 unsigned kvers = kernelVersion();
546 int ret, fd;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700547
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800548 if (!kvers) return -1;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700549
550 string fname = pathToFilename(string(elfPath), true);
551
552 for (int i = 0; i < (int)cs.size(); i++) {
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700553 string name = cs[i].name;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700554
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800555 if (cs[i].prog_def.has_value()) {
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700556 unsigned min_kver = cs[i].prog_def->min_kver;
557 unsigned max_kver = cs[i].prog_def->max_kver;
558 ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)\n", i, name.c_str(), min_kver,
559 max_kver, kvers);
560 if (kvers < min_kver) continue;
561 if (kvers >= max_kver) continue;
Maciej Żenczykowski07375e22020-02-19 14:23:59 -0800562 }
563
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700564 // strip any potential $foo suffix
565 // this can be used to provide duplicate programs
566 // conditionally loaded based on running kernel version
Maciej Żenczykowski428843d2020-04-23 12:43:44 -0700567 name = name.substr(0, name.find_last_of('$'));
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700568
569 bool reuse = false;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700570 // Format of pin location is
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800571 // /sys/fs/bpf/<prefix>prog_<filename>_<mapname>
572 string progPinLoc = BPF_FS_PATH;
573 progPinLoc += prefix;
574 progPinLoc += "prog_";
Maciej Żenczykowski6c7871b2020-04-23 12:46:00 -0700575 progPinLoc += fname;
576 progPinLoc += '_';
577 progPinLoc += name;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700578 if (access(progPinLoc.c_str(), F_OK) == 0) {
Maciej Żenczykowskiaa295c82020-06-16 17:02:48 -0700579 fd = retrieveProgram(progPinLoc.c_str());
580 ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)\n", progPinLoc.c_str(), fd,
581 (fd < 0 ? std::strerror(errno) : "no error"));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700582 reuse = true;
583 } else {
584 vector<char> log_buf(BPF_LOAD_LOG_SZ, 0);
585
Maciej Żenczykowski681f6042020-04-21 15:34:18 -0700586 fd = bpf_prog_load(cs[i].type, name.c_str(), (struct bpf_insn*)cs[i].data.data(),
587 cs[i].data.size(), license.c_str(), kvers, 0, log_buf.data(),
588 log_buf.size());
Steven Moreland804bca02019-12-12 17:21:23 -0800589 ALOGD("bpf_prog_load lib call for %s (%s) returned fd: %d (%s)\n", elfPath,
590 cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error"));
Joel Fernandesd76a2002018-10-16 13:19:58 -0700591
Maciej Żenczykowski524deef2020-02-11 11:12:37 -0800592 if (fd < 0) {
Maciej Żenczykowskif7c0d992021-01-21 16:01:04 -0800593 vector<string> lines = android::base::Split(log_buf.data(), "\n");
Maciej Żenczykowski524deef2020-02-11 11:12:37 -0800594
Maciej Żenczykowskiaa295c82020-06-16 17:02:48 -0700595 ALOGW("bpf_prog_load - BEGIN log_buf contents:");
596 for (const auto& line : lines) ALOGW("%s", line.c_str());
597 ALOGW("bpf_prog_load - END log_buf contents.");
598
599 if (cs[i].prog_def->optional) {
600 ALOGW("failed program is marked optional - continuing...");
601 continue;
602 }
603 ALOGE("non-optional program failed to load.");
Maciej Żenczykowski524deef2020-02-11 11:12:37 -0800604 }
Joel Fernandesd76a2002018-10-16 13:19:58 -0700605 }
606
607 if (fd < 0) return fd;
608 if (fd == 0) return -EINVAL;
609
610 if (!reuse) {
611 ret = bpf_obj_pin(fd, progPinLoc.c_str());
Connor O'Brien3278a162020-02-13 21:45:22 -0800612 if (ret) return -errno;
613 if (cs[i].prog_def.has_value()) {
614 if (chown(progPinLoc.c_str(), (uid_t)cs[i].prog_def->uid,
615 (gid_t)cs[i].prog_def->gid)) {
616 return -errno;
617 }
618 }
619 if (chmod(progPinLoc.c_str(), 0440)) return -errno;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700620 }
621
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700622 cs[i].prog_fd.reset(fd);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700623 }
624
625 return 0;
626}
627
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800628int loadProg(const char* elfPath, bool* isCritical, const char* prefix) {
Joel Fernandesd76a2002018-10-16 13:19:58 -0700629 vector<char> license;
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700630 vector<char> critical;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700631 vector<codeSection> cs;
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700632 vector<unique_fd> mapFds;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700633 int ret;
634
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700635 if (!isCritical) return -1;
636 *isCritical = false;
637
Joel Fernandesd76a2002018-10-16 13:19:58 -0700638 ifstream elfFile(elfPath, ios::in | ios::binary);
639 if (!elfFile.is_open()) return -1;
640
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700641 ret = readSectionByName("critical", elfFile, critical);
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700642 *isCritical = !ret;
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700643
Joel Fernandesd76a2002018-10-16 13:19:58 -0700644 ret = readSectionByName("license", elfFile, license);
645 if (ret) {
646 ALOGE("Couldn't find license in %s\n", elfPath);
647 return ret;
648 } else {
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700649 ALOGD("Loading %s%s ELF object %s with license %s\n",
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700650 *isCritical ? "critical for " : "optional", *isCritical ? (char*)critical.data() : "",
Maciej Żenczykowski4ba8c1c2020-06-10 15:49:31 -0700651 elfPath, (char*)license.data());
Joel Fernandesd76a2002018-10-16 13:19:58 -0700652 }
653
654 ret = readCodeSections(elfFile, cs);
655 if (ret) {
656 ALOGE("Couldn't read all code sections in %s\n", elfPath);
657 return ret;
658 }
659
660 /* Just for future debugging */
661 if (0) dumpAllCs(cs);
662
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800663 ret = createMaps(elfPath, elfFile, mapFds, prefix);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700664 if (ret) {
665 ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath);
666 return ret;
667 }
668
669 for (int i = 0; i < (int)mapFds.size(); i++)
Connor O'Brien8d49fc72019-10-24 18:23:49 -0700670 ALOGD("map_fd found at %d is %d in %s\n", i, mapFds[i].get(), elfPath);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700671
672 applyMapRelo(elfFile, mapFds, cs);
673
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800674 ret = loadCodeSections(elfPath, cs, string(license.data()), prefix);
Joel Fernandesd76a2002018-10-16 13:19:58 -0700675 if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d\n", ret);
676
677 return ret;
678}
679
Joel Fernandesd76a2002018-10-16 13:19:58 -0700680} // namespace bpf
681} // namespace android