diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-11-04 06:23:26 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-11-04 06:23:26 +0000 |
commit | 78f4bf25b91544e6caf3f0552b9ed1ef670a1ff6 (patch) | |
tree | be3612a3a4d02d871c224147051d3b9d6d47bca6 | |
parent | e6a3e70df04e520f554d5c773ca0aadec10a9037 (diff) | |
parent | a8e1252c3f20d153b597ffcb61c7c187c4d62cb0 (diff) | |
download | bpf-android14-mainline-appsearch-release.tar.gz |
Snap for 11051817 from a8e1252c3f20d153b597ffcb61c7c187c4d62cb0 to mainline-appsearch-releaseaml_ase_341510000aml_ase_341410000aml_ase_341310010android14-mainline-appsearch-release
Change-Id: I1035f7b7fd622f3ed1fcbca8453391a07c672fbc
-rw-r--r-- | bpfloader/Android.bp | 2 | ||||
-rw-r--r-- | libbpf_android/Android.bp | 5 | ||||
-rw-r--r-- | libbpf_android/BpfLoadTest.cpp | 23 | ||||
-rw-r--r-- | libbpf_android/Loader.cpp | 207 | ||||
-rw-r--r-- | libbpf_android/include/libbpf_android.h | 1 | ||||
-rw-r--r-- | progs/bpfRingbufProg.c | 5 |
6 files changed, 72 insertions, 171 deletions
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp index d3428b0..09a5d3d 100644 --- a/bpfloader/Android.bp +++ b/bpfloader/Android.bp @@ -46,7 +46,6 @@ cc_binary { "libbase", "liblog", "libnetdutils", - "libbpf_bcc", ], srcs: [ "BpfLoader.cpp", @@ -55,7 +54,6 @@ cc_binary { init_rc: ["bpfloader.rc"], required: [ - "btfloader", "timeInState.o" ], diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp index dda943d..d8272cc 100644 --- a/libbpf_android/Android.bp +++ b/libbpf_android/Android.bp @@ -42,8 +42,6 @@ cc_library { "libcutils", "libutils", "liblog", - "libbpf_bcc", - "libbpf_minimal", ], header_libs: [ "bpf_headers", @@ -51,7 +49,6 @@ cc_library { export_header_lib_headers: [ "bpf_headers", ], - export_shared_lib_headers: ["libbpf_bcc"], export_include_dirs: ["include"], defaults: ["bpf_defaults"], @@ -79,7 +76,6 @@ cc_test { shared_libs: [ "libbpf_android", "libbpf_bcc", - "libbpf_minimal", "libbase", "liblog", "libutils", @@ -87,7 +83,6 @@ cc_test { data: [ ":bpfLoadTpProg.o", - ":bpfLoadTpProgBtf.o", ], require_root: true, } diff --git a/libbpf_android/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp index 0c4e6ee..f3a8f85 100644 --- a/libbpf_android/BpfLoadTest.cpp +++ b/libbpf_android/BpfLoadTest.cpp @@ -17,6 +17,7 @@ #include <android-base/file.h> #include <android-base/macros.h> #include <gtest/gtest.h> +#include <libbpf.h> #include <stdlib.h> #include <unistd.h> #include <iostream> @@ -66,7 +67,7 @@ class BpfLoadTest : public TestWithParam<std::string> { EXPECT_EQ(android::bpf::loadProg(progPath.c_str(), &critical), 0); EXPECT_EQ(false, critical); - mProgFd = bpf_obj_get(mTpProgPath.c_str()); + mProgFd = retrieveProgram(mTpProgPath.c_str()); EXPECT_GT(mProgFd, 0); int ret = bpf_attach_tracepoint(mProgFd, "sched", "sched_switch"); @@ -103,34 +104,18 @@ class BpfLoadTest : public TestWithParam<std::string> { EXPECT_EQ(non_zero, 1); } - void checkMapBtf() { - // Earlier kernels lack BPF_BTF_LOAD support - if (!isAtLeastKernelVersion(4, 19, 0)) GTEST_SKIP() << "pre-4.19 kernel does not support BTF"; - - const bool haveBtf = GetParam().find("Btf") != std::string::npos; - - std::string str; - EXPECT_EQ(android::base::ReadFileToString(mTpMapPath, &str), haveBtf); - if (haveBtf) EXPECT_FALSE(str.empty()); - } - void checkKernelVersionEnforced() { - EXPECT_EQ(bpf_obj_get(mTpNeverLoadProgPath.c_str()), -1); + EXPECT_EQ(retrieveProgram(mTpNeverLoadProgPath.c_str()), -1); EXPECT_EQ(errno, ENOENT); } }; -INSTANTIATE_TEST_SUITE_P(BpfLoadTests, BpfLoadTest, - ::testing::Values("bpfLoadTpProg", "bpfLoadTpProgBtf")); +INSTANTIATE_TEST_SUITE_P(BpfLoadTests, BpfLoadTest, ::testing::Values("bpfLoadTpProg")); TEST_P(BpfLoadTest, bpfCheckMap) { checkMapNonZero(); } -TEST_P(BpfLoadTest, bpfCheckBtf) { - checkMapBtf(); -} - TEST_P(BpfLoadTest, bpfCheckMinKernelVersionEnforced) { checkKernelVersionEnforced(); } diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp index 7f6aae1..d817614 100644 --- a/libbpf_android/Loader.cpp +++ b/libbpf_android/Loader.cpp @@ -31,13 +31,13 @@ #include <sys/wait.h> #include <unistd.h> -// This is BpfLoader v0.38 +// This is BpfLoader v0.41 // WARNING: If you ever hit cherrypick conflicts here you're doing it wrong: // You are NOT allowed to cherrypick bpfloader related patches out of order. // (indeed: cherrypicking is probably a bad idea and you should merge instead) // Mainline supports ONLY the published versions of the bpfloader for each Android release. #define BPFLOADER_VERSION_MAJOR 0u -#define BPFLOADER_VERSION_MINOR 38u +#define BPFLOADER_VERSION_MINOR 41u #define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR) #include "BpfSyscallWrappers.h" @@ -49,8 +49,6 @@ #error "BPFLOADER_VERSION is less than COMPILE_FOR_BPFLOADER_VERSION" #endif -#include <bpf/bpf.h> - #include <cstdlib> #include <fstream> #include <iostream> @@ -95,6 +93,8 @@ const std::string& getBuildType() { return t; } +static unsigned int page_size = static_cast<unsigned int>(getpagesize()); + constexpr const char* lookupSelinuxContext(const domain d, const char* const unspecified = "") { switch (d) { case domain::unspecified: return unspecified; @@ -612,81 +612,6 @@ static int getSymNameByIdx(ifstream& elfFile, int index, string& name) { return getSymName(elfFile, symtab[index].st_name, name); } -static bool waitpidTimeout(pid_t pid, int timeoutMs) { - // Add SIGCHLD to the signal set. - sigset_t child_mask, original_mask; - sigemptyset(&child_mask); - sigaddset(&child_mask, SIGCHLD); - if (sigprocmask(SIG_BLOCK, &child_mask, &original_mask) == -1) return false; - - // Wait for a SIGCHLD notification. - errno = 0; - timespec ts = {0, timeoutMs * 1000000}; - int wait_result = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts)); - - // Restore the original signal set. - sigprocmask(SIG_SETMASK, &original_mask, nullptr); - - if (wait_result == -1) return false; - - int status; - return TEMP_FAILURE_RETRY(waitpid(pid, &status, WNOHANG)) == pid; -} - -static std::optional<unique_fd> getMapBtfInfo(const char* elfPath, - std::unordered_map<string, std::pair<uint32_t, uint32_t>> &btfTypeIds) { - unique_fd bpfloaderSocket, btfloaderSocket; - if (!android::base::Socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, &bpfloaderSocket, - &btfloaderSocket)) { - return {}; - } - - unique_fd pipeRead, pipeWrite; - if (!android::base::Pipe(&pipeRead, &pipeWrite, O_NONBLOCK)) { - return {}; - } - - pid_t pid = fork(); - if (pid < 0) return {}; - if (!pid) { - bpfloaderSocket.reset(); - pipeRead.reset(); - auto socketFdStr = std::to_string(btfloaderSocket.release()); - auto pipeFdStr = std::to_string(pipeWrite.release()); - - if (execl("/system/bin/btfloader", "/system/bin/btfloader", socketFdStr.c_str(), - pipeFdStr.c_str(), elfPath, NULL) == -1) { - ALOGW("exec btfloader failed with errno %d (%s)", errno, strerror(errno)); - exit(EX_UNAVAILABLE); - } - } - btfloaderSocket.reset(); - pipeWrite.reset(); - if (!waitpidTimeout(pid, 100)) { - kill(pid, SIGKILL); - return {}; - } - - unique_fd btfFd; - if (android::base::ReceiveFileDescriptors(bpfloaderSocket, nullptr, 0, &btfFd)) return {}; - - std::string btfTypeIdStr; - if (!android::base::ReadFdToString(pipeRead, &btfTypeIdStr)) return {}; - if (!btfFd.ok()) return {}; - - const auto mapTypeIdLines = android::base::Split(btfTypeIdStr, "\n"); - for (const auto &line : mapTypeIdLines) { - const auto vec = android::base::Split(line, " "); - // Splitting on newline will give us one empty line - if (vec.size() != 3) continue; - const int kTid = atoi(vec[1].c_str()); - const int vTid = atoi(vec[2].c_str()); - if (!kTid || !vTid) return {}; - btfTypeIds[vec[0]] = std::make_pair(kTid, vTid); - } - return btfFd; -} - static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, const struct bpf_map_def& mapDef, const enum bpf_map_type type) { // Assuming fd is a valid Bpf Map file descriptor then @@ -705,6 +630,14 @@ static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, if (type == BPF_MAP_TYPE_DEVMAP || 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 (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* @@ -715,7 +648,7 @@ static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName, if ((fd_type == type) && (fd_key_size == (int)mapDef.key_size) && (fd_value_size == (int)mapDef.value_size) && - (fd_max_entries == (int)mapDef.max_entries) && + (fd_max_entries == (int)desired_max_entries) && (fd_map_flags == desired_map_flags)) { return true; } @@ -731,10 +664,9 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& const char* prefix, const unsigned long long allowedDomainBitmask, const size_t sizeOfBpfMapDef) { int ret; - vector<char> mdData, btfData; + vector<char> mdData; vector<struct bpf_map_def> md; vector<string> mapNames; - std::unordered_map<string, std::pair<uint32_t, uint32_t>> btfTypeIdMap; string objName = pathToObjName(string(elfPath)); ret = readSectionByName("maps", elfFile, mdData); @@ -767,16 +699,8 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& ret = getSectionSymNames(elfFile, "maps", mapNames); if (ret) return ret; - unsigned btfMinBpfLoaderVer = readSectionUint("btf_min_bpfloader_ver", elfFile, 0); - unsigned btfMinKernelVer = readSectionUint("btf_min_kernel_ver", elfFile, 0); unsigned kvers = kernelVersion(); - std::optional<unique_fd> btfFd; - if ((BPFLOADER_VERSION >= btfMinBpfLoaderVer) && (kvers >= btfMinKernelVer) && - (!readSectionByName(".BTF", elfFile, btfData))) { - btfFd = getMapBtfInfo(elfPath, btfTypeIdMap); - } - for (int i = 0; i < (int)mapNames.size(); i++) { if (md[i].zero != 0) abort(); @@ -839,6 +763,14 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& 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 (max_entries < page_size) max_entries = page_size; + } + domain selinux_context = getDomainFromSelinuxContext(md[i].selinux_context); if (specified(selinux_context)) { if (!inDomainBitmask(selinux_context, allowedDomainBitmask)) { @@ -878,20 +810,15 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& ALOGD("bpf_create_map reusing map %s, ret: %d", mapNames[i].c_str(), fd.get()); reuse = true; } else { - struct bpf_create_map_attr attr = { - .name = mapNames[i].c_str(), - .map_type = type, - .map_flags = md[i].map_flags, - .key_size = md[i].key_size, - .value_size = md[i].value_size, - .max_entries = md[i].max_entries, + union bpf_attr req = { + .map_type = type, + .key_size = md[i].key_size, + .value_size = md[i].value_size, + .max_entries = max_entries, + .map_flags = md[i].map_flags, }; - if (btfFd.has_value() && btfTypeIdMap.find(mapNames[i]) != btfTypeIdMap.end()) { - attr.btf_fd = btfFd->get(); - attr.btf_key_type_id = btfTypeIdMap.at(mapNames[i]).first; - attr.btf_value_type_id = btfTypeIdMap.at(mapNames[i]).second; - } - fd.reset(bcc_create_map_xattr(&attr, true)); + strlcpy(req.map_name, mapNames[i].c_str(), sizeof(req.map_name)); + fd.reset(bpf(BPF_MAP_CREATE, req)); saved_errno = errno; ALOGD("bpf_create_map name %s, ret: %d", mapNames[i].c_str(), fd.get()); } @@ -907,7 +834,7 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& if (specified(selinux_context)) { string createLoc = string(BPF_FS_PATH) + lookupPinSubdir(selinux_context) + "tmp_map_" + objName + "_" + mapNames[i]; - ret = bpf_obj_pin(fd, createLoc.c_str()); + ret = bpfFdPin(fd, createLoc.c_str()); if (ret) { int err = errno; ALOGE("create %s -> %d [%d:%s]", createLoc.c_str(), ret, err, strerror(err)); @@ -922,7 +849,7 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& return -err; } } else { - ret = bpf_obj_pin(fd, mapPinLoc.c_str()); + ret = bpfFdPin(fd, mapPinLoc.c_str()); if (ret) { int err = errno; ALOGE("pin %s -> %d [%d:%s]", mapPinLoc.c_str(), ret, err, strerror(err)); @@ -945,13 +872,11 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& } } - struct bpf_map_info map_info = {}; - __u32 map_info_len = sizeof(map_info); - int rv = bpf_obj_get_info_by_fd(fd, &map_info, &map_info_len); - if (rv) { - ALOGE("bpf_obj_get_info_by_fd failed, ret: %d [%d]", rv, errno); + int mapId = bpfGetFdMapId(fd); + if (mapId == -1) { + ALOGE("bpfGetFdMapId failed, ret: %d [%d]", mapId, errno); } else { - ALOGI("map %s id %d", mapPinLoc.c_str(), map_info.id); + ALOGI("map %s id %d", mapPinLoc.c_str(), mapId); } mapFds.push_back(std::move(fd)); @@ -1038,7 +963,6 @@ static void applyMapRelo(ifstream& elfFile, vector<unique_fd> &mapFds, vector<co static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license, const char* prefix, const unsigned long long allowedDomainBitmask) { unsigned kvers = kernelVersion(); - int ret, fd; if (!kvers) { ALOGE("unable to get kernel version"); @@ -1048,6 +972,8 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string objName = pathToObjName(string(elfPath)); for (int i = 0; i < (int)cs.size(); i++) { + unique_fd& fd = cs[i].prog_fd; + int ret; string name = cs[i].name; if (!cs[i].prog_def.has_value()) { @@ -1125,34 +1051,36 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string progPinLoc = string(BPF_FS_PATH) + lookupPinSubdir(pin_subdir, prefix) + "prog_" + objName + '_' + string(name); if (access(progPinLoc.c_str(), F_OK) == 0) { - fd = retrieveProgram(progPinLoc.c_str()); - ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)", progPinLoc.c_str(), fd, - (fd < 0 ? std::strerror(errno) : "no error")); + fd.reset(retrieveProgram(progPinLoc.c_str())); + ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)", progPinLoc.c_str(), fd.get(), + (!fd.ok() ? std::strerror(errno) : "no error")); reuse = true; } else { vector<char> log_buf(BPF_LOAD_LOG_SZ, 0); - struct bpf_load_program_attr attr = { - .prog_type = cs[i].type, - .name = name.c_str(), - .insns = (struct bpf_insn*)cs[i].data.data(), - .license = license.c_str(), - .log_level = 0, - .expected_attach_type = cs[i].expected_attach_type, + union bpf_attr req = { + .prog_type = cs[i].type, + .kern_version = kvers, + .license = ptr_to_u64(license.c_str()), + .insns = ptr_to_u64(cs[i].data.data()), + .insn_cnt = static_cast<__u32>(cs[i].data.size() / sizeof(struct bpf_insn)), + .log_level = 1, + .log_buf = ptr_to_u64(log_buf.data()), + .log_size = static_cast<__u32>(log_buf.size()), + .expected_attach_type = cs[i].expected_attach_type, }; + strlcpy(req.prog_name, cs[i].name.c_str(), sizeof(req.prog_name)); + fd.reset(bpf(BPF_PROG_LOAD, req)); - fd = bcc_prog_load_xattr(&attr, cs[i].data.size(), log_buf.data(), log_buf.size(), - true); - - ALOGD("bpf_prog_load lib call for %s (%s) returned fd: %d (%s)", elfPath, - cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error")); + ALOGD("BPF_PROG_LOAD call for %s (%s) returned fd: %d (%s)", elfPath, + cs[i].name.c_str(), fd.get(), (!fd.ok() ? std::strerror(errno) : "no error")); - if (fd < 0) { + if (!fd.ok()) { vector<string> lines = android::base::Split(log_buf.data(), "\n"); - ALOGW("bpf_prog_load - BEGIN log_buf contents:"); + ALOGW("BPF_PROG_LOAD - BEGIN log_buf contents:"); for (const auto& line : lines) ALOGW("%s", line.c_str()); - ALOGW("bpf_prog_load - END log_buf contents."); + ALOGW("BPF_PROG_LOAD - END log_buf contents."); if (cs[i].prog_def->optional) { ALOGW("failed program is marked optional - continuing..."); @@ -1162,14 +1090,13 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const } } - if (fd < 0) return fd; - if (fd == 0) return -EINVAL; + if (!fd.ok()) return fd.get(); if (!reuse) { if (specified(selinux_context)) { string createLoc = string(BPF_FS_PATH) + lookupPinSubdir(selinux_context) + "tmp_prog_" + objName + '_' + string(name); - ret = bpf_obj_pin(fd, createLoc.c_str()); + ret = bpfFdPin(fd, createLoc.c_str()); if (ret) { int err = errno; ALOGE("create %s -> %d [%d:%s]", createLoc.c_str(), ret, err, strerror(err)); @@ -1184,7 +1111,7 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const return -err; } } else { - ret = bpf_obj_pin(fd, progPinLoc.c_str()); + ret = bpfFdPin(fd, progPinLoc.c_str()); if (ret) { int err = errno; ALOGE("create %s -> %d [%d:%s]", progPinLoc.c_str(), ret, err, strerror(err)); @@ -1205,16 +1132,12 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const } } - struct bpf_prog_info prog_info = {}; - __u32 prog_info_len = sizeof(prog_info); - int rv = bpf_obj_get_info_by_fd(fd, &prog_info, &prog_info_len); - if (rv) { - ALOGE("bpf_obj_get_info_by_fd failed, ret: %d [%d]", rv, errno); + int progId = bpfGetFdProgId(fd); + if (progId == -1) { + ALOGE("bpfGetFdProgId failed, ret: %d [%d]", progId, errno); } else { - ALOGI("prog %s id %d", progPinLoc.c_str(), prog_info.id); + ALOGI("prog %s id %d", progPinLoc.c_str(), progId); } - - cs[i].prog_fd.reset(fd); } return 0; diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h index 31bd539..cc8a942 100644 --- a/libbpf_android/include/libbpf_android.h +++ b/libbpf_android/include/libbpf_android.h @@ -17,7 +17,6 @@ #pragma once -#include <libbpf.h> #include <linux/bpf.h> #include <fstream> diff --git a/progs/bpfRingbufProg.c b/progs/bpfRingbufProg.c index cbf9104..dec1615 100644 --- a/progs/bpfRingbufProg.c +++ b/progs/bpfRingbufProg.c @@ -21,8 +21,9 @@ #define TEST_RINGBUF_MAGIC_NUM 12345 // This ring buffer is for testing purposes only. -DEFINE_BPF_RINGBUF_EXT(test_ringbuf, __u64, 4096, AID_ROOT, AID_ROOT, 0660, "", "", false, - BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, false, false); +DEFINE_BPF_RINGBUF_EXT(test_ringbuf, __u64, 4096, AID_ROOT, AID_ROOT, 0660, "", "", PRIVATE, + BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, + LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG); // This program is for test purposes only - it should never be attached to a // socket, only executed manually with BPF_PROG_RUN. |