diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-10-07 16:13:52 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-10-07 16:13:52 +0000 |
commit | 4e6a1555289d3b10a70e2cc3939beb5e04749898 (patch) | |
tree | b4608f90b54a697c11c980d1bc849e4e5e03e7f8 | |
parent | 47a4ba02c8bdb34b16ee1303b6f1c251c76a078c (diff) | |
parent | 1da64c9f3561255a30bdf80046aad857cbcdedfd (diff) | |
download | bpf-android-mainline-12.0.0_r113.tar.gz |
Snap for 7802884 from 1da64c9f3561255a30bdf80046aad857cbcdedfd to mainline-tzdata3-releaseandroid-mainline-12.0.0_r56android-mainline-12.0.0_r39android-mainline-12.0.0_r19android-mainline-12.0.0_r113aml_tz3_311312010
Change-Id: I56a42ef8a6af12b09d2d776d75915388cba930af
-rw-r--r-- | libbpf_android/Loader.cpp | 178 | ||||
-rw-r--r-- | libbpf_android/include/libbpf_android.h | 3 | ||||
-rw-r--r-- | progs/include/bpf_helpers.h | 55 | ||||
-rw-r--r-- | progs/include/bpf_map_def.h | 112 |
4 files changed, 328 insertions, 20 deletions
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp index dbd198d..259068a 100644 --- a/libbpf_android/Loader.cpp +++ b/libbpf_android/Loader.cpp @@ -28,6 +28,11 @@ #include <sys/utsname.h> #include <unistd.h> +// This is BpfLoader v0.2 +#define BPFLOADER_VERSION_MAJOR 0u +#define BPFLOADER_VERSION_MINOR 2u +#define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR) + #include "../progs/include/bpf_map_def.h" #include "bpf/BpfUtils.h" #include "include/libbpf_android.h" @@ -205,6 +210,29 @@ static int readSectionByName(const char* name, ifstream& elfFile, vector<char>& return -2; } +unsigned int readSectionUint(const char* name, ifstream& elfFile, unsigned int defVal) { + vector<char> theBytes; + int ret = readSectionByName(name, elfFile, theBytes); + if (ret) { + ALOGD("Couldn't find section %s (defaulting to %u [0x%x]).\n", name, defVal, defVal); + return defVal; + } else if (theBytes.size() < sizeof(unsigned int)) { + ALOGE("Section %s too short (defaulting to %u [0x%x]).\n", 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<unsigned char>(theBytes[3]); + value <<= 8; + value += static_cast<unsigned char>(theBytes[2]); + value <<= 8; + value += static_cast<unsigned char>(theBytes[1]); + value <<= 8; + value += static_cast<unsigned char>(theBytes[0]); + ALOGI("Section %s value is %u [0x%x]\n", name, value, value); + return value; + } +} + static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) { int ret; vector<Elf64_Shdr> shTable; @@ -281,14 +309,36 @@ static bool isRelSection(codeSection& cs, string& name) { return false; } -static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd) { +static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd, + size_t sizeOfBpfProgDef) { vector<char> pdData; int ret = readSectionByName("progs", elfFile, pdData); + // Older file formats do not require a 'progs' section at all. + // (We should probably figure out whether this is behaviour which is safe to remove now.) if (ret == -2) return 0; if (ret) return ret; - pd.resize(pdData.size() / sizeof(struct bpf_prog_def)); - memcpy(pd.data(), pdData.data(), pdData.size()); + if (pdData.size() % sizeOfBpfProgDef) { + ALOGE("readProgDefs failed due to improper sized progs section, %zu %% %zu != 0\n", + pdData.size(), sizeOfBpfProgDef); + return -1; + }; + + int progCount = pdData.size() / sizeOfBpfProgDef; + pd.resize(progCount); + size_t trimmedSize = std::min(sizeOfBpfProgDef, sizeof(struct bpf_prog_def)); + + const char* dataPtr = pdData.data(); + for (auto& p : pd) { + // First we zero initialize + memset(&p, 0, sizeof(p)); + // Then we set non-zero defaults + p.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER; // v1.0 + // Then we copy over the structure prefix from the ELF file. + memcpy(&p, dataPtr, trimmedSize); + // Move to next struct in the ELF file + dataPtr += sizeOfBpfProgDef; + } return 0; } @@ -335,7 +385,7 @@ static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vect } /* Read a section by its index - for ex to get sec hdr strtab blob */ -static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs) { +static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs, size_t sizeOfBpfProgDef) { vector<Elf64_Shdr> shTable; int entries, ret = 0; @@ -344,7 +394,7 @@ static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs) { entries = shTable.size(); vector<struct bpf_prog_def> pd; - ret = readProgDefs(elfFile, pd); + ret = readProgDefs(elfFile, pd, sizeOfBpfProgDef); if (ret) return ret; vector<string> progDefNames; ret = getSectionSymNames(elfFile, "progs", progDefNames); @@ -416,7 +466,7 @@ static int getSymNameByIdx(ifstream& elfFile, int index, string& name) { } static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds, - const char* prefix) { + const char* prefix, size_t sizeOfBpfMapDef) { int ret; vector<char> mdData; vector<struct bpf_map_def> md; @@ -426,20 +476,71 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& ret = readSectionByName("maps", elfFile, mdData); if (ret == -2) return 0; // no maps to read if (ret) return ret; - md.resize(mdData.size() / sizeof(struct bpf_map_def)); - memcpy(md.data(), mdData.data(), mdData.size()); + + if (mdData.size() % sizeOfBpfMapDef) { + ALOGE("createMaps failed due to improper sized maps section, %zu %% %zu != 0\n", + mdData.size(), sizeOfBpfMapDef); + return -1; + }; + + int mapCount = mdData.size() / sizeOfBpfMapDef; + md.resize(mapCount); + size_t trimmedSize = std::min(sizeOfBpfMapDef, sizeof(struct bpf_map_def)); + + const char* dataPtr = mdData.data(); + for (auto& m : md) { + // First we zero initialize + memset(&m, 0, sizeof(m)); + // Then we set non-zero defaults + m.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER; // v1.0 + m.max_kver = 0xFFFFFFFFu; // matches KVER_INF from bpf_helpers.h + // Then we copy over the structure prefix from the ELF file. + memcpy(&m, dataPtr, trimmedSize); + // Move to next struct in the ELF file + dataPtr += sizeOfBpfMapDef; + } ret = getSectionSymNames(elfFile, "maps", mapNames); if (ret) return ret; + unsigned kvers = kernelVersion(); + for (int i = 0; i < (int)mapNames.size(); i++) { - unique_fd fd; - int saved_errno; + if (BPFLOADER_VERSION < md[i].bpfloader_min_ver) { + ALOGI("skipping map %s which requires bpfloader min ver 0x%05x\n", mapNames[i].c_str(), + md[i].bpfloader_min_ver); + mapFds.push_back(unique_fd()); + continue; + } + + if (BPFLOADER_VERSION >= md[i].bpfloader_max_ver) { + ALOGI("skipping map %s which requires bpfloader max ver 0x%05x\n", mapNames[i].c_str(), + md[i].bpfloader_max_ver); + mapFds.push_back(unique_fd()); + continue; + } + + if (kvers < md[i].min_kver) { + ALOGI("skipping map %s which requires kernel version 0x%x >= 0x%x\n", + mapNames[i].c_str(), kvers, md[i].min_kver); + mapFds.push_back(unique_fd()); + continue; + } + + if (kvers >= md[i].max_kver) { + ALOGI("skipping map %s which requires kernel version 0x%x < 0x%x\n", + mapNames[i].c_str(), kvers, md[i].max_kver); + mapFds.push_back(unique_fd()); + continue; + } + // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname> - string mapPinLoc; + string mapPinLoc = + string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]); bool reuse = false; + unique_fd fd; + int saved_errno; - mapPinLoc = string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]); if (access(mapPinLoc.c_str(), F_OK) == 0) { fd.reset(bpf_obj_get(mapPinLoc.c_str())); saved_errno = errno; @@ -574,6 +675,8 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const for (int i = 0; i < (int)cs.size(); i++) { string name = cs[i].name; + unsigned bpfMinVer = DEFAULT_BPFLOADER_MIN_VER; // v0.0 + unsigned bpfMaxVer = DEFAULT_BPFLOADER_MAX_VER; // v1.0 if (cs[i].prog_def.has_value()) { unsigned min_kver = cs[i].prog_def->min_kver; @@ -582,8 +685,16 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const max_kver, kvers); if (kvers < min_kver) continue; if (kvers >= max_kver) continue; + + bpfMinVer = cs[i].prog_def->bpfloader_min_ver; + bpfMaxVer = cs[i].prog_def->bpfloader_max_ver; } + ALOGD("cs[%d].name:%s requires bpfloader version [0x%05x,0x%05x)\n", i, name.c_str(), + bpfMinVer, bpfMaxVer); + if (BPFLOADER_VERSION < bpfMinVer) continue; + if (BPFLOADER_VERSION >= bpfMaxVer) continue; + // strip any potential $foo suffix // this can be used to provide duplicate programs // conditionally loaded based on running kernel version @@ -674,7 +785,46 @@ int loadProg(const char* elfPath, bool* isCritical, const char* prefix) { elfPath, (char*)license.data()); } - ret = readCodeSections(elfFile, cs); + // the following default values are for bpfloader V0.0 format which does not include them + unsigned int bpfLoaderMinVer = + readSectionUint("bpfloader_min_ver", elfFile, DEFAULT_BPFLOADER_MIN_VER); + unsigned int bpfLoaderMaxVer = + readSectionUint("bpfloader_max_ver", elfFile, DEFAULT_BPFLOADER_MAX_VER); + size_t sizeOfBpfMapDef = + readSectionUint("size_of_bpf_map_def", elfFile, DEFAULT_SIZEOF_BPF_MAP_DEF); + size_t sizeOfBpfProgDef = + readSectionUint("size_of_bpf_prog_def", elfFile, DEFAULT_SIZEOF_BPF_PROG_DEF); + + // inclusive lower bound check + if (BPFLOADER_VERSION < bpfLoaderMinVer) { + ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with min ver 0x%05x\n", + BPFLOADER_VERSION, elfPath, bpfLoaderMinVer); + return 0; + } + + // exclusive upper bound check + if (BPFLOADER_VERSION >= bpfLoaderMaxVer) { + ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with max ver 0x%05x\n", + BPFLOADER_VERSION, elfPath, bpfLoaderMaxVer); + return 0; + } + + ALOGI("BpfLoader version 0x%05x processing ELF object %s with ver [0x%05x,0x%05x)\n", + BPFLOADER_VERSION, elfPath, bpfLoaderMinVer, bpfLoaderMaxVer); + + if (sizeOfBpfMapDef < DEFAULT_SIZEOF_BPF_MAP_DEF) { + ALOGE("sizeof(bpf_map_def) of %zu is too small (< %d)\n", sizeOfBpfMapDef, + DEFAULT_SIZEOF_BPF_MAP_DEF); + return -1; + } + + if (sizeOfBpfProgDef < DEFAULT_SIZEOF_BPF_PROG_DEF) { + ALOGE("sizeof(bpf_prog_def) of %zu is too small (< %d)\n", sizeOfBpfProgDef, + DEFAULT_SIZEOF_BPF_PROG_DEF); + return -1; + } + + ret = readCodeSections(elfFile, cs, sizeOfBpfProgDef); if (ret) { ALOGE("Couldn't read all code sections in %s\n", elfPath); return ret; @@ -683,7 +833,7 @@ int loadProg(const char* elfPath, bool* isCritical, const char* prefix) { /* Just for future debugging */ if (0) dumpAllCs(cs); - ret = createMaps(elfPath, elfFile, mapFds, prefix); + ret = createMaps(elfPath, elfFile, mapFds, prefix, sizeOfBpfMapDef); if (ret) { ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath); return ret; diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h index 90c9906..640f35b 100644 --- a/libbpf_android/include/libbpf_android.h +++ b/libbpf_android/include/libbpf_android.h @@ -29,6 +29,9 @@ namespace bpf { // BPF loader implementation. Loads an eBPF ELF object int loadProg(const char* elfPath, bool* isCritical, const char* prefix = ""); +// Exposed for testing +unsigned int readSectionUint(const char* name, std::ifstream& elfFile, unsigned int defVal); + // Wait for bpfloader to load BPF programs. static inline void waitForProgsLoaded() { // infinite loop until success with 5/10/20/40/60/60/60... delay diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h index 075ea94..abd19c6 100644 --- a/progs/include/bpf_helpers.h +++ b/progs/include/bpf_helpers.h @@ -6,11 +6,47 @@ #include "bpf_map_def.h" +/****************************************************************************** + * WARNING: CHANGES TO THIS FILE OUTSIDE OF AOSP/MASTER ARE LIKELY TO BREAK * + * DEVICE COMPATIBILITY WITH MAINLINE MODULES SHIPPING EBPF CODE. * + * * + * THIS WILL LIKELY RESULT IN BRICKED DEVICES AT SOME ARBITRARY FUTURE TIME * + * * + * THAT GOES ESPECIALLY FOR THE 'SEC' 'LICENSE' AND 'CRITICAL' MACRO DEFINES * + * * + * We strongly suggest that if you need changes to bpfloader functionality * + * you get your changes reviewed and accepted into aosp/master. * + * * + ******************************************************************************/ + /* place things in different elf sections */ #define SEC(NAME) __attribute__((section(NAME), used)) -/* Example use: LICENSE("GPL"); or LICENSE("Apache 2.0"); */ -#define LICENSE(NAME) char _license[] SEC("license") = (NAME) +/* Must be present in every program, example usage: + * LICENSE("GPL"); or LICENSE("Apache 2.0"); + * + * We also take this opportunity to embed a bunch of other useful values in + * the resulting .o (This is to enable some limited forward compatibility + * with mainline module shipped ebpf programs) + * + * The bpfloader_{min/max}_ver defines the [min, max) range of bpfloader + * versions that should load this .o file (bpfloaders outside of this range + * will simply ignore/skip this *entire* .o) + * The [inclusive,exclusive) matches what we do for kernel ver dependencies. + * + * The size_of_bpf_{map,prog}_def allow the bpfloader to load programs where + * these structures have been extended with additional fields (they will of + * course simply be ignored then). + * + * If missing, bpfloader_{min/max}_ver default to 0/0x10000 ie. [v0.0, v1.0), + * while size_of_bpf_{map/prog}_def default to 32/20 which are the v0.0 sizes. + */ +#define LICENSE(NAME) \ + unsigned int _bpfloader_min_ver SEC("bpfloader_min_ver") = DEFAULT_BPFLOADER_MIN_VER; \ + unsigned int _bpfloader_max_ver SEC("bpfloader_max_ver") = DEFAULT_BPFLOADER_MAX_VER; \ + size_t _size_of_bpf_map_def SEC("size_of_bpf_map_def") = sizeof(struct bpf_map_def); \ + size_t _size_of_bpf_prog_def SEC("size_of_bpf_prog_def") = sizeof(struct bpf_prog_def); \ + char _license[] SEC("license") = (NAME) /* flag the resulting bpf .o file as critical to system functionality, * loading all kernel version appropriate programs in it must succeed @@ -23,6 +59,10 @@ * implemented in the kernel sources. */ +#define KVER_NONE 0 +#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) +#define KVER_INF 0xFFFFFFFFu + /* generic functions */ /* @@ -68,9 +108,14 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, .key_size = sizeof(TypeOfKey), \ .value_size = sizeof(TypeOfValue), \ .max_entries = (num_entries), \ + .map_flags = 0, \ .uid = (usr), \ .gid = (grp), \ .mode = (md), \ + .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .min_kver = KVER_NONE, \ + .max_kver = KVER_INF, \ }; \ \ static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ @@ -108,10 +153,6 @@ static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_g static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid; static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id; -#define KVER_NONE 0 -#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) -#define KVER_INF 0xFFFFFFFF - #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ opt) \ const struct bpf_prog_def SEC("progs") the_prog##_def = { \ @@ -120,6 +161,8 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g .min_kver = (min_kv), \ .max_kver = (max_kv), \ .optional = (opt), \ + .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ }; \ SEC(SECTION_NAME) \ int the_prog diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h index 50a822c..647c813 100644 --- a/progs/include/bpf_map_def.h +++ b/progs/include/bpf_map_def.h @@ -25,6 +25,92 @@ // Pull in AID_* constants from //system/core/libcutils/include/private/android_filesystem_config.h #include <private/android_filesystem_config.h> +/****************************************************************************** + * * + * ! ! ! W A R N I N G ! ! ! * + * * + * CHANGES TO THESE STRUCTURE DEFINITIONS OUTSIDE OF AOSP/MASTER *WILL* BREAK * + * MAINLINE MODULE COMPATIBILITY * + * * + * AND THUS MAY RESULT IN YOUR DEVICE BRICKING AT SOME ARBITRARY POINT IN * + * THE FUTURE * + * * + * (and even in aosp/master you may only append new fields at the very end, * + * you may *never* delete fields, change their types, ordering, insert in * + * the middle, etc. If a mainline module using the old definition has * + * already shipped (which happens roughly monthly), then it's set in stone) * + * * + ******************************************************************************/ + +// These are the values used if these fields are missing +#define DEFAULT_BPFLOADER_MIN_VER 0u // v0.0 (this is inclusive ie. >= v0.0) +#define DEFAULT_BPFLOADER_MAX_VER 0x10000u // v1.0 (this is exclusive ie. < v1.0) +#define DEFAULT_SIZEOF_BPF_MAP_DEF 32 // v0.0 struct: enum (uint sized) + 7 uint +#define DEFAULT_SIZEOF_BPF_PROG_DEF 20 // v0.0 struct: 4 uint + bool + 3 byte alignment pad + +/* + * The bpf_{map,prog}_def structures are compiled for different architectures. + * Once by the BPF compiler for the BPF architecture, and once by a C++ + * compiler for the native Android architecture for the bpfloader. + * + * For things to work, their layout must be the same between the two. + * The BPF architecture is platform independent ('64-bit LSB bpf'). + * So this effectively means these structures must be the same layout + * on 5 architectures, all of them little endian: + * 64-bit BPF, x86_64, arm and 32-bit x86 and arm + * + * As such for any types we use inside of these structs we must make sure that + * the size and alignment are the same, so the same amount of padding is used. + * + * Currently we only use: bool, enum bpf_map_type and unsigned int. + * Additionally we use char for padding. + * + * !!! WARNING: HERE BE DRAGONS !!! + * + * Be particularly careful with 64-bit integers. + * You will need to manually override their alignment to 8 bytes. + * + * To quote some parts of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69560 + * + * Some types have weaker alignment requirements when they are structure members. + * + * unsigned long long on x86 is such a type. + * + * C distinguishes C11 _Alignof (the minimum alignment the type is guaranteed + * to have in all contexts, so 4, see min_align_of_type) from GNU C __alignof + * (the normal alignment of the type, so 8). + * + * alignof / _Alignof == minimum alignment required by target ABI + * __alignof / __alignof__ == preferred alignment + * + * When in a struct, apparently the minimum alignment is used. + */ + +_Static_assert(sizeof(bool) == 1, "sizeof bool != 1"); +_Static_assert(__alignof__(bool) == 1, "__alignof__ bool != 1"); +_Static_assert(_Alignof(bool) == 1, "_Alignof bool != 1"); + +_Static_assert(sizeof(char) == 1, "sizeof char != 1"); +_Static_assert(__alignof__(char) == 1, "__alignof__ char != 1"); +_Static_assert(_Alignof(char) == 1, "_Alignof char != 1"); + +// This basically verifies that an enum is 'just' a 32-bit int +_Static_assert(sizeof(enum bpf_map_type) == 4, "sizeof enum bpf_map_type != 4"); +_Static_assert(__alignof__(enum bpf_map_type) == 4, "__alignof__ enum bpf_map_type != 4"); +_Static_assert(_Alignof(enum bpf_map_type) == 4, "_Alignof enum bpf_map_type != 4"); + +// Linux kernel requires sizeof(int) == 4, sizeof(void*) == sizeof(long), sizeof(long long) == 8 +_Static_assert(sizeof(unsigned int) == 4, "sizeof unsigned int != 4"); +_Static_assert(__alignof__(unsigned int) == 4, "__alignof__ unsigned int != 4"); +_Static_assert(_Alignof(unsigned int) == 4, "_Alignof unsigned int != 4"); + +// We don't currently use any 64-bit types in these structs, so this is purely to document issue. +// Here sizeof & __alignof__ are consistent, but _Alignof is not: compile for 'aosp_cf_x86_phone' +_Static_assert(sizeof(unsigned long long) == 8, "sizeof unsigned long long != 8"); +_Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long long != 8"); +// BPF wants 8, but 32-bit x86 wants 4 +//_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8"); + /* * Map structure to be used by Android eBPF C programs. The Android eBPF loader * uses this structure from eBPF object to create maps at boot time. @@ -51,8 +137,22 @@ struct bpf_map_def { unsigned int uid; // uid_t unsigned int gid; // gid_t unsigned int mode; // mode_t + + // The following fields were added in version 0.1 + unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 + unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 + + // The following fields were added in version 0.2 + // kernelVersion() must be >= min_kver and < max_kver + unsigned int min_kver; + unsigned int max_kver; }; +// This needs to be updated whenever the above structure definition is expanded. +_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48"); +_Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4"); +_Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4"); + struct bpf_prog_def { unsigned int uid; unsigned int gid; @@ -62,4 +162,16 @@ struct bpf_prog_def { unsigned int max_kver; bool optional; // program section (ie. function) may fail to load, continue onto next func. + char pad0[3]; + + // The following fields were added in version 0.1 + unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 + unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 + + // No new fields in version 0.2 }; + +// This needs to be updated whenever the above structure definition is expanded. +_Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28"); +_Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4"); +_Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4"); |