summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-10-07 16:13:52 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-10-07 16:13:52 +0000
commit4e6a1555289d3b10a70e2cc3939beb5e04749898 (patch)
treeb4608f90b54a697c11c980d1bc849e4e5e03e7f8
parent47a4ba02c8bdb34b16ee1303b6f1c251c76a078c (diff)
parent1da64c9f3561255a30bdf80046aad857cbcdedfd (diff)
downloadbpf-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.cpp178
-rw-r--r--libbpf_android/include/libbpf_android.h3
-rw-r--r--progs/include/bpf_helpers.h55
-rw-r--r--progs/include/bpf_map_def.h112
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");