1 /*
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>
27 #include <sys/stat.h>
28 #include <sys/utsname.h>
29 #include <unistd.h>
30 
31 #include "../progs/include/bpf_map_def.h"
32 #include "LoaderUtils.h"
33 #include "bpf/BpfUtils.h"
34 #include "include/libbpf_android.h"
35 
36 #include <cstdlib>
37 #include <fstream>
38 #include <iostream>
39 #include <optional>
40 #include <string>
41 #include <vector>
42 
43 #include <android-base/properties.h>
44 #include <android-base/strings.h>
45 #include <android-base/unique_fd.h>
46 
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 
52 using android::base::StartsWith;
53 using android::base::unique_fd;
54 using std::ifstream;
55 using std::ios;
56 using std::optional;
57 using std::string;
58 using std::vector;
59 
60 namespace android {
61 namespace bpf {
62 
63 typedef 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  */
75 sectionType sectionNameTypes[] = {
76     {"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 
83     /* End of table */
84     {"END", BPF_PROG_TYPE_UNSPEC},
85 };
86 
87 typedef struct {
88     enum bpf_prog_type type;
89     string name;
90     vector<char> data;
91     vector<char> rel_data;
92     optional<struct bpf_prog_def> prog_def;
93 
94     unique_fd prog_fd; /* fd after loading */
95 } codeSection;
96 
readElfHeader(ifstream & elfFile,Elf64_Ehdr * eh)97 static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) {
98     elfFile.seekg(0);
99     if (elfFile.fail()) return -1;
100 
101     if (!elfFile.read((char*)eh, sizeof(*eh))) return -1;
102 
103     return 0;
104 }
105 
106 /* Reads all section header tables into an Shdr array */
readSectionHeadersAll(ifstream & elfFile,vector<Elf64_Shdr> & shTable)107 static int readSectionHeadersAll(ifstream& elfFile, vector<Elf64_Shdr>& shTable) {
108     Elf64_Ehdr eh;
109     int ret = 0;
110 
111     ret = readElfHeader(elfFile, &eh);
112     if (ret) return ret;
113 
114     elfFile.seekg(eh.e_shoff);
115     if (elfFile.fail()) return -1;
116 
117     /* Read shdr table entries */
118     shTable.resize(eh.e_shnum);
119 
120     if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM;
121 
122     return 0;
123 }
124 
125 /* Read a section by its index - for ex to get sec hdr strtab blob */
readSectionByIdx(ifstream & elfFile,int id,vector<char> & sec)126 static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) {
127     vector<Elf64_Shdr> shTable;
128     int entries, ret = 0;
129 
130     ret = readSectionHeadersAll(elfFile, shTable);
131     if (ret) return ret;
132     entries = shTable.size();
133 
134     elfFile.seekg(shTable[id].sh_offset);
135     if (elfFile.fail()) return -1;
136 
137     sec.resize(shTable[id].sh_size);
138     if (!elfFile.read(sec.data(), shTable[id].sh_size)) return -1;
139 
140     return 0;
141 }
142 
143 /* Read whole section header string table */
readSectionHeaderStrtab(ifstream & elfFile,vector<char> & strtab)144 static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
145     Elf64_Ehdr eh;
146     int ret = 0;
147 
148     ret = readElfHeader(elfFile, &eh);
149     if (ret) return ret;
150 
151     ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
152     if (ret) return ret;
153 
154     return 0;
155 }
156 
157 /* Get name from offset in strtab */
getSymName(ifstream & elfFile,int nameOff,string & name)158 static int getSymName(ifstream& elfFile, int nameOff, string& name) {
159     int ret;
160     vector<char> secStrTab;
161 
162     ret = readSectionHeaderStrtab(elfFile, secStrTab);
163     if (ret) return ret;
164 
165     if (nameOff >= (int)secStrTab.size()) return -1;
166 
167     name = string((char*)secStrTab.data() + nameOff);
168     return 0;
169 }
170 
171 /* Reads a full section by name - example to get the GPL license */
readSectionByName(const char * name,ifstream & elfFile,vector<char> & data)172 static int readSectionByName(const char* name, ifstream& elfFile, vector<char>& data) {
173     vector<char> secStrTab;
174     vector<Elf64_Shdr> shTable;
175     int ret;
176 
177     ret = readSectionHeadersAll(elfFile, shTable);
178     if (ret) return ret;
179 
180     ret = readSectionHeaderStrtab(elfFile, secStrTab);
181     if (ret) return ret;
182 
183     for (int i = 0; i < (int)shTable.size(); i++) {
184         char* secname = secStrTab.data() + shTable[i].sh_name;
185         if (!secname) continue;
186 
187         if (!strcmp(secname, name)) {
188             vector<char> dataTmp;
189             dataTmp.resize(shTable[i].sh_size);
190 
191             elfFile.seekg(shTable[i].sh_offset);
192             if (elfFile.fail()) return -1;
193 
194             if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
195 
196             data = dataTmp;
197             return 0;
198         }
199     }
200     return -2;
201 }
202 
readSectionByType(ifstream & elfFile,int type,vector<char> & data)203 static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) {
204     int ret;
205     vector<Elf64_Shdr> shTable;
206 
207     ret = readSectionHeadersAll(elfFile, shTable);
208     if (ret) return ret;
209 
210     for (int i = 0; i < (int)shTable.size(); i++) {
211         if ((int)shTable[i].sh_type != type) continue;
212 
213         vector<char> dataTmp;
214         dataTmp.resize(shTable[i].sh_size);
215 
216         elfFile.seekg(shTable[i].sh_offset);
217         if (elfFile.fail()) return -1;
218 
219         if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
220 
221         data = dataTmp;
222         return 0;
223     }
224     return -2;
225 }
226 
symCompare(Elf64_Sym a,Elf64_Sym b)227 static bool symCompare(Elf64_Sym a, Elf64_Sym b) {
228     return (a.st_value < b.st_value);
229 }
230 
readSymTab(ifstream & elfFile,int sort,vector<Elf64_Sym> & data)231 static int readSymTab(ifstream& elfFile, int sort, vector<Elf64_Sym>& data) {
232     int ret, numElems;
233     Elf64_Sym* buf;
234     vector<char> secData;
235 
236     ret = readSectionByType(elfFile, SHT_SYMTAB, secData);
237     if (ret) return ret;
238 
239     buf = (Elf64_Sym*)secData.data();
240     numElems = (secData.size() / sizeof(Elf64_Sym));
241     data.assign(buf, buf + numElems);
242 
243     if (sort) std::sort(data.begin(), data.end(), symCompare);
244     return 0;
245 }
246 
getSectionType(string & name)247 static enum bpf_prog_type getSectionType(string& name) {
248     for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
249         if (StartsWith(name, sectionNameTypes[i].name)) return sectionNameTypes[i].type;
250 
251     return BPF_PROG_TYPE_UNSPEC;
252 }
253 
254 /* If ever needed
255 static string getSectionName(enum bpf_prog_type type)
256 {
257     for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
258         if (sectionNameTypes[i].type == type)
259             return std::string(sectionNameTypes[i].name);
260 
261     return NULL;
262 }
263 */
264 
isRelSection(codeSection & cs,string & name)265 static bool isRelSection(codeSection& cs, string& name) {
266     for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++) {
267         sectionType st = sectionNameTypes[i];
268 
269         if (st.type != cs.type) continue;
270 
271         if (StartsWith(name, std::string(".rel") + st.name + "/"))
272             return true;
273         else
274             return false;
275     }
276     return false;
277 }
278 
readProgDefs(ifstream & elfFile,vector<struct bpf_prog_def> & pd)279 static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd) {
280     vector<char> pdData;
281     int ret = readSectionByName("progs", elfFile, pdData);
282     if (ret == -2) return 0;
283     if (ret) return ret;
284 
285     pd.resize(pdData.size() / sizeof(struct bpf_prog_def));
286     memcpy(pd.data(), pdData.data(), pdData.size());
287     return 0;
288 }
289 
getSectionSymNames(ifstream & elfFile,const string & sectionName,vector<string> & names)290 static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names) {
291     int ret;
292     string name;
293     vector<Elf64_Sym> symtab;
294     vector<Elf64_Shdr> shTable;
295 
296     ret = readSymTab(elfFile, 1 /* sort */, symtab);
297     if (ret) return ret;
298 
299     /* Get index of section */
300     ret = readSectionHeadersAll(elfFile, shTable);
301     if (ret) return ret;
302 
303     int sec_idx = -1;
304     for (int i = 0; i < (int)shTable.size(); i++) {
305         ret = getSymName(elfFile, shTable[i].sh_name, name);
306         if (ret) return ret;
307 
308         if (!name.compare(sectionName)) {
309             sec_idx = i;
310             break;
311         }
312     }
313 
314     /* No section found with matching name*/
315     if (sec_idx == -1) {
316         ALOGE("No %s section could be found in elf object\n", sectionName.c_str());
317         return -1;
318     }
319 
320     for (int i = 0; i < (int)symtab.size(); i++) {
321         if (symtab[i].st_shndx == sec_idx) {
322             string s;
323             ret = getSymName(elfFile, symtab[i].st_name, s);
324             if (ret) return ret;
325             names.push_back(s);
326         }
327     }
328 
329     return 0;
330 }
331 
332 /* Read a section by its index - for ex to get sec hdr strtab blob */
readCodeSections(ifstream & elfFile,vector<codeSection> & cs)333 static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs) {
334     vector<Elf64_Shdr> shTable;
335     int entries, ret = 0;
336 
337     ret = readSectionHeadersAll(elfFile, shTable);
338     if (ret) return ret;
339     entries = shTable.size();
340 
341     vector<struct bpf_prog_def> pd;
342     ret = readProgDefs(elfFile, pd);
343     if (ret) return ret;
344     vector<string> progDefNames;
345     ret = getSectionSymNames(elfFile, "progs", progDefNames);
346     if (!pd.empty() && ret) return ret;
347 
348     for (int i = 0; i < entries; i++) {
349         string name;
350         codeSection cs_temp;
351         cs_temp.type = BPF_PROG_TYPE_UNSPEC;
352 
353         ret = getSymName(elfFile, shTable[i].sh_name, name);
354         if (ret) return ret;
355 
356         enum bpf_prog_type ptype = getSectionType(name);
357         if (ptype != BPF_PROG_TYPE_UNSPEC) {
358             string oldName = name;
359             deslash(name);
360             cs_temp.type = ptype;
361             cs_temp.name = name;
362 
363             ret = readSectionByIdx(elfFile, i, cs_temp.data);
364             if (ret) return ret;
365             ALOGD("Loaded code section %d (%s)\n", i, name.c_str());
366 
367             vector<string> csSymNames;
368             ret = getSectionSymNames(elfFile, oldName, csSymNames);
369             if (ret || !csSymNames.size()) return ret;
370             for (size_t i = 0; i < progDefNames.size(); ++i) {
371                 if (!progDefNames[i].compare(csSymNames[0] + "_def")) {
372                     cs_temp.prog_def = pd[i];
373                     break;
374                 }
375             }
376         }
377 
378         /* Check for rel section */
379         if (cs_temp.data.size() > 0 && i < entries) {
380             ret = getSymName(elfFile, shTable[i + 1].sh_name, name);
381             if (ret) return ret;
382 
383             if (isRelSection(cs_temp, name)) {
384                 ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data);
385                 if (ret) return ret;
386                 ALOGD("Loaded relo section %d (%s)\n", i, name.c_str());
387             }
388         }
389 
390         if (cs_temp.data.size() > 0) {
391             cs.push_back(std::move(cs_temp));
392             ALOGD("Adding section %d to cs list\n", i);
393         }
394     }
395     return 0;
396 }
397 
getSymNameByIdx(ifstream & elfFile,int index,string & name)398 static int getSymNameByIdx(ifstream& elfFile, int index, string& name) {
399     vector<Elf64_Sym> symtab;
400     int ret = 0;
401 
402     ret = readSymTab(elfFile, 0 /* !sort */, symtab);
403     if (ret) return ret;
404 
405     if (index >= (int)symtab.size()) return -1;
406 
407     return getSymName(elfFile, symtab[index].st_name, name);
408 }
409 
createMaps(const char * elfPath,ifstream & elfFile,vector<unique_fd> & mapFds)410 static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds) {
411     int ret;
412     vector<char> mdData;
413     vector<struct bpf_map_def> md;
414     vector<string> mapNames;
415     string fname = pathToFilename(string(elfPath), true);
416 
417     ret = readSectionByName("maps", elfFile, mdData);
418     if (ret == -2) return 0;  // no maps to read
419     if (ret) return ret;
420     md.resize(mdData.size() / sizeof(struct bpf_map_def));
421     memcpy(md.data(), mdData.data(), mdData.size());
422 
423     ret = getSectionSymNames(elfFile, "maps", mapNames);
424     if (ret) return ret;
425 
426     for (int i = 0; i < (int)mapNames.size(); i++) {
427         unique_fd fd;
428         // Format of pin location is /sys/fs/bpf/map_<filename>_<mapname>
429         string mapPinLoc;
430         bool reuse = false;
431 
432         mapPinLoc = string(BPF_FS_PATH) + "map_" + fname + "_" + string(mapNames[i]);
433         if (access(mapPinLoc.c_str(), F_OK) == 0) {
434             fd.reset(bpf_obj_get(mapPinLoc.c_str()));
435             ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get());
436             reuse = true;
437         } else {
438             fd.reset(bpf_create_map(md[i].type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
439                                     md[i].max_entries, md[i].map_flags));
440             ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get());
441         }
442 
443         if (fd < 0) return fd;
444         if (fd == 0) return -EINVAL;
445 
446         if (!reuse) {
447             ret = bpf_obj_pin(fd, mapPinLoc.c_str());
448             if (ret) return -errno;
449             ret = chown(mapPinLoc.c_str(), (uid_t)md[i].uid, (gid_t)md[i].gid);
450             if (ret) return -errno;
451             ret = chmod(mapPinLoc.c_str(), md[i].mode);
452             if (ret) return -errno;
453         }
454 
455         mapFds.push_back(std::move(fd));
456     }
457 
458     return ret;
459 }
460 
461 /* For debugging, dump all instructions */
dumpIns(char * ins,int size)462 static void dumpIns(char* ins, int size) {
463     for (int row = 0; row < size / 8; row++) {
464         ALOGE("%d: ", row);
465         for (int j = 0; j < 8; j++) {
466             ALOGE("%3x ", ins[(row * 8) + j]);
467         }
468         ALOGE("\n");
469     }
470 }
471 
472 /* For debugging, dump all code sections from cs list */
dumpAllCs(vector<codeSection> & cs)473 static void dumpAllCs(vector<codeSection>& cs) {
474     for (int i = 0; i < (int)cs.size(); i++) {
475         ALOGE("Dumping cs %d, name %s\n", int(i), cs[i].name.c_str());
476         dumpIns((char*)cs[i].data.data(), cs[i].data.size());
477         ALOGE("-----------\n");
478     }
479 }
480 
applyRelo(void * insnsPtr,Elf64_Addr offset,int fd)481 static void applyRelo(void* insnsPtr, Elf64_Addr offset, int fd) {
482     int insnIndex;
483     struct bpf_insn *insn, *insns;
484 
485     insns = (struct bpf_insn*)(insnsPtr);
486 
487     insnIndex = offset / sizeof(struct bpf_insn);
488     insn = &insns[insnIndex];
489 
490     ALOGD(
491         "applying relo to instruction at byte offset: %d, \
492 	       insn offset %d , insn %lx\n",
493         (int)offset, (int)insnIndex, *(unsigned long*)insn);
494 
495     if (insn->code != (BPF_LD | BPF_IMM | BPF_DW)) {
496         ALOGE("Dumping all instructions till ins %d\n", insnIndex);
497         ALOGE("invalid relo for insn %d: code 0x%x\n", insnIndex, insn->code);
498         dumpIns((char*)insnsPtr, (insnIndex + 3) * 8);
499         return;
500     }
501 
502     insn->imm = fd;
503     insn->src_reg = BPF_PSEUDO_MAP_FD;
504 }
505 
applyMapRelo(ifstream & elfFile,vector<unique_fd> & mapFds,vector<codeSection> & cs)506 static void applyMapRelo(ifstream& elfFile, vector<unique_fd> &mapFds, vector<codeSection>& cs) {
507     vector<string> mapNames;
508 
509     int ret = getSectionSymNames(elfFile, "maps", mapNames);
510     if (ret) return;
511 
512     for (int k = 0; k != (int)cs.size(); k++) {
513         Elf64_Rel* rel = (Elf64_Rel*)(cs[k].rel_data.data());
514         int n_rel = cs[k].rel_data.size() / sizeof(*rel);
515 
516         for (int i = 0; i < n_rel; i++) {
517             int symIndex = ELF64_R_SYM(rel[i].r_info);
518             string symName;
519 
520             ret = getSymNameByIdx(elfFile, symIndex, symName);
521             if (ret) return;
522 
523             /* Find the map fd and apply relo */
524             for (int j = 0; j < (int)mapNames.size(); j++) {
525                 if (!mapNames[j].compare(symName)) {
526                     applyRelo(cs[k].data.data(), rel[i].r_offset, mapFds[j]);
527                     break;
528                 }
529             }
530         }
531     }
532 }
533 
loadCodeSections(const char * elfPath,vector<codeSection> & cs,const string & license)534 static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license) {
535     unsigned kvers = kernelVersion();
536     int ret, fd;
537 
538     if (!kvers) return -1;
539 
540     string fname = pathToFilename(string(elfPath), true);
541 
542     for (int i = 0; i < (int)cs.size(); i++) {
543         string name = cs[i].name;
544 
545         if (cs[i].prog_def.has_value()) {
546             unsigned min_kver = cs[i].prog_def->min_kver;
547             unsigned max_kver = cs[i].prog_def->max_kver;
548             ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)\n", i, name.c_str(), min_kver,
549                   max_kver, kvers);
550             if (kvers < min_kver) continue;
551             if (kvers >= max_kver) continue;
552         }
553 
554         // strip any potential $foo suffix
555         // this can be used to provide duplicate programs
556         // conditionally loaded based on running kernel version
557         name = name.substr(0, name.find_last_of('$'));
558 
559         bool reuse = false;
560         // Format of pin location is
561         // /sys/fs/bpf/prog_<filename>_<mapname>
562         string progPinLoc = BPF_FS_PATH "prog_";
563         progPinLoc += fname;
564         progPinLoc += '_';
565         progPinLoc += name;
566         if (access(progPinLoc.c_str(), F_OK) == 0) {
567             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"));
570             reuse = true;
571         } else {
572             vector<char> log_buf(BPF_LOAD_LOG_SZ, 0);
573 
574             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());
577             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"));
579 
580             if (fd < 0) {
581                 std::vector<std::string> lines = android::base::Split(log_buf.data(), "\n");
582 
583                 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.");
592             }
593         }
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());
600             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;
608         }
609 
610         cs[i].prog_fd.reset(fd);
611     }
612 
613     return 0;
614 }
615 
loadProg(const char * elfPath,bool * isCritical)616 int loadProg(const char* elfPath, bool* isCritical) {
617     vector<char> license;
618     vector<char> critical;
619     vector<codeSection> cs;
620     vector<unique_fd> mapFds;
621     int ret;
622 
623     if (!isCritical) return -1;
624     *isCritical = false;
625 
626     ifstream elfFile(elfPath, ios::in | ios::binary);
627     if (!elfFile.is_open()) return -1;
628 
629     ret = readSectionByName("critical", elfFile, critical);
630     *isCritical = !ret;
631 
632     ret = readSectionByName("license", elfFile, license);
633     if (ret) {
634         ALOGE("Couldn't find license in %s\n", elfPath);
635         return ret;
636     } else {
637         ALOGD("Loading %s%s ELF object %s with license %s\n",
638               *isCritical ? "critical for " : "optional", *isCritical ? (char*)critical.data() : "",
639               elfPath, (char*)license.data());
640     }
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 
651     ret = createMaps(elfPath, elfFile, mapFds);
652     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++)
658         ALOGD("map_fd found at %d is %d in %s\n", i, mapFds[i].get(), elfPath);
659 
660     applyMapRelo(elfFile, mapFds, cs);
661 
662     ret = loadCodeSections(elfPath, cs, string(license.data()));
663     if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d\n", ret);
664 
665     return ret;
666 }
667 
waitSecondsForProgsLoaded(int seconds)668 static 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 
waitForProgsLoaded()675 void waitForProgsLoaded() {
676     if (!android::bpf::isBpfSupported()) return;
677 
678     if (waitSecondsForProgsLoaded(5)) return;
679     if (waitSecondsForProgsLoaded(10)) return;
680     if (waitSecondsForProgsLoaded(20)) return;
681     while (!waitSecondsForProgsLoaded(60))
682         ;  // loop until success
683 }
684 
685 }  // namespace bpf
686 }  // namespace android
687