diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp index f8ed6d5..c7c56d5 100644 --- a/libbpf_android/BpfUtils.cpp +++ b/libbpf_android/BpfUtils.cpp @@ -96,6 +96,24 @@ int setrlimitForTest() { return res; } +#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c)) + +unsigned kernelVersion() { + struct utsname buf; + int ret = uname(&buf); + if (ret) return 0; + + unsigned kver_major; + unsigned kver_minor; + unsigned kver_sub; + char dummy; + ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &dummy); + // Check the device kernel version + if (ret < 3) return 0; + + return KVER(kver_major, kver_minor, kver_sub); +} + std::string BpfLevelToString(BpfLevel bpfLevel) { switch (bpfLevel) { case BpfLevel::NONE: @@ -123,23 +141,12 @@ static BpfLevel getUncachedBpfSupportLevel() { // Check if the device is shipped originally with android P. if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE; - struct utsname buf; - int ret = uname(&buf); - if (ret) return BpfLevel::NONE; + unsigned kver = kernelVersion(); - int kernel_version_major; - int kernel_version_minor; - char dummy; - ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy); - // Check the device kernel version - if (ret < 2) return BpfLevel::NONE; - - if (kernel_version_major > 5) return BpfLevel::EXTENDED_5_4; - if (kernel_version_major == 5 && kernel_version_minor >= 4) return BpfLevel::EXTENDED_5_4; - if (kernel_version_major == 5) return BpfLevel::EXTENDED_4_19; - if (kernel_version_major == 4 && kernel_version_minor >= 19) return BpfLevel::EXTENDED_4_19; - if (kernel_version_major == 4 && kernel_version_minor >= 14) return BpfLevel::EXTENDED_4_14; - if (kernel_version_major == 4 && kernel_version_minor >= 9) return BpfLevel::BASIC_4_9; + if (kver >= KVER(5, 4, 0)) return BpfLevel::EXTENDED_5_4; + if (kver >= KVER(4, 19, 0)) return BpfLevel::EXTENDED_4_19; + if (kver >= KVER(4, 14, 0)) return BpfLevel::EXTENDED_4_14; + if (kver >= KVER(4, 9, 0)) return BpfLevel::BASIC_4_9; return BpfLevel::NONE; } diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp index 8f139a3..ce710a4 100644 --- a/libbpf_android/Loader.cpp +++ b/libbpf_android/Loader.cpp @@ -30,6 +30,7 @@ #include "../progs/include/bpf_map_def.h" #include "LoaderUtils.h" +#include "bpf/BpfUtils.h" #include "include/libbpf_android.h" #include @@ -531,9 +532,10 @@ static void applyMapRelo(ifstream& elfFile, vector &mapFds, vector& cs, const string& license) { - int ret, fd, kvers; + unsigned kvers = kernelVersion(); + int ret, fd; - if ((kvers = getMachineKvers()) < 0) return -1; + if (!kvers) return -1; string fname = pathToFilename(string(elfPath), true); @@ -541,6 +543,11 @@ static int loadCodeSections(const char* elfPath, vector& cs, const string progPinLoc; bool reuse = false; + if (cs[i].prog_def.has_value()) { + if (kvers < cs[i].prog_def->min_kver) continue; + if (kvers >= cs[i].prog_def->max_kver) continue; + } + // Format of pin location is // /sys/fs/bpf/prog__ progPinLoc = string(BPF_FS_PATH) + "prog_" + fname + "_" + cs[i].name; diff --git a/libbpf_android/LoaderUtils.h b/libbpf_android/LoaderUtils.h index 9eda833..a5ff7fc 100644 --- a/libbpf_android/LoaderUtils.h +++ b/libbpf_android/LoaderUtils.h @@ -32,43 +32,6 @@ static std::string pathToFilename(const std::string& path, bool noext = false) { return ret; } -static int getMachineKvers(void) { - struct utsname un; - char* unameOut; - int nums[3]; // maj, min, sub - - if (uname(&un)) return -1; - unameOut = un.release; - - std::string s = unameOut; - std::string token; - size_t pos = 0; - int cur_num = 0; - - while ((pos = s.find('.')) != std::string::npos && cur_num < 3) { - token = s.substr(0, pos); - s.erase(0, pos + 1); - - if ((pos = token.find('-')) != std::string::npos) token = token.substr(0, pos); - - nums[cur_num++] = stoi(token); - } - - if ((pos = s.find('-')) != std::string::npos) - token = s.substr(0, pos); - else - token = s; - - if (token.length() > 0 && cur_num < 3) { - nums[cur_num++] = stoi(token); - } - - if (cur_num != 3) - return -1; - else - return (65536 * nums[0] + 256 * nums[1] + nums[2]); -} - static void deslash(std::string& s) { std::replace(s.begin(), s.end(), '/', '_'); } diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h index 06dcc47..f724f3b 100644 --- a/libbpf_android/include/bpf/BpfUtils.h +++ b/libbpf_android/include/bpf/BpfUtils.h @@ -148,6 +148,7 @@ inline int detachProgram(bpf_attach_type type, const base::unique_fd& cg_fd) { uint64_t getSocketCookie(int sockFd); int synchronizeKernelRCU(); int setrlimitForTest(); +unsigned kernelVersion(); std::string BpfLevelToString(BpfLevel BpfLevel); BpfLevel getBpfSupportLevel(); diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h index fbdcb2f..09c3373 100644 --- a/progs/include/bpf_helpers.h +++ b/progs/include/bpf_helpers.h @@ -98,10 +98,25 @@ 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 DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \ - const struct bpf_prog_def SEC("progs") the_prog##_def = { \ - .uid = (prog_uid), \ - .gid = (prog_gid), \ - }; \ - SEC(SECTION_NAME) \ +#define KVER_NONE 0 +#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c)) +#define KVER_INF 0xFFFFFFFF + +// programs requiring a kernel version >= min_kv && < max_kv +#define DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv) \ + const struct bpf_prog_def SEC("progs") the_prog##_def = { \ + .uid = (prog_uid), \ + .gid = (prog_gid), \ + .min_kver = (min_kv), \ + .max_kver = (max_kv), \ + }; \ + SEC(SECTION_NAME) \ int the_prog + +// programs requiring a kernel version >= min_kv +#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \ + DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF) + +// programs with no kernel version requirements +#define DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \ + DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF) diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h index 03ca73b..01d9b8e 100644 --- a/progs/include/bpf_map_def.h +++ b/progs/include/bpf_map_def.h @@ -57,4 +57,7 @@ struct bpf_map_def { struct bpf_prog_def { unsigned int uid; unsigned int gid; + + unsigned int min_kver; // KERNEL_MAJOR * 65536 + KERNEL_MINOR * 256 + KERNEL_SUB + unsigned int max_kver; // ie. 0x40900 for Linux 4.9 - but beware of hexadecimal for >= 10 };