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 // This is BpfLoader v0.2 32 #define BPFLOADER_VERSION_MAJOR 0u 33 #define BPFLOADER_VERSION_MINOR 2u 34 #define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR) 35 36 #include "../progs/include/bpf_map_def.h" 37 #include "bpf/BpfUtils.h" 38 #include "include/libbpf_android.h" 39 40 #include <cstdlib> 41 #include <fstream> 42 #include <iostream> 43 #include <optional> 44 #include <string> 45 #include <vector> 46 47 #include <android-base/strings.h> 48 #include <android-base/unique_fd.h> 49 50 #define BPF_FS_PATH "/sys/fs/bpf/" 51 52 // Size of the BPF log buffer for verifier logging 53 #define BPF_LOAD_LOG_SZ 0x1ffff 54 55 using android::base::StartsWith; 56 using android::base::unique_fd; 57 using std::ifstream; 58 using std::ios; 59 using std::optional; 60 using std::string; 61 using std::vector; 62 63 namespace android { 64 namespace bpf { 65 66 static string pathToFilename(const string& path, bool noext = false) { 67 vector<string> spath = android::base::Split(path, "/"); 68 string ret = spath.back(); 69 70 if (noext) { 71 size_t lastindex = ret.find_last_of('.'); 72 return ret.substr(0, lastindex); 73 } 74 return ret; 75 } 76 77 typedef struct { 78 const char* name; 79 enum bpf_prog_type type; 80 } sectionType; 81 82 /* 83 * Map section name prefixes to program types, the section name will be: 84 * SEC(<prefix>/<name-of-program>) 85 * For example: 86 * SEC("tracepoint/sched_switch_func") where sched_switch_funcs 87 * is the name of the program, and tracepoint is the type. 88 */ 89 sectionType sectionNameTypes[] = { 90 {"kprobe", BPF_PROG_TYPE_KPROBE}, 91 {"tracepoint", BPF_PROG_TYPE_TRACEPOINT}, 92 {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER}, 93 {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB}, 94 {"schedcls", BPF_PROG_TYPE_SCHED_CLS}, 95 {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK}, 96 {"xdp", BPF_PROG_TYPE_XDP}, 97 98 /* End of table */ 99 {"END", BPF_PROG_TYPE_UNSPEC}, 100 }; 101 102 typedef struct { 103 enum bpf_prog_type type; 104 string name; 105 vector<char> data; 106 vector<char> rel_data; 107 optional<struct bpf_prog_def> prog_def; 108 109 unique_fd prog_fd; /* fd after loading */ 110 } codeSection; 111 112 static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) { 113 elfFile.seekg(0); 114 if (elfFile.fail()) return -1; 115 116 if (!elfFile.read((char*)eh, sizeof(*eh))) return -1; 117 118 return 0; 119 } 120 121 /* Reads all section header tables into an Shdr array */ 122 static int readSectionHeadersAll(ifstream& elfFile, vector<Elf64_Shdr>& shTable) { 123 Elf64_Ehdr eh; 124 int ret = 0; 125 126 ret = readElfHeader(elfFile, &eh); 127 if (ret) return ret; 128 129 elfFile.seekg(eh.e_shoff); 130 if (elfFile.fail()) return -1; 131 132 /* Read shdr table entries */ 133 shTable.resize(eh.e_shnum); 134 135 if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM; 136 137 return 0; 138 } 139 140 /* Read a section by its index - for ex to get sec hdr strtab blob */ 141 static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) { 142 vector<Elf64_Shdr> shTable; 143 int ret = readSectionHeadersAll(elfFile, shTable); 144 if (ret) return ret; 145 146 elfFile.seekg(shTable[id].sh_offset); 147 if (elfFile.fail()) return -1; 148 149 sec.resize(shTable[id].sh_size); 150 if (!elfFile.read(sec.data(), shTable[id].sh_size)) return -1; 151 152 return 0; 153 } 154 155 /* Read whole section header string table */ 156 static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) { 157 Elf64_Ehdr eh; 158 int ret = readElfHeader(elfFile, &eh); 159 if (ret) return ret; 160 161 ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab); 162 if (ret) return ret; 163 164 return 0; 165 } 166 167 /* Get name from offset in strtab */ 168 static int getSymName(ifstream& elfFile, int nameOff, string& name) { 169 int ret; 170 vector<char> secStrTab; 171 172 ret = readSectionHeaderStrtab(elfFile, secStrTab); 173 if (ret) return ret; 174 175 if (nameOff >= (int)secStrTab.size()) return -1; 176 177 name = string((char*)secStrTab.data() + nameOff); 178 return 0; 179 } 180 181 /* Reads a full section by name - example to get the GPL license */ 182 static int readSectionByName(const char* name, ifstream& elfFile, vector<char>& data) { 183 vector<char> secStrTab; 184 vector<Elf64_Shdr> shTable; 185 int ret; 186 187 ret = readSectionHeadersAll(elfFile, shTable); 188 if (ret) return ret; 189 190 ret = readSectionHeaderStrtab(elfFile, secStrTab); 191 if (ret) return ret; 192 193 for (int i = 0; i < (int)shTable.size(); i++) { 194 char* secname = secStrTab.data() + shTable[i].sh_name; 195 if (!secname) continue; 196 197 if (!strcmp(secname, name)) { 198 vector<char> dataTmp; 199 dataTmp.resize(shTable[i].sh_size); 200 201 elfFile.seekg(shTable[i].sh_offset); 202 if (elfFile.fail()) return -1; 203 204 if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1; 205 206 data = dataTmp; 207 return 0; 208 } 209 } 210 return -2; 211 } 212 213 unsigned int readSectionUint(const char* name, ifstream& elfFile, unsigned int defVal) { 214 vector<char> theBytes; 215 int ret = readSectionByName(name, elfFile, theBytes); 216 if (ret) { 217 ALOGD("Couldn't find section %s (defaulting to %u [0x%x]).\n", name, defVal, defVal); 218 return defVal; 219 } else if (theBytes.size() < sizeof(unsigned int)) { 220 ALOGE("Section %s too short (defaulting to %u [0x%x]).\n", name, defVal, defVal); 221 return defVal; 222 } else { 223 // decode first 4 bytes as LE32 uint, there will likely be more bytes due to alignment. 224 unsigned int value = static_cast<unsigned char>(theBytes[3]); 225 value <<= 8; 226 value += static_cast<unsigned char>(theBytes[2]); 227 value <<= 8; 228 value += static_cast<unsigned char>(theBytes[1]); 229 value <<= 8; 230 value += static_cast<unsigned char>(theBytes[0]); 231 ALOGI("Section %s value is %u [0x%x]\n", name, value, value); 232 return value; 233 } 234 } 235 236 static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) { 237 int ret; 238 vector<Elf64_Shdr> shTable; 239 240 ret = readSectionHeadersAll(elfFile, shTable); 241 if (ret) return ret; 242 243 for (int i = 0; i < (int)shTable.size(); i++) { 244 if ((int)shTable[i].sh_type != type) continue; 245 246 vector<char> dataTmp; 247 dataTmp.resize(shTable[i].sh_size); 248 249 elfFile.seekg(shTable[i].sh_offset); 250 if (elfFile.fail()) return -1; 251 252 if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1; 253 254 data = dataTmp; 255 return 0; 256 } 257 return -2; 258 } 259 260 static bool symCompare(Elf64_Sym a, Elf64_Sym b) { 261 return (a.st_value < b.st_value); 262 } 263 264 static int readSymTab(ifstream& elfFile, int sort, vector<Elf64_Sym>& data) { 265 int ret, numElems; 266 Elf64_Sym* buf; 267 vector<char> secData; 268 269 ret = readSectionByType(elfFile, SHT_SYMTAB, secData); 270 if (ret) return ret; 271 272 buf = (Elf64_Sym*)secData.data(); 273 numElems = (secData.size() / sizeof(Elf64_Sym)); 274 data.assign(buf, buf + numElems); 275 276 if (sort) std::sort(data.begin(), data.end(), symCompare); 277 return 0; 278 } 279 280 static enum bpf_prog_type getSectionType(string& name) { 281 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++) 282 if (StartsWith(name, sectionNameTypes[i].name)) return sectionNameTypes[i].type; 283 284 return BPF_PROG_TYPE_UNSPEC; 285 } 286 287 /* If ever needed 288 static string getSectionName(enum bpf_prog_type type) 289 { 290 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++) 291 if (sectionNameTypes[i].type == type) 292 return string(sectionNameTypes[i].name); 293 294 return NULL; 295 } 296 */ 297 298 static bool isRelSection(codeSection& cs, string& name) { 299 for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++) { 300 sectionType st = sectionNameTypes[i]; 301 302 if (st.type != cs.type) continue; 303 304 if (StartsWith(name, string(".rel") + st.name + "/")) 305 return true; 306 else 307 return false; 308 } 309 return false; 310 } 311 312 static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd, 313 size_t sizeOfBpfProgDef) { 314 vector<char> pdData; 315 int ret = readSectionByName("progs", elfFile, pdData); 316 // Older file formats do not require a 'progs' section at all. 317 // (We should probably figure out whether this is behaviour which is safe to remove now.) 318 if (ret == -2) return 0; 319 if (ret) return ret; 320 321 if (pdData.size() % sizeOfBpfProgDef) { 322 ALOGE("readProgDefs failed due to improper sized progs section, %zu %% %zu != 0\n", 323 pdData.size(), sizeOfBpfProgDef); 324 return -1; 325 }; 326 327 int progCount = pdData.size() / sizeOfBpfProgDef; 328 pd.resize(progCount); 329 size_t trimmedSize = std::min(sizeOfBpfProgDef, sizeof(struct bpf_prog_def)); 330 331 const char* dataPtr = pdData.data(); 332 for (auto& p : pd) { 333 // First we zero initialize 334 memset(&p, 0, sizeof(p)); 335 // Then we set non-zero defaults 336 p.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER; // v1.0 337 // Then we copy over the structure prefix from the ELF file. 338 memcpy(&p, dataPtr, trimmedSize); 339 // Move to next struct in the ELF file 340 dataPtr += sizeOfBpfProgDef; 341 } 342 return 0; 343 } 344 345 static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names) { 346 int ret; 347 string name; 348 vector<Elf64_Sym> symtab; 349 vector<Elf64_Shdr> shTable; 350 351 ret = readSymTab(elfFile, 1 /* sort */, symtab); 352 if (ret) return ret; 353 354 /* Get index of section */ 355 ret = readSectionHeadersAll(elfFile, shTable); 356 if (ret) return ret; 357 358 int sec_idx = -1; 359 for (int i = 0; i < (int)shTable.size(); i++) { 360 ret = getSymName(elfFile, shTable[i].sh_name, name); 361 if (ret) return ret; 362 363 if (!name.compare(sectionName)) { 364 sec_idx = i; 365 break; 366 } 367 } 368 369 /* No section found with matching name*/ 370 if (sec_idx == -1) { 371 ALOGW("No %s section could be found in elf object\n", sectionName.c_str()); 372 return -1; 373 } 374 375 for (int i = 0; i < (int)symtab.size(); i++) { 376 if (symtab[i].st_shndx == sec_idx) { 377 string s; 378 ret = getSymName(elfFile, symtab[i].st_name, s); 379 if (ret) return ret; 380 names.push_back(s); 381 } 382 } 383 384 return 0; 385 } 386 387 /* Read a section by its index - for ex to get sec hdr strtab blob */ 388 static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs, size_t sizeOfBpfProgDef) { 389 vector<Elf64_Shdr> shTable; 390 int entries, ret = 0; 391 392 ret = readSectionHeadersAll(elfFile, shTable); 393 if (ret) return ret; 394 entries = shTable.size(); 395 396 vector<struct bpf_prog_def> pd; 397 ret = readProgDefs(elfFile, pd, sizeOfBpfProgDef); 398 if (ret) return ret; 399 vector<string> progDefNames; 400 ret = getSectionSymNames(elfFile, "progs", progDefNames); 401 if (!pd.empty() && ret) return ret; 402 403 for (int i = 0; i < entries; i++) { 404 string name; 405 codeSection cs_temp; 406 cs_temp.type = BPF_PROG_TYPE_UNSPEC; 407 408 ret = getSymName(elfFile, shTable[i].sh_name, name); 409 if (ret) return ret; 410 411 enum bpf_prog_type ptype = getSectionType(name); 412 if (ptype != BPF_PROG_TYPE_UNSPEC) { 413 string oldName = name; 414 415 // convert all slashes to underscores 416 std::replace(name.begin(), name.end(), '/', '_'); 417 418 cs_temp.type = ptype; 419 cs_temp.name = name; 420 421 ret = readSectionByIdx(elfFile, i, cs_temp.data); 422 if (ret) return ret; 423 ALOGD("Loaded code section %d (%s)\n", i, name.c_str()); 424 425 vector<string> csSymNames; 426 ret = getSectionSymNames(elfFile, oldName, csSymNames); 427 if (ret || !csSymNames.size()) return ret; 428 for (size_t i = 0; i < progDefNames.size(); ++i) { 429 if (!progDefNames[i].compare(csSymNames[0] + "_def")) { 430 cs_temp.prog_def = pd[i]; 431 break; 432 } 433 } 434 } 435 436 /* Check for rel section */ 437 if (cs_temp.data.size() > 0 && i < entries) { 438 ret = getSymName(elfFile, shTable[i + 1].sh_name, name); 439 if (ret) return ret; 440 441 if (isRelSection(cs_temp, name)) { 442 ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data); 443 if (ret) return ret; 444 ALOGD("Loaded relo section %d (%s)\n", i, name.c_str()); 445 } 446 } 447 448 if (cs_temp.data.size() > 0) { 449 cs.push_back(std::move(cs_temp)); 450 ALOGD("Adding section %d to cs list\n", i); 451 } 452 } 453 return 0; 454 } 455 456 static int getSymNameByIdx(ifstream& elfFile, int index, string& name) { 457 vector<Elf64_Sym> symtab; 458 int ret = 0; 459 460 ret = readSymTab(elfFile, 0 /* !sort */, symtab); 461 if (ret) return ret; 462 463 if (index >= (int)symtab.size()) return -1; 464 465 return getSymName(elfFile, symtab[index].st_name, name); 466 } 467 468 static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds, 469 const char* prefix, size_t sizeOfBpfMapDef) { 470 int ret; 471 vector<char> mdData; 472 vector<struct bpf_map_def> md; 473 vector<string> mapNames; 474 string fname = pathToFilename(string(elfPath), true); 475 476 ret = readSectionByName("maps", elfFile, mdData); 477 if (ret == -2) return 0; // no maps to read 478 if (ret) return ret; 479 480 if (mdData.size() % sizeOfBpfMapDef) { 481 ALOGE("createMaps failed due to improper sized maps section, %zu %% %zu != 0\n", 482 mdData.size(), sizeOfBpfMapDef); 483 return -1; 484 }; 485 486 int mapCount = mdData.size() / sizeOfBpfMapDef; 487 md.resize(mapCount); 488 size_t trimmedSize = std::min(sizeOfBpfMapDef, sizeof(struct bpf_map_def)); 489 490 const char* dataPtr = mdData.data(); 491 for (auto& m : md) { 492 // First we zero initialize 493 memset(&m, 0, sizeof(m)); 494 // Then we set non-zero defaults 495 m.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER; // v1.0 496 m.max_kver = 0xFFFFFFFFu; // matches KVER_INF from bpf_helpers.h 497 // Then we copy over the structure prefix from the ELF file. 498 memcpy(&m, dataPtr, trimmedSize); 499 // Move to next struct in the ELF file 500 dataPtr += sizeOfBpfMapDef; 501 } 502 503 ret = getSectionSymNames(elfFile, "maps", mapNames); 504 if (ret) return ret; 505 506 unsigned kvers = kernelVersion(); 507 508 for (int i = 0; i < (int)mapNames.size(); i++) { 509 if (BPFLOADER_VERSION < md[i].bpfloader_min_ver) { 510 ALOGI("skipping map %s which requires bpfloader min ver 0x%05x\n", mapNames[i].c_str(), 511 md[i].bpfloader_min_ver); 512 mapFds.push_back(unique_fd()); 513 continue; 514 } 515 516 if (BPFLOADER_VERSION >= md[i].bpfloader_max_ver) { 517 ALOGI("skipping map %s which requires bpfloader max ver 0x%05x\n", mapNames[i].c_str(), 518 md[i].bpfloader_max_ver); 519 mapFds.push_back(unique_fd()); 520 continue; 521 } 522 523 if (kvers < md[i].min_kver) { 524 ALOGI("skipping map %s which requires kernel version 0x%x >= 0x%x\n", 525 mapNames[i].c_str(), kvers, md[i].min_kver); 526 mapFds.push_back(unique_fd()); 527 continue; 528 } 529 530 if (kvers >= md[i].max_kver) { 531 ALOGI("skipping map %s which requires kernel version 0x%x < 0x%x\n", 532 mapNames[i].c_str(), kvers, md[i].max_kver); 533 mapFds.push_back(unique_fd()); 534 continue; 535 } 536 537 // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname> 538 string mapPinLoc = 539 string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]); 540 bool reuse = false; 541 unique_fd fd; 542 int saved_errno; 543 544 if (access(mapPinLoc.c_str(), F_OK) == 0) { 545 fd.reset(bpf_obj_get(mapPinLoc.c_str())); 546 saved_errno = errno; 547 ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get()); 548 reuse = true; 549 } else { 550 enum bpf_map_type type = md[i].type; 551 if (type == BPF_MAP_TYPE_DEVMAP && !isAtLeastKernelVersion(4, 14, 0)) { 552 // On Linux Kernels older than 4.14 this map type doesn't exist, but it can kind 553 // of be approximated: ARRAY has the same userspace api, though it is not usable 554 // by the same ebpf programs. However, that's okay because the bpf_redirect_map() 555 // helper doesn't exist on 4.9 anyway (so the bpf program would fail to load, 556 // and thus needs to be tagged as 4.14+ either way), so there's nothing useful you 557 // could do with a DEVMAP anyway (that isn't already provided by an ARRAY)... 558 // Hence using an ARRAY instead of a DEVMAP simply makes life easier for userspace. 559 type = BPF_MAP_TYPE_ARRAY; 560 } 561 if (type == BPF_MAP_TYPE_DEVMAP_HASH && !isAtLeastKernelVersion(5, 4, 0)) { 562 // On Linux Kernels older than 5.4 this map type doesn't exist, but it can kind 563 // of be approximated: HASH has the same userspace visible api. 564 // However it cannot be used by ebpf programs in the same way. 565 // Since bpf_redirect_map() only requires 4.14, a program using a DEVMAP_HASH map 566 // would fail to load (due to trying to redirect to a HASH instead of DEVMAP_HASH). 567 // One must thus tag any BPF_MAP_TYPE_DEVMAP_HASH + bpf_redirect_map() using 568 // programs as being 5.4+... 569 type = BPF_MAP_TYPE_HASH; 570 } 571 fd.reset(bpf_create_map(type, mapNames[i].c_str(), md[i].key_size, md[i].value_size, 572 md[i].max_entries, md[i].map_flags)); 573 saved_errno = errno; 574 ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get()); 575 } 576 577 if (fd < 0) return -saved_errno; 578 579 if (!reuse) { 580 ret = bpf_obj_pin(fd, mapPinLoc.c_str()); 581 if (ret) return -errno; 582 ret = chown(mapPinLoc.c_str(), (uid_t)md[i].uid, (gid_t)md[i].gid); 583 if (ret) return -errno; 584 ret = chmod(mapPinLoc.c_str(), md[i].mode); 585 if (ret) return -errno; 586 } 587 588 mapFds.push_back(std::move(fd)); 589 } 590 591 return ret; 592 } 593 594 /* For debugging, dump all instructions */ 595 static void dumpIns(char* ins, int size) { 596 for (int row = 0; row < size / 8; row++) { 597 ALOGE("%d: ", row); 598 for (int j = 0; j < 8; j++) { 599 ALOGE("%3x ", ins[(row * 8) + j]); 600 } 601 ALOGE("\n"); 602 } 603 } 604 605 /* For debugging, dump all code sections from cs list */ 606 static void dumpAllCs(vector<codeSection>& cs) { 607 for (int i = 0; i < (int)cs.size(); i++) { 608 ALOGE("Dumping cs %d, name %s\n", int(i), cs[i].name.c_str()); 609 dumpIns((char*)cs[i].data.data(), cs[i].data.size()); 610 ALOGE("-----------\n"); 611 } 612 } 613 614 static void applyRelo(void* insnsPtr, Elf64_Addr offset, int fd) { 615 int insnIndex; 616 struct bpf_insn *insn, *insns; 617 618 insns = (struct bpf_insn*)(insnsPtr); 619 620 insnIndex = offset / sizeof(struct bpf_insn); 621 insn = &insns[insnIndex]; 622 623 ALOGD( 624 "applying relo to instruction at byte offset: %d, \ 625 insn offset %d , insn %lx\n", 626 (int)offset, (int)insnIndex, *(unsigned long*)insn); 627 628 if (insn->code != (BPF_LD | BPF_IMM | BPF_DW)) { 629 ALOGE("Dumping all instructions till ins %d\n", insnIndex); 630 ALOGE("invalid relo for insn %d: code 0x%x\n", insnIndex, insn->code); 631 dumpIns((char*)insnsPtr, (insnIndex + 3) * 8); 632 return; 633 } 634 635 insn->imm = fd; 636 insn->src_reg = BPF_PSEUDO_MAP_FD; 637 } 638 639 static void applyMapRelo(ifstream& elfFile, vector<unique_fd> &mapFds, vector<codeSection>& cs) { 640 vector<string> mapNames; 641 642 int ret = getSectionSymNames(elfFile, "maps", mapNames); 643 if (ret) return; 644 645 for (int k = 0; k != (int)cs.size(); k++) { 646 Elf64_Rel* rel = (Elf64_Rel*)(cs[k].rel_data.data()); 647 int n_rel = cs[k].rel_data.size() / sizeof(*rel); 648 649 for (int i = 0; i < n_rel; i++) { 650 int symIndex = ELF64_R_SYM(rel[i].r_info); 651 string symName; 652 653 ret = getSymNameByIdx(elfFile, symIndex, symName); 654 if (ret) return; 655 656 /* Find the map fd and apply relo */ 657 for (int j = 0; j < (int)mapNames.size(); j++) { 658 if (!mapNames[j].compare(symName)) { 659 applyRelo(cs[k].data.data(), rel[i].r_offset, mapFds[j]); 660 break; 661 } 662 } 663 } 664 } 665 } 666 667 static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license, 668 const char* prefix) { 669 unsigned kvers = kernelVersion(); 670 int ret, fd; 671 672 if (!kvers) return -1; 673 674 string fname = pathToFilename(string(elfPath), true); 675 676 for (int i = 0; i < (int)cs.size(); i++) { 677 string name = cs[i].name; 678 unsigned bpfMinVer = DEFAULT_BPFLOADER_MIN_VER; // v0.0 679 unsigned bpfMaxVer = DEFAULT_BPFLOADER_MAX_VER; // v1.0 680 681 if (cs[i].prog_def.has_value()) { 682 unsigned min_kver = cs[i].prog_def->min_kver; 683 unsigned max_kver = cs[i].prog_def->max_kver; 684 ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)\n", i, name.c_str(), min_kver, 685 max_kver, kvers); 686 if (kvers < min_kver) continue; 687 if (kvers >= max_kver) continue; 688 689 bpfMinVer = cs[i].prog_def->bpfloader_min_ver; 690 bpfMaxVer = cs[i].prog_def->bpfloader_max_ver; 691 } 692 693 ALOGD("cs[%d].name:%s requires bpfloader version [0x%05x,0x%05x)\n", i, name.c_str(), 694 bpfMinVer, bpfMaxVer); 695 if (BPFLOADER_VERSION < bpfMinVer) continue; 696 if (BPFLOADER_VERSION >= bpfMaxVer) continue; 697 698 // strip any potential $foo suffix 699 // this can be used to provide duplicate programs 700 // conditionally loaded based on running kernel version 701 name = name.substr(0, name.find_last_of('$')); 702 703 bool reuse = false; 704 // Format of pin location is 705 // /sys/fs/bpf/<prefix>prog_<filename>_<mapname> 706 string progPinLoc = BPF_FS_PATH; 707 progPinLoc += prefix; 708 progPinLoc += "prog_"; 709 progPinLoc += fname; 710 progPinLoc += '_'; 711 progPinLoc += name; 712 if (access(progPinLoc.c_str(), F_OK) == 0) { 713 fd = retrieveProgram(progPinLoc.c_str()); 714 ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)\n", progPinLoc.c_str(), fd, 715 (fd < 0 ? std::strerror(errno) : "no error")); 716 reuse = true; 717 } else { 718 vector<char> log_buf(BPF_LOAD_LOG_SZ, 0); 719 720 fd = bpf_prog_load(cs[i].type, name.c_str(), (struct bpf_insn*)cs[i].data.data(), 721 cs[i].data.size(), license.c_str(), kvers, 0, log_buf.data(), 722 log_buf.size()); 723 ALOGD("bpf_prog_load lib call for %s (%s) returned fd: %d (%s)\n", elfPath, 724 cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error")); 725 726 if (fd < 0) { 727 vector<string> lines = android::base::Split(log_buf.data(), "\n"); 728 729 ALOGW("bpf_prog_load - BEGIN log_buf contents:"); 730 for (const auto& line : lines) ALOGW("%s", line.c_str()); 731 ALOGW("bpf_prog_load - END log_buf contents."); 732 733 if (cs[i].prog_def->optional) { 734 ALOGW("failed program is marked optional - continuing..."); 735 continue; 736 } 737 ALOGE("non-optional program failed to load."); 738 } 739 } 740 741 if (fd < 0) return fd; 742 if (fd == 0) return -EINVAL; 743 744 if (!reuse) { 745 ret = bpf_obj_pin(fd, progPinLoc.c_str()); 746 if (ret) return -errno; 747 if (cs[i].prog_def.has_value()) { 748 if (chown(progPinLoc.c_str(), (uid_t)cs[i].prog_def->uid, 749 (gid_t)cs[i].prog_def->gid)) { 750 return -errno; 751 } 752 } 753 if (chmod(progPinLoc.c_str(), 0440)) return -errno; 754 } 755 756 cs[i].prog_fd.reset(fd); 757 } 758 759 return 0; 760 } 761 762 int loadProg(const char* elfPath, bool* isCritical, const char* prefix) { 763 vector<char> license; 764 vector<char> critical; 765 vector<codeSection> cs; 766 vector<unique_fd> mapFds; 767 int ret; 768 769 if (!isCritical) return -1; 770 *isCritical = false; 771 772 ifstream elfFile(elfPath, ios::in | ios::binary); 773 if (!elfFile.is_open()) return -1; 774 775 ret = readSectionByName("critical", elfFile, critical); 776 *isCritical = !ret; 777 778 ret = readSectionByName("license", elfFile, license); 779 if (ret) { 780 ALOGE("Couldn't find license in %s\n", elfPath); 781 return ret; 782 } else { 783 ALOGD("Loading %s%s ELF object %s with license %s\n", 784 *isCritical ? "critical for " : "optional", *isCritical ? (char*)critical.data() : "", 785 elfPath, (char*)license.data()); 786 } 787 788 // the following default values are for bpfloader V0.0 format which does not include them 789 unsigned int bpfLoaderMinVer = 790 readSectionUint("bpfloader_min_ver", elfFile, DEFAULT_BPFLOADER_MIN_VER); 791 unsigned int bpfLoaderMaxVer = 792 readSectionUint("bpfloader_max_ver", elfFile, DEFAULT_BPFLOADER_MAX_VER); 793 size_t sizeOfBpfMapDef = 794 readSectionUint("size_of_bpf_map_def", elfFile, DEFAULT_SIZEOF_BPF_MAP_DEF); 795 size_t sizeOfBpfProgDef = 796 readSectionUint("size_of_bpf_prog_def", elfFile, DEFAULT_SIZEOF_BPF_PROG_DEF); 797 798 // inclusive lower bound check 799 if (BPFLOADER_VERSION < bpfLoaderMinVer) { 800 ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with min ver 0x%05x\n", 801 BPFLOADER_VERSION, elfPath, bpfLoaderMinVer); 802 return 0; 803 } 804 805 // exclusive upper bound check 806 if (BPFLOADER_VERSION >= bpfLoaderMaxVer) { 807 ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with max ver 0x%05x\n", 808 BPFLOADER_VERSION, elfPath, bpfLoaderMaxVer); 809 return 0; 810 } 811 812 ALOGI("BpfLoader version 0x%05x processing ELF object %s with ver [0x%05x,0x%05x)\n", 813 BPFLOADER_VERSION, elfPath, bpfLoaderMinVer, bpfLoaderMaxVer); 814 815 if (sizeOfBpfMapDef < DEFAULT_SIZEOF_BPF_MAP_DEF) { 816 ALOGE("sizeof(bpf_map_def) of %zu is too small (< %d)\n", sizeOfBpfMapDef, 817 DEFAULT_SIZEOF_BPF_MAP_DEF); 818 return -1; 819 } 820 821 if (sizeOfBpfProgDef < DEFAULT_SIZEOF_BPF_PROG_DEF) { 822 ALOGE("sizeof(bpf_prog_def) of %zu is too small (< %d)\n", sizeOfBpfProgDef, 823 DEFAULT_SIZEOF_BPF_PROG_DEF); 824 return -1; 825 } 826 827 ret = readCodeSections(elfFile, cs, sizeOfBpfProgDef); 828 if (ret) { 829 ALOGE("Couldn't read all code sections in %s\n", elfPath); 830 return ret; 831 } 832 833 /* Just for future debugging */ 834 if (0) dumpAllCs(cs); 835 836 ret = createMaps(elfPath, elfFile, mapFds, prefix, sizeOfBpfMapDef); 837 if (ret) { 838 ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath); 839 return ret; 840 } 841 842 for (int i = 0; i < (int)mapFds.size(); i++) 843 ALOGD("map_fd found at %d is %d in %s\n", i, mapFds[i].get(), elfPath); 844 845 applyMapRelo(elfFile, mapFds, cs); 846 847 ret = loadCodeSections(elfPath, cs, string(license.data()), prefix); 848 if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d\n", ret); 849 850 return ret; 851 } 852 853 } // namespace bpf 854 } // namespace android 855