diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp index 8f5318d..5a65c1b 100644 --- a/libbpf_android/Loader.cpp +++ b/libbpf_android/Loader.cpp @@ -564,8 +564,9 @@ static int loadCodeSections(const char* elfPath, vector& cs, const progPinLoc += '_'; progPinLoc += name; if (access(progPinLoc.c_str(), F_OK) == 0) { - fd = bpf_obj_get(progPinLoc.c_str()); - ALOGD("New bpf prog load reusing prog %s, ret: %d\n", progPinLoc.c_str(), fd); + fd = retrieveProgram(progPinLoc.c_str()); + ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)\n", progPinLoc.c_str(), fd, + (fd < 0 ? std::strerror(errno) : "no error")); reuse = true; } else { vector log_buf(BPF_LOAD_LOG_SZ, 0); @@ -579,9 +580,15 @@ static int loadCodeSections(const char* elfPath, vector& cs, const if (fd < 0) { std::vector lines = android::base::Split(log_buf.data(), "\n"); - ALOGE("bpf_prog_load - BEGIN log_buf contents:"); - for (const auto& line : lines) ALOGE("%s", line.c_str()); - ALOGE("bpf_prog_load - END 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."); + + if (cs[i].prog_def->optional) { + ALOGW("failed program is marked optional - continuing..."); + continue; + } + ALOGE("non-optional program failed to load."); } } diff --git a/libbpf_android/include/bpf/BpfMap.h b/libbpf_android/include/bpf/BpfMap.h index c92f989..3e7413e 100644 --- a/libbpf_android/include/bpf/BpfMap.h +++ b/libbpf_android/include/bpf/BpfMap.h @@ -179,7 +179,7 @@ class BpfMap { template base::Result BpfMap::init(const char* path) { - mMapFd = base::unique_fd(mapRetrieve(path, 0)); + mMapFd = base::unique_fd(mapRetrieveRW(path)); if (mMapFd == -1) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h index f724f3b..6814f94 100644 --- a/libbpf_android/include/bpf/BpfUtils.h +++ b/libbpf_android/include/bpf/BpfUtils.h @@ -129,6 +129,22 @@ inline int mapRetrieve(const char* pathname, uint32_t flag) { return bpfFdGet(pathname, flag); } +inline int mapRetrieveRW(const char* pathname) { + return mapRetrieve(pathname, 0); +} + +inline int mapRetrieveRO(const char* pathname) { + return mapRetrieve(pathname, BPF_F_RDONLY); +} + +inline int mapRetrieveWO(const char* pathname) { + return mapRetrieve(pathname, BPF_F_WRONLY); +} + +inline int retrieveProgram(const char* pathname) { + return bpfFdGet(pathname, BPF_F_RDONLY); +} + inline int attachProgram(bpf_attach_type type, const base::unique_fd& prog_fd, const base::unique_fd& cg_fd) { return bpf(BPF_PROG_ATTACH, { diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h index f76b382..9d22584 100644 --- a/progs/include/bpf_helpers.h +++ b/progs/include/bpf_helpers.h @@ -111,21 +111,47 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g #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) \ +#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 = { \ + .uid = (prog_uid), \ + .gid = (prog_gid), \ + .min_kver = (min_kv), \ + .max_kver = (max_kv), \ + .optional = (opt), \ + }; \ + SEC(SECTION_NAME) \ int the_prog +// Programs (here used in the sense of functions/sections) marked optional are allowed to fail +// to load (for example due to missing kernel patches). +// The bpfloader will just ignore these failures and continue processing the next section. +// +// A non-optional program (function/section) failing to load causes a failure and aborts +// processing of the entire .o, if the .o is additionally marked critical, this will result +// in the entire bpfloader process terminating with a failure and not setting the bpf.progs_loaded +// system property. This in turn results in waitForProgsLoaded() never finishing. +// +// ie. a non-optional program in a critical .o is mandatory for kernels matching the min/max kver. + +// 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) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + false) +#define DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, \ + max_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, true) + // 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) +#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \ + false) +#define DEFINE_OPTIONAL_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \ + true) // 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) + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, false) +#define DEFINE_OPTIONAL_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, true) diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h index 60412db..8523c36 100644 --- a/progs/include/bpf_map_def.h +++ b/progs/include/bpf_map_def.h @@ -59,4 +59,6 @@ struct bpf_prog_def { 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 + + bool optional; // program section (ie. function) may fail to load, continue onto next func. };