From 8b3ea0a2747e19378a2f0663682ee141f6b6acce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 15 Jul 2025 23:14:37 -0700 Subject: [PATCH 01/13] simplify libbpf_android.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Flag: EXEMPT trivial Signed-off-by: Maciej Żenczykowski Change-Id: I39f73afef65b22b1d275742758aff7745991d9e7 --- loader/Loader.cpp | 7 +++++++ loader/include/libbpf_android.h | 35 ++------------------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index af684c5..f0c00b5 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -817,6 +817,13 @@ static int loadCodeSections(const char* elfPath, vector& cs, const return 0; } +struct Location { + const char* const dir = ""; + const char* const prefix = ""; + const bpf_prog_type* allowedProgTypes = nullptr; + size_t allowedProgTypesLength = 0; +}; + int loadProg(const char* elfPath, bool* isCritical, const Location& location) { vector license; vector critical; diff --git a/loader/include/libbpf_android.h b/loader/include/libbpf_android.h index 9fb30b5..706c0e8 100644 --- a/loader/include/libbpf_android.h +++ b/loader/include/libbpf_android.h @@ -17,39 +17,8 @@ #pragma once -#ifdef __cplusplus - -#include - -#include - -namespace android { -namespace bpf { - -struct Location { - const char* const dir = ""; - const char* const prefix = ""; - const bpf_prog_type* allowedProgTypes = nullptr; - size_t allowedProgTypesLength = 0; -}; - -// BPF loader implementation. Loads an eBPF ELF object -int loadProg(const char* elfPath, bool* isCritical, const Location &location = {}); - -// Exposed for testing -unsigned int readSectionUint(const char* name, std::ifstream& elfFile, unsigned int defVal); - -} // namespace bpf -} // namespace android - -extern "C" { -#else // __cplusplus -#define __noreturn -#endif // __cplusplus - // The C++ portion of the BpfLoader is exposed as a terminal function. -__noreturn void vendorBpfLoader(); - #ifdef __cplusplus -} // extern C +extern "C" __noreturn #endif +void vendorBpfLoader(); From 0e2f1cc28bf5a5d05be92b7356e7072fa5ea2fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 15 Jul 2025 23:25:58 -0700 Subject: [PATCH 02/13] vendorBpfLoader: no need for allowedProgTypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (while at it remove fuse bpf support, which isn't needed for vendor) Test: TreeHugger Flag: EXEMPT no-op Signed-off-by: Maciej Żenczykowski Change-Id: Ic7293b94644d933a908a252ab794ae64f88b5865 --- loader/Loader.cpp | 64 ++++++----------------------------------------- 1 file changed, 7 insertions(+), 57 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index f0c00b5..2606545 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -95,15 +95,14 @@ typedef struct { * * However, be aware that you should not be directly using the SECTION() macro. * Instead use the DEFINE_(BPF|XDP)_(PROG|MAP)... & LICENSE/CRITICAL macros. + * + * see b/162057235. For arbitrary program types, the concern is that due to the lack of + * SELinux access controls over BPF program attachpoints, we have no way to control the + * attachment of programs to shared resources (or to detect when a shared resource + * has one BPF program replace another that is attached there) */ sectionType sectionNameTypes[] = { - {"kprobe/", BPF_PROG_TYPE_KPROBE}, - {"kretprobe/", BPF_PROG_TYPE_KPROBE}, - {"perf_event/", BPF_PROG_TYPE_PERF_EVENT}, {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER}, - {"tracepoint/", BPF_PROG_TYPE_TRACEPOINT}, - {"uprobe/", BPF_PROG_TYPE_KPROBE}, - {"uretprobe/", BPF_PROG_TYPE_KPROBE}, }; typedef struct { @@ -284,31 +283,13 @@ static int readSymTab(ifstream& elfFile, int sort, vector& data) { return 0; } -static enum bpf_prog_type getFuseProgType() { - int result = BPF_PROG_TYPE_UNSPEC; - ifstream("/sys/fs/fuse/bpf_prog_type_fuse") >> result; - return static_cast(result); -} - static enum bpf_prog_type getSectionType(string& name) { for (auto& snt : sectionNameTypes) if (StartsWith(name, snt.name)) return snt.type; - // TODO Remove this code when fuse-bpf is upstream and this BPF_PROG_TYPE_FUSE is fixed - if (StartsWith(name, "fuse/")) return getFuseProgType(); - return BPF_PROG_TYPE_UNSPEC; } -static string getSectionName(enum bpf_prog_type type) -{ - for (auto& snt : sectionNameTypes) - if (snt.type == type) - return string(snt.name); - - return "UNKNOWN SECTION NAME " + std::to_string(type); -} - static int readProgDefs(ifstream& elfFile, vector& pd) { vector pdData; int ret = readSectionByName("progs", elfFile, pdData); @@ -370,22 +351,8 @@ static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vect return 0; } -static bool IsAllowed(bpf_prog_type type, const bpf_prog_type* allowed, size_t numAllowed) { - if (allowed == nullptr) return true; - - for (size_t i = 0; i < numAllowed; i++) { - if (allowed[i] == BPF_PROG_TYPE_UNSPEC) { - if (type == getFuseProgType()) return true; - } else if (type == allowed[i]) - return true; - } - - return false; -} - /* Read a section by its index - for ex to get sec hdr strtab blob */ -static int readCodeSections(ifstream& elfFile, vector& cs, - const bpf_prog_type* allowed, size_t numAllowed) { +static int readCodeSections(ifstream& elfFile, vector& cs) { vector shTable; int entries, ret = 0; @@ -412,11 +379,6 @@ static int readCodeSections(ifstream& elfFile, vector& cs, if (ptype == BPF_PROG_TYPE_UNSPEC) continue; - if (!IsAllowed(ptype, allowed, numAllowed)) { - ALOGE("Program type %s not permitted here", getSectionName(ptype).c_str()); - return -1; - } - string oldName = name; // convert all slashes to underscores @@ -820,8 +782,6 @@ static int loadCodeSections(const char* elfPath, vector& cs, const struct Location { const char* const dir = ""; const char* const prefix = ""; - const bpf_prog_type* allowedProgTypes = nullptr; - size_t allowedProgTypesLength = 0; }; int loadProg(const char* elfPath, bool* isCritical, const Location& location) { @@ -850,7 +810,7 @@ int loadProg(const char* elfPath, bool* isCritical, const Location& location) { *isCritical ? "critical for " : "optional", *isCritical ? (char*)critical.data() : "", elfPath, (char*)license.data()); - ret = readCodeSections(elfFile, cs, location.allowedProgTypes, location.allowedProgTypesLength); + ret = readCodeSections(elfFile, cs); if (ret) { ALOGE("Couldn't read all code sections in %s", elfPath); return ret; @@ -873,21 +833,11 @@ int loadProg(const char* elfPath, bool* isCritical, const Location& location) { return ret; } -// see b/162057235. For arbitrary program types, the concern is that due to the lack of -// SELinux access controls over BPF program attachpoints, we have no way to control the -// attachment of programs to shared resources (or to detect when a shared resource -// has one BPF program replace another that is attached there) -constexpr bpf_prog_type kVendorAllowedProgTypes[] = { - BPF_PROG_TYPE_SOCKET_FILTER, -}; - const Location locations[] = { // Vendor operating system { .dir = "/vendor/etc/bpf/", .prefix = "vendor/", - .allowedProgTypes = kVendorAllowedProgTypes, - .allowedProgTypesLength = arraysize(kVendorAllowedProgTypes), }, }; From c30b4f8beeecc9ad30e3b584553adfef2a3b3cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 15 Jul 2025 23:37:11 -0700 Subject: [PATCH 03/13] vendorBpfLoader: no need for locations array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Afterwards we still have: I BpfLoader: Platform BpfLoader loading critical for healthd ELF object /vendor/etc/bpf/filterPowerSupplyEvents.o with license Apache 2.0 W BpfLoader: No maps section could be found in elf object D BpfLoader: prog /sys/fs/bpf/vendor/prog_filterPowerSupplyEvents_skfilter_power_supply id 82 $ adbz shell ls -lZ /sys/fs/bpf /sys/fs/bpf/vendor /sys/fs/bpf: total 0 ... drwxrwxrwt 2 root root u:object_r:fs_bpf_vendor:s0 0 2025-07-15 23:53 vendor /sys/fs/bpf/vendor: total 0 -r--r----- 1 root system u:object_r:fs_bpf_vendor:s0 0 2025-07-15 23:53 prog_filterPowerSupplyEvents_skfilter_power_supply Test: TreeHugger Flag: EXEMPT no-op Signed-off-by: Maciej Żenczykowski Change-Id: I66a6fc3abf8f5c4c52f6a47476c251e97f1f6e14 --- loader/Loader.cpp | 89 ++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index 2606545..be12a6f 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -51,8 +51,6 @@ #include #include -#define BPF_FS_PATH "/sys/fs/bpf/" - // Size of the BPF log buffer for verifier logging #define BPF_LOAD_LOG_SZ 0xfffff @@ -481,8 +479,7 @@ static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, return false; } -static int createMaps(const char* elfPath, ifstream& elfFile, vector& mapFds, - const char* prefix) { +static int createMaps(const char* elfPath, ifstream& elfFile, vector& mapFds) { int ret; vector mdData; vector md; @@ -546,7 +543,7 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector& // Format of pin location is /sys/fs/bpf/map__ // except that maps shared across .o's have empty // Note: refers to the extension-less basename of the .o file (without @ suffix). - string mapPinLoc = string(BPF_FS_PATH) + prefix + "map_" + + string mapPinLoc = string("/sys/fs/bpf/vendor/map_") + (md[i].shared ? "" : objName) + "_" + mapNames[i]; bool reuse = false; unique_fd fd; @@ -667,8 +664,7 @@ static void applyMapRelo(ifstream& elfFile, vector &mapFds, vector& cs, const string& license, - const char* prefix) { +static int loadCodeSections(const char* elfPath, vector& cs, const string& license) { unsigned kvers = kernelVersion(); if (!kvers) { @@ -704,8 +700,7 @@ static int loadCodeSections(const char* elfPath, vector& cs, const bool reuse = false; // Format of pin location is // /sys/fs/bpf/prog__ - string progPinLoc = string(BPF_FS_PATH) + prefix + "prog_" + - objName + '_' + string(name); + string progPinLoc = string("/sys/fs/bpf/vendor/prog_") + objName + '_' + name; if (access(progPinLoc.c_str(), F_OK) == 0) { fd.reset(retrieveProgram(progPinLoc.c_str())); ALOGV("New bpf prog load reusing prog %s, ret: %d (%s)", progPinLoc.c_str(), fd.get(), @@ -779,12 +774,7 @@ static int loadCodeSections(const char* elfPath, vector& cs, const return 0; } -struct Location { - const char* const dir = ""; - const char* const prefix = ""; -}; - -int loadProg(const char* elfPath, bool* isCritical, const Location& location) { +int loadProg(const char* elfPath, bool* isCritical) { vector license; vector critical; vector cs; @@ -816,7 +806,7 @@ int loadProg(const char* elfPath, bool* isCritical, const Location& location) { return ret; } - ret = createMaps(elfPath, elfFile, mapFds, location.prefix); + ret = createMaps(elfPath, elfFile, mapFds); if (ret) { ALOGE("Failed to create maps: (ret=%d) in %s", ret, elfPath); return ret; @@ -827,35 +817,27 @@ int loadProg(const char* elfPath, bool* isCritical, const Location& location) { applyMapRelo(elfFile, mapFds, cs); - ret = loadCodeSections(elfPath, cs, string(license.data()), location.prefix); + ret = loadCodeSections(elfPath, cs, string(license.data())); if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d", ret); return ret; } -const Location locations[] = { - // Vendor operating system - { - .dir = "/vendor/etc/bpf/", - .prefix = "vendor/", - }, -}; - -int loadAllElfObjects(const Location& location) { +int loadAllElfObjects() { int retVal = 0; DIR* dir; struct dirent* ent; - if ((dir = opendir(location.dir)) != NULL) { + if ((dir = opendir("/vendor/etc/bpf/")) != NULL) { while ((ent = readdir(dir)) != NULL) { string s = ent->d_name; if (!EndsWith(s, ".o")) continue; - string progPath(location.dir); + string progPath("/vendor/etc/bpf/"); progPath += s; bool critical; - int ret = loadProg(progPath.c_str(), &critical, location); + int ret = loadProg(progPath.c_str(), &critical); if (ret) { if (critical) retVal = ret; ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), strerror(-ret)); @@ -868,23 +850,18 @@ int loadAllElfObjects(const Location& location) { return retVal; } -int createSysFsBpfSubDir(const char* const prefix) { - if (*prefix) { - mode_t prevUmask = umask(0); +int createSysFsBpfVendor() { + mode_t prevUmask = umask(0); - string s = "/sys/fs/bpf/"; - s += prefix; - - errno = 0; - int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO); - if (ret && errno != EEXIST) { - const int err = errno; - ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), strerror(err)); - return -err; - } - - umask(prevUmask); + errno = 0; + int ret = mkdir("/sys/fs/bpf/vendor", S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO); + if (ret && errno != EEXIST) { + const int err = errno; + ALOGE("Failed to create directory: /sys/fs/bpf/vendor, ret: %s", strerror(err)); + return -err; } + + umask(prevUmask); return 0; } @@ -900,23 +877,17 @@ void vendorBpfLoader() { const char* argv[] = {"/system/bin/bpfloader", NULL}; android::base::InitLogging(const_cast(argv), &android::base::KernelLogger); - for (const auto& location : android::bpf::locations) { - if (android::bpf::createSysFsBpfSubDir(location.prefix)) { - exit(120); - } - } + if (android::bpf::createSysFsBpfVendor()) exit(120); // Load all ELF objects, create programs and maps, and pin them - for (const auto& location : android::bpf::locations) { - if (android::bpf::loadAllElfObjects(location)) { - ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir); - ALOGE("If this triggers reliably, you're probably missing kernel options or patches."); - ALOGE("If this triggers randomly, you might be hitting some memory allocation " - "problems or startup script race."); - ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---"); - sleep(20); - exit(121); - } + if (android::bpf::loadAllElfObjects()) { + ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM /vendor/etc/bpf ==="); + ALOGE("If this triggers reliably, you're probably missing kernel options or patches."); + ALOGE("If this triggers randomly, you might be hitting some memory allocation " + "problems or startup script race."); + ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---"); + sleep(20); + exit(121); } const char* args[] = {"/apex/com.android.tethering/bin/netbpfload", "done", NULL}; From d29bd0b4ca62ffa909fee8604d1a65fbeb32eaa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 00:01:50 -0700 Subject: [PATCH 04/13] vendorBpfLoader: move /sys/fs/bpf/vendor creation to rust MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We continue to have: $ adbz shell ls -lZ /sys/fs/bpf /sys/fs/bpf/vendor /sys/fs/bpf: total 0 ... drwxrwxrwt 2 root root u:object_r:fs_bpf_vendor:s0 0 2025-07-16 00:09 vendor /sys/fs/bpf/vendor: total 0 -r--r----- 1 root system u:object_r:fs_bpf_vendor:s0 0 2025-07-16 00:09 prog_filterPowerSupplyEvents_skfilter_power_supply Test: TreeHugger Flag: EXEMPT no-op Signed-off-by: Maciej Żenczykowski Change-Id: I74d87a6f382e3b1bc10a8eb82915bc340568f2a8 --- loader/Loader.cpp | 17 ----------------- loader/bpfloader.rs | 4 ++++ 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index be12a6f..57a1259 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -850,21 +850,6 @@ int loadAllElfObjects() { return retVal; } -int createSysFsBpfVendor() { - mode_t prevUmask = umask(0); - - errno = 0; - int ret = mkdir("/sys/fs/bpf/vendor", S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO); - if (ret && errno != EEXIST) { - const int err = errno; - ALOGE("Failed to create directory: /sys/fs/bpf/vendor, ret: %s", strerror(err)); - return -err; - } - - umask(prevUmask); - return 0; -} - } // namespace bpf } // namespace android @@ -877,8 +862,6 @@ void vendorBpfLoader() { const char* argv[] = {"/system/bin/bpfloader", NULL}; android::base::InitLogging(const_cast(argv), &android::base::KernelLogger); - if (android::bpf::createSysFsBpfVendor()) exit(120); - // Load all ELF objects, create programs and maps, and pin them if (android::bpf::loadAllElfObjects()) { ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM /vendor/etc/bpf ==="); diff --git a/loader/bpfloader.rs b/loader/bpfloader.rs index e9bfd6e..bfa5d74 100644 --- a/loader/bpfloader.rs +++ b/loader/bpfloader.rs @@ -644,6 +644,10 @@ fn main() { load_libbpf_progs(); info!("Loading legacy BPF progs"); + if let Err(e) = create_dir(Path::new("/sys/fs/bpf/vendor")) { + panic!("Error during mkdir /sys/fs/bpf/vendor: {e}"); + }; + // SAFETY: Linking in the existing legacy vendor bpfloader functionality. // The following bindgen function can abort() or exit() on failure, // but will usually execve(). From 174cddec913ce009d6d3c6c18979f6af70c7b4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 08:33:00 -0700 Subject: [PATCH 05/13] vendorBpfLoader: kernel is guaranteed to be 5.4+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (even 5.10+) Test: TreeHugger Flag: EXEMPT cleanup Signed-off-by: Maciej Żenczykowski Change-Id: I4c9a2a222071095559b1605d4417f93eecf4667f --- loader/Loader.cpp | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index 57a1259..f62347d 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -432,7 +432,7 @@ static int getSymNameByIdx(ifstream& elfFile, int index, string& name) { } static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, - const struct bpf_map_def& mapDef, const enum bpf_map_type type) { + const struct bpf_map_def& mapDef) { // Assuming fd is a valid Bpf Map file descriptor then // all the following should always succeed on a 4.14+ kernel. // If they somehow do fail, they'll return -1 (and set errno), @@ -446,14 +446,14 @@ static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, // DEVMAPs are readonly from the bpf program side's point of view, as such // the kernel in kernel/bpf/devmap.c dev_map_init_map() will set the flag int desired_map_flags = (int)mapDef.map_flags; - if (type == BPF_MAP_TYPE_DEVMAP || type == BPF_MAP_TYPE_DEVMAP_HASH) + if (mapDef.type == BPF_MAP_TYPE_DEVMAP || mapDef.type == BPF_MAP_TYPE_DEVMAP_HASH) desired_map_flags |= BPF_F_RDONLY_PROG; // The .h file enforces that this is a power of two, and page size will // also always be a power of two, so this logic is actually enough to // force it to be a multiple of the page size, as required by the kernel. unsigned int desired_max_entries = mapDef.max_entries; - if (type == BPF_MAP_TYPE_RINGBUF) { + if (mapDef.type == BPF_MAP_TYPE_RINGBUF) { if (desired_max_entries < page_size) desired_max_entries = page_size; } @@ -464,7 +464,7 @@ static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, // Another possibility is that something is misconfigured in the code: // most likely a shared map is declared twice differently. // But such a change should never be checked into the source tree... - if ((fd_type == type) && + if ((fd_type == mapDef.type) && (fd_key_size == (int)mapDef.key_size) && (fd_value_size == (int)mapDef.value_size) && (fd_max_entries == (int)desired_max_entries) && @@ -474,7 +474,7 @@ static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, ALOGE("bpf map name %s mismatch: desired/found: " "type:%d/%d key:%u/%d value:%u/%d entries:%u/%d flags:%u/%d", - mapName.c_str(), type, fd_type, mapDef.key_size, fd_key_size, mapDef.value_size, + mapName.c_str(), mapDef.type, fd_type, mapDef.key_size, fd_key_size, mapDef.value_size, fd_value_size, mapDef.max_entries, fd_max_entries, desired_map_flags, fd_map_flags); return false; } @@ -520,23 +520,11 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector& continue; } - enum bpf_map_type type = md[i].type; - if (type == BPF_MAP_TYPE_DEVMAP_HASH && !isAtLeastKernelVersion(5, 4, 0)) { - // On Linux Kernels older than 5.4 this map type doesn't exist, but it can kind - // of be approximated: HASH has the same userspace visible api. - // However it cannot be used by ebpf programs in the same way. - // Since bpf_redirect_map() only requires 4.14, a program using a DEVMAP_HASH map - // would fail to load (due to trying to redirect to a HASH instead of DEVMAP_HASH). - // One must thus tag any BPF_MAP_TYPE_DEVMAP_HASH + bpf_redirect_map() using - // programs as being 5.4+... - type = BPF_MAP_TYPE_HASH; - } - // The .h file enforces that this is a power of two, and page size will // also always be a power of two, so this logic is actually enough to // force it to be a multiple of the page size, as required by the kernel. unsigned int max_entries = md[i].max_entries; - if (type == BPF_MAP_TYPE_RINGBUF) { + if (md[i].type == BPF_MAP_TYPE_RINGBUF) { if (max_entries < page_size) max_entries = page_size; } @@ -556,7 +544,7 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector& reuse = true; } else { union bpf_attr req = { - .map_type = type, + .map_type = md[i].type, .key_size = md[i].key_size, .value_size = md[i].value_size, .max_entries = max_entries, @@ -573,7 +561,7 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector& // When reusing a pinned map, we need to check the map type/sizes/etc match, but for // safety (since reuse code path is rare) run these checks even if we just created it. // We assume failure is due to pinned map mismatch, hence the 'NOT UNIQUE' return code. - if (!mapMatchesExpectations(fd, mapNames[i], md[i], type)) return -ENOTUNIQ; + if (!mapMatchesExpectations(fd, mapNames[i], md[i])) return -ENOTUNIQ; if (!reuse) { ret = bpfFdPin(fd, mapPinLoc.c_str()); From b902e1c254e9fbd4d4517d573b28cacc60b46695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 08:35:34 -0700 Subject: [PATCH 06/13] vendorBpfLoader: change single line, end-of-line /* */ comments to // MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Flag: EXEMPT cleanup Signed-off-by: Maciej Żenczykowski Change-Id: Ibc2b32b3a07a1115489b373a97827625fa27ff10 --- loader/Loader.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index f62347d..a5b3d50 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -110,7 +110,7 @@ typedef struct { vector rel_data; optional prog_def; - unique_fd prog_fd; /* fd after loading */ + unique_fd prog_fd; // fd after loading } codeSection; static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) { @@ -122,7 +122,7 @@ static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) { return 0; } -/* Reads all section header tables into an Shdr array */ +// Reads all section header tables into an Shdr array static int readSectionHeadersAll(ifstream& elfFile, vector& shTable) { Elf64_Ehdr eh; int ret = 0; @@ -133,7 +133,7 @@ static int readSectionHeadersAll(ifstream& elfFile, vector& shTable) elfFile.seekg(eh.e_shoff); if (elfFile.fail()) return -1; - /* Read shdr table entries */ + // Read shdr table entries shTable.resize(eh.e_shnum); if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM; @@ -141,7 +141,7 @@ static int readSectionHeadersAll(ifstream& elfFile, vector& shTable) return 0; } -/* Read a section by its index - for ex to get sec hdr strtab blob */ +// Read a section by its index - for ex to get sec hdr strtab blob static int readSectionByIdx(ifstream& elfFile, int id, vector& sec) { vector shTable; int ret = readSectionHeadersAll(elfFile, shTable); @@ -156,7 +156,7 @@ static int readSectionByIdx(ifstream& elfFile, int id, vector& sec) { return 0; } -/* Read whole section header string table */ +// Read whole section header string table static int readSectionHeaderStrtab(ifstream& elfFile, vector& strtab) { Elf64_Ehdr eh; int ret = readElfHeader(elfFile, &eh); @@ -168,7 +168,7 @@ static int readSectionHeaderStrtab(ifstream& elfFile, vector& strtab) { return 0; } -/* Get name from offset in strtab */ +// Get name from offset in strtab static int getSymName(ifstream& elfFile, int nameOff, string& name) { int ret; vector secStrTab; @@ -182,7 +182,7 @@ static int getSymName(ifstream& elfFile, int nameOff, string& name) { return 0; } -/* Reads a full section by name - example to get the GPL license */ +// Reads a full section by name - example to get the GPL license static int readSectionByName(const char* name, ifstream& elfFile, vector& data) { vector secStrTab; vector shTable; @@ -314,7 +314,7 @@ static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vect ret = readSymTab(elfFile, 1 /* sort */, symtab); if (ret) return ret; - /* Get index of section */ + // Get index of section ret = readSectionHeadersAll(elfFile, shTable); if (ret) return ret; @@ -329,7 +329,7 @@ static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vect } } - /* No section found with matching name*/ + // No section found with matching name if (sec_idx == -1) { ALOGW("No %s section could be found in elf object", sectionName.c_str()); return -1; @@ -349,7 +349,7 @@ static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vect return 0; } -/* Read a section by its index - for ex to get sec hdr strtab blob */ +// Read a section by its index - for ex to get sec hdr strtab blob static int readCodeSections(ifstream& elfFile, vector& cs) { vector shTable; int entries, ret = 0; @@ -399,7 +399,7 @@ static int readCodeSections(ifstream& elfFile, vector& cs) { } } - /* Check for rel section */ + // Check for rel section if (cs_temp.data.size() > 0 && i < entries) { ret = getSymName(elfFile, shTable[i + 1].sh_name, name); if (ret) return ret; @@ -641,7 +641,7 @@ static void applyMapRelo(ifstream& elfFile, vector &mapFds, vector Date: Wed, 16 Jul 2025 08:39:18 -0700 Subject: [PATCH 07/13] vendorBpfLoader: remove mapMatchesExpectations() check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was primarily meant as a safety check for mainline, it's not really needed in platform bpf loader. Test: TreeHugger Flag: EXEMPT cleanup Signed-off-by: Maciej Żenczykowski Change-Id: I615f54f10baa75f641129507ecce9159ff31a740 --- loader/Loader.cpp | 53 ----------------------------------------------- 1 file changed, 53 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index a5b3d50..f683413 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -431,54 +431,6 @@ static int getSymNameByIdx(ifstream& elfFile, int index, string& name) { return getSymName(elfFile, symtab[index].st_name, name); } -static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, - const struct bpf_map_def& mapDef) { - // Assuming fd is a valid Bpf Map file descriptor then - // all the following should always succeed on a 4.14+ kernel. - // If they somehow do fail, they'll return -1 (and set errno), - // which should then cause (among others) a key_size mismatch. - int fd_type = bpfGetFdMapType(fd); - int fd_key_size = bpfGetFdKeySize(fd); - int fd_value_size = bpfGetFdValueSize(fd); - int fd_max_entries = bpfGetFdMaxEntries(fd); - int fd_map_flags = bpfGetFdMapFlags(fd); - - // DEVMAPs are readonly from the bpf program side's point of view, as such - // the kernel in kernel/bpf/devmap.c dev_map_init_map() will set the flag - int desired_map_flags = (int)mapDef.map_flags; - if (mapDef.type == BPF_MAP_TYPE_DEVMAP || mapDef.type == BPF_MAP_TYPE_DEVMAP_HASH) - desired_map_flags |= BPF_F_RDONLY_PROG; - - // The .h file enforces that this is a power of two, and page size will - // also always be a power of two, so this logic is actually enough to - // force it to be a multiple of the page size, as required by the kernel. - unsigned int desired_max_entries = mapDef.max_entries; - if (mapDef.type == BPF_MAP_TYPE_RINGBUF) { - if (desired_max_entries < page_size) desired_max_entries = page_size; - } - - // The following checks should *never* trigger, if one of them somehow does, - // it probably means a bpf .o file has been changed/replaced at runtime - // and bpfloader was manually rerun (normally it should only run *once* - // early during the boot process). - // Another possibility is that something is misconfigured in the code: - // most likely a shared map is declared twice differently. - // But such a change should never be checked into the source tree... - if ((fd_type == mapDef.type) && - (fd_key_size == (int)mapDef.key_size) && - (fd_value_size == (int)mapDef.value_size) && - (fd_max_entries == (int)desired_max_entries) && - (fd_map_flags == desired_map_flags)) { - return true; - } - - ALOGE("bpf map name %s mismatch: desired/found: " - "type:%d/%d key:%u/%d value:%u/%d entries:%u/%d flags:%u/%d", - mapName.c_str(), mapDef.type, fd_type, mapDef.key_size, fd_key_size, mapDef.value_size, - fd_value_size, mapDef.max_entries, fd_max_entries, desired_map_flags, fd_map_flags); - return false; -} - static int createMaps(const char* elfPath, ifstream& elfFile, vector& mapFds) { int ret; vector mdData; @@ -558,11 +510,6 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector& if (!fd.ok()) return -saved_errno; - // When reusing a pinned map, we need to check the map type/sizes/etc match, but for - // safety (since reuse code path is rare) run these checks even if we just created it. - // We assume failure is due to pinned map mismatch, hence the 'NOT UNIQUE' return code. - if (!mapMatchesExpectations(fd, mapNames[i], md[i])) return -ENOTUNIQ; - if (!reuse) { ret = bpfFdPin(fd, mapPinLoc.c_str()); if (ret) { From 77f8e9e3733bbd5cb85984b2dbe34c4996148517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 08:41:44 -0700 Subject: [PATCH 08/13] vendorBpfLoader: remove printing of map/prog ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Really just spurious logging code. If you're working on a device (as opposed to looking at bugreports) you can get this information with for example 'bpftool': $ adb shell bpftool map show pinned '/sys/fs/bpf/map_bpfRingbufProg_test_ringbuf' 77: ringbuf name test_ringbuf flags 0x0 key 0B value 0B max_entries 4096 memlock 16696B $ adb shell bpftool prog show pinned /sys/fs/bpf/vendor/prog_filterPowerSupplyEvents_skfilter_power_supply 82: socket_filter name skfilter_power_ tag b8b4693584760391 loaded_at 2025-07-16T08:44:56-0700 uid 0 xlated 848B jited 470B memlock 4096B Test: TreeHugger Flag: EXEMPT cleanup Signed-off-by: Maciej Żenczykowski Change-Id: Ie7baf7cf5df9c25ad2d159767584670361e8c6eb --- loader/Loader.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index f683413..97fac23 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -533,13 +533,6 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector& } } - int mapId = bpfGetFdMapId(fd); - if (mapId == -1) { - ALOGE("bpfGetFdMapId failed, ret: %d [%d]", mapId, errno); - } else { - ALOGD("map %s id %d", mapPinLoc.c_str(), mapId); - } - mapFds.push_back(std::move(fd)); } @@ -697,13 +690,6 @@ static int loadCodeSections(const char* elfPath, vector& cs, const return -err; } } - - int progId = bpfGetFdProgId(fd); - if (progId == -1) { - ALOGE("bpfGetFdProgId failed, ret: %d [%d]", progId, errno); - } else { - ALOGD("prog %s id %d", progPinLoc.c_str(), progId); - } } return 0; From b3ad463c44825e4cabd7a45fd581765331e751d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 08:51:33 -0700 Subject: [PATCH 09/13] vendorBpfLoader: remove unused readSectionUint() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Flag: EXEMPT cleanup Signed-off-by: Maciej Żenczykowski Change-Id: I1a9e8f5e419eb4cde2dd734720d314bcee2dbf9c --- loader/Loader.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index 97fac23..268ec52 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -214,29 +214,6 @@ static int readSectionByName(const char* name, ifstream& elfFile, vector& return -2; } -unsigned int readSectionUint(const char* name, ifstream& elfFile, unsigned int defVal) { - vector theBytes; - int ret = readSectionByName(name, elfFile, theBytes); - if (ret) { - ALOGV("Couldn't find section %s (defaulting to %u [0x%x]).", name, defVal, defVal); - return defVal; - } else if (theBytes.size() < sizeof(unsigned int)) { - ALOGE("Section %s too short (defaulting to %u [0x%x]).", name, defVal, defVal); - return defVal; - } else { - // decode first 4 bytes as LE32 uint, there will likely be more bytes due to alignment. - unsigned int value = static_cast(theBytes[3]); - value <<= 8; - value += static_cast(theBytes[2]); - value <<= 8; - value += static_cast(theBytes[1]); - value <<= 8; - value += static_cast(theBytes[0]); - ALOGV("Section %s value is %u [0x%x]", name, value, value); - return value; - } -} - static int readSectionByType(ifstream& elfFile, int type, vector& data) { int ret; vector shTable; From a3ecd745945a56fda272324ae73624a2205f41c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 08:55:30 -0700 Subject: [PATCH 10/13] vendorBpfLoader: trivialize getSectionType() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit since we only support skfilter/ we can simplify this (support for any future other vendor types should be added to the rust loader) Test: TreeHugger Flag: EXEMPT cleanup Signed-off-by: Maciej Żenczykowski Change-Id: I72ad38c056728ef768ee70bc38471c3e9d368f60 --- loader/Loader.cpp | 37 ++----------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index 268ec52..7d8a999 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -79,30 +79,6 @@ static string pathToObjName(const string& path) { return name.substr(0, name.find_last_of('@')); } -typedef struct { - const char* name; - enum bpf_prog_type type; -} sectionType; - -/* - * Map section name prefixes to program types, the section name will be: - * SECTION(/) - * For example: - * SECTION("tracepoint/sched_switch_func") where sched_switch_funcs - * is the name of the program, and tracepoint is the type. - * - * However, be aware that you should not be directly using the SECTION() macro. - * Instead use the DEFINE_(BPF|XDP)_(PROG|MAP)... & LICENSE/CRITICAL macros. - * - * see b/162057235. For arbitrary program types, the concern is that due to the lack of - * SELinux access controls over BPF program attachpoints, we have no way to control the - * attachment of programs to shared resources (or to detect when a shared resource - * has one BPF program replace another that is attached there) - */ -sectionType sectionNameTypes[] = { - {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER}, -}; - typedef struct { enum bpf_prog_type type; string name; @@ -258,13 +234,6 @@ static int readSymTab(ifstream& elfFile, int sort, vector& data) { return 0; } -static enum bpf_prog_type getSectionType(string& name) { - for (auto& snt : sectionNameTypes) - if (StartsWith(name, snt.name)) return snt.type; - - return BPF_PROG_TYPE_UNSPEC; -} - static int readProgDefs(ifstream& elfFile, vector& pd) { vector pdData; int ret = readSectionByName("progs", elfFile, pdData); @@ -350,16 +319,14 @@ static int readCodeSections(ifstream& elfFile, vector& cs) { ret = getSymName(elfFile, shTable[i].sh_name, name); if (ret) return ret; - enum bpf_prog_type ptype = getSectionType(name); - - if (ptype == BPF_PROG_TYPE_UNSPEC) continue; + if (!StartsWith(name, "skfilter/")) continue; string oldName = name; // convert all slashes to underscores std::replace(name.begin(), name.end(), '/', '_'); - cs_temp.type = ptype; + cs_temp.type = BPF_PROG_TYPE_SOCKET_FILTER; cs_temp.name = name; ret = readSectionByIdx(elfFile, i, cs_temp.data); From 97810f306da663409dfbf922b6603c47eebd3f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 09:01:20 -0700 Subject: [PATCH 11/13] vendorBpfLoader: less copies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Flag: EXEMPT no-op Signed-off-by: Maciej Żenczykowski Change-Id: I3572cf9dca5caf910d4870788b0ce41a02ba14ad --- loader/Loader.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index 7d8a999..81dc678 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -175,15 +175,12 @@ static int readSectionByName(const char* name, ifstream& elfFile, vector& if (!secname) continue; if (!strcmp(secname, name)) { - vector dataTmp; - dataTmp.resize(shTable[i].sh_size); - elfFile.seekg(shTable[i].sh_offset); if (elfFile.fail()) return -1; - if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1; + data.resize(shTable[i].sh_size); + if (!elfFile.read(data.data(), shTable[i].sh_size)) return -1; - data = dataTmp; return 0; } } @@ -200,15 +197,12 @@ static int readSectionByType(ifstream& elfFile, int type, vector& data) { for (int i = 0; i < (int)shTable.size(); i++) { if ((int)shTable[i].sh_type != type) continue; - vector dataTmp; - dataTmp.resize(shTable[i].sh_size); - elfFile.seekg(shTable[i].sh_offset); if (elfFile.fail()) return -1; - if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1; + data.resize(shTable[i].sh_size); + if (!elfFile.read(data.data(), shTable[i].sh_size)) return -1; - data = dataTmp; return 0; } return -2; From 424eb2ad5110d276f209c1fe53666ecf58b301bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 09:14:23 -0700 Subject: [PATCH 12/13] vendorBpfLoader: templatize readSectionByName MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Flag: EXEMPT no-op Signed-off-by: Maciej Żenczykowski Change-Id: Id793381411d559ba338aaad83815e5f429848286 --- loader/Loader.cpp | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index 81dc678..f946052 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -159,7 +159,8 @@ static int getSymName(ifstream& elfFile, int nameOff, string& name) { } // Reads a full section by name - example to get the GPL license -static int readSectionByName(const char* name, ifstream& elfFile, vector& data) { +template +static int readSectionByName(const char* name, ifstream& elfFile, vector& data) { vector secStrTab; vector shTable; int ret; @@ -178,8 +179,10 @@ static int readSectionByName(const char* name, ifstream& elfFile, vector& elfFile.seekg(shTable[i].sh_offset); if (elfFile.fail()) return -1; - data.resize(shTable[i].sh_size); - if (!elfFile.read(data.data(), shTable[i].sh_size)) return -1; + if (shTable[i].sh_size % sizeof(T)) return -1; + data.resize(shTable[i].sh_size / sizeof(T)); + if (!elfFile.read(reinterpret_cast(data.data()), shTable[i].sh_size)) + return -1; return 0; } @@ -229,19 +232,7 @@ static int readSymTab(ifstream& elfFile, int sort, vector& data) { } static int readProgDefs(ifstream& elfFile, vector& pd) { - vector pdData; - int ret = readSectionByName("progs", elfFile, pdData); - if (ret) return ret; - - if (pdData.size() % sizeof(struct bpf_prog_def)) { - ALOGE("readProgDefs failed due to improper sized progs section, %zu %% %zu != 0", - pdData.size(), sizeof(struct bpf_prog_def)); - return -1; - }; - - pd.resize(pdData.size() / sizeof(struct bpf_prog_def)); - memcpy(pd.data(), pdData.data(), pdData.size()); - return 0; + return readSectionByName("progs", elfFile, pd); } static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector& names, @@ -371,23 +362,14 @@ static int getSymNameByIdx(ifstream& elfFile, int index, string& name) { static int createMaps(const char* elfPath, ifstream& elfFile, vector& mapFds) { int ret; - vector mdData; vector md; vector mapNames; string objName = pathToObjName(string(elfPath)); - ret = readSectionByName("maps", elfFile, mdData); + ret = readSectionByName("maps", elfFile, md); if (ret == -2) return 0; // no maps to read if (ret) return ret; - if (mdData.size() % sizeof(struct bpf_map_def)) { - ALOGE("createMaps failed due to improper sized maps section, %zu %% %zu != 0", - mdData.size(), sizeof(struct bpf_map_def)); - return -1; - } - md.resize(mdData.size() / sizeof(struct bpf_map_def)); - memcpy(md.data(), mdData.data(), mdData.size()); - ret = getSectionSymNames(elfFile, "maps", mapNames); if (ret) return ret; From b0733601779cd002f7ae6beae41967241ca33cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jul 2025 09:35:03 -0700 Subject: [PATCH 13/13] vendorBpfLoader: error handling simplifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We continue to have: $ adb shell ls -lZ /sys/fs/bpf/vendor total 0 -r--r----- 1 root system u:object_r:fs_bpf_vendor:s0 0 2025-07-16 09:37 prog_filterPowerSupplyEvents_skfilter_power_supply Test: TreeHugger Flag: EXEMPT no-op Signed-off-by: Maciej Żenczykowski Change-Id: I2be675467688cf5f9c651b8311dceb68744100a8 --- loader/Loader.cpp | 49 ++++++++++++++--------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/loader/Loader.cpp b/loader/Loader.cpp index f946052..cde6447 100644 --- a/loader/Loader.cpp +++ b/loader/Loader.cpp @@ -101,10 +101,8 @@ static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) { // Reads all section header tables into an Shdr array static int readSectionHeadersAll(ifstream& elfFile, vector& shTable) { Elf64_Ehdr eh; - int ret = 0; - ret = readElfHeader(elfFile, &eh); - if (ret) return ret; + if (readElfHeader(elfFile, &eh)) return -1; elfFile.seekg(eh.e_shoff); if (elfFile.fail()) return -1; @@ -112,7 +110,7 @@ static int readSectionHeadersAll(ifstream& elfFile, vector& shTable) // Read shdr table entries shTable.resize(eh.e_shnum); - if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM; + if (!elfFile.read((char*)shTable.data(), eh.e_shnum * eh.e_shentsize)) return -1; return 0; } @@ -120,8 +118,7 @@ static int readSectionHeadersAll(ifstream& elfFile, vector& shTable) // Read a section by its index - for ex to get sec hdr strtab blob static int readSectionByIdx(ifstream& elfFile, int id, vector& sec) { vector shTable; - int ret = readSectionHeadersAll(elfFile, shTable); - if (ret) return ret; + if (readSectionHeadersAll(elfFile, shTable)) return -1; elfFile.seekg(shTable[id].sh_offset); if (elfFile.fail()) return -1; @@ -135,45 +132,33 @@ static int readSectionByIdx(ifstream& elfFile, int id, vector& sec) { // Read whole section header string table static int readSectionHeaderStrtab(ifstream& elfFile, vector& strtab) { Elf64_Ehdr eh; - int ret = readElfHeader(elfFile, &eh); - if (ret) return ret; - - ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab); - if (ret) return ret; - + if (readElfHeader(elfFile, &eh)) return -1; + if (readSectionByIdx(elfFile, eh.e_shstrndx, strtab)) return -1; return 0; } // Get name from offset in strtab static int getSymName(ifstream& elfFile, int nameOff, string& name) { - int ret; vector secStrTab; - - ret = readSectionHeaderStrtab(elfFile, secStrTab); - if (ret) return ret; + if (readSectionHeaderStrtab(elfFile, secStrTab)) return -1; if (nameOff >= (int)secStrTab.size()) return -1; - name = string((char*)secStrTab.data() + nameOff); + name = string(secStrTab.data() + nameOff); return 0; } // Reads a full section by name - example to get the GPL license template static int readSectionByName(const char* name, ifstream& elfFile, vector& data) { - vector secStrTab; vector shTable; - int ret; + if (readSectionHeadersAll(elfFile, shTable)) return -1; - ret = readSectionHeadersAll(elfFile, shTable); - if (ret) return ret; - - ret = readSectionHeaderStrtab(elfFile, secStrTab); - if (ret) return ret; + vector secStrTab; + if (readSectionHeaderStrtab(elfFile, secStrTab)) return -1; for (int i = 0; i < (int)shTable.size(); i++) { char* secname = secStrTab.data() + shTable[i].sh_name; - if (!secname) continue; if (!strcmp(secname, name)) { elfFile.seekg(shTable[i].sh_offset); @@ -191,11 +176,8 @@ static int readSectionByName(const char* name, ifstream& elfFile, vector& dat } static int readSectionByType(ifstream& elfFile, int type, vector& data) { - int ret; vector shTable; - - ret = readSectionHeadersAll(elfFile, shTable); - if (ret) return ret; + if (readSectionHeadersAll(elfFile, shTable)) return -1; for (int i = 0; i < (int)shTable.size(); i++) { if ((int)shTable[i].sh_type != type) continue; @@ -216,15 +198,12 @@ static bool symCompare(Elf64_Sym a, Elf64_Sym b) { } static int readSymTab(ifstream& elfFile, int sort, vector& data) { - int ret, numElems; - Elf64_Sym* buf; vector secData; - - ret = readSectionByType(elfFile, SHT_SYMTAB, secData); + int ret = readSectionByType(elfFile, SHT_SYMTAB, secData); if (ret) return ret; - buf = (Elf64_Sym*)secData.data(); - numElems = (secData.size() / sizeof(Elf64_Sym)); + Elf64_Sym* buf = (Elf64_Sym*)secData.data(); + int numElems = secData.size() / sizeof(Elf64_Sym); data.assign(buf, buf + numElems); if (sort) std::sort(data.begin(), data.end(), symCompare);