diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-21 23:19:37 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-21 23:19:37 +0000 |
commit | 61f6929b842896687c4fc398bade4e81638760fa (patch) | |
tree | df4e08788afae8b1f6d9a25a1e7b9ab1adaa2da8 | |
parent | 7d3e8fd8c0c08fc0c84e50b9d30efc6bf308bd4b (diff) | |
parent | b5b90714ed2862a188e08434ae50cf448b34ec12 (diff) | |
download | net-61f6929b842896687c4fc398bade4e81638760fa.tar.gz |
Snap for 8750293 from b5b90714ed2862a188e08434ae50cf448b34ec12 to tm-d1-releaseandroid-13.0.0_r9android-13.0.0_r15android-13.0.0_r14android-13.0.0_r13android-13.0.0_r11android-13.0.0_r10android13-d1-s3-releaseandroid13-d1-s2-releaseandroid13-d1-s1-releaseandroid13-d1-release
Change-Id: Ibdb9ce34f93c6285a908e27bf5cb21fa339422d6
-rw-r--r-- | common/native/bpf_headers/include/bpf/BpfMap.h | 70 | ||||
-rw-r--r-- | common/native/bpf_headers/include/bpf/BpfUtils.h | 7 | ||||
-rw-r--r-- | common/native/bpf_headers/include/bpf/bpf_helpers.h | 60 | ||||
-rw-r--r-- | common/native/bpf_headers/include/bpf/bpf_map_def.h | 41 | ||||
-rw-r--r-- | common/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h | 30 | ||||
-rw-r--r-- | common/native/tcutils/kernelversion.h | 7 |
6 files changed, 173 insertions, 42 deletions
diff --git a/common/native/bpf_headers/include/bpf/BpfMap.h b/common/native/bpf_headers/include/bpf/BpfMap.h index 86c0756e..2bee2ee4 100644 --- a/common/native/bpf_headers/include/bpf/BpfMap.h +++ b/common/native/bpf_headers/include/bpf/BpfMap.h @@ -49,16 +49,20 @@ class BpfMap { protected: // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY BpfMap<Key, Value>(const char* pathname, uint32_t flags) { - int map_fd = mapRetrieve(pathname, flags); - if (map_fd >= 0) mMapFd.reset(map_fd); + mMapFd.reset(mapRetrieve(pathname, flags)); + if (mMapFd < 0) abort(); + if (isAtLeastKernelVersion(4, 14, 0)) { + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } } public: explicit BpfMap<Key, Value>(const char* pathname) : BpfMap<Key, Value>(pathname, 0) {} BpfMap<Key, Value>(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { - int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); - if (map_fd >= 0) mMapFd.reset(map_fd); + mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags)); + if (mMapFd < 0) abort(); } base::Result<Key> getFirstKey() const { @@ -99,15 +103,38 @@ class BpfMap { return {}; } + protected: + [[clang::reinitializes]] base::Result<void> init(const char* path, int fd) { + mMapFd.reset(fd); + if (mMapFd == -1) { + return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); + } + if (isAtLeastKernelVersion(4, 14, 0)) { + // Normally we should return an error here instead of calling abort, + // but this cannot happen at runtime without a massive code bug (K/V type mismatch) + // and as such it's better to just blow the system up and let the developer fix it. + // Crashes are much more likely to be noticed than logs and missing functionality. + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } + return {}; + } + + public: // Function that tries to get map from a pinned path. - base::Result<void> init(const char* path); + [[clang::reinitializes]] base::Result<void> init(const char* path) { + return init(path, mapRetrieveRW(path)); + } + #ifdef TEST_BPF_MAP // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader // this should only ever be used by test code, it is equivalent to: // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) // TODO: derive map_flags from BpfMap vs BpfMapRO - base::Result<void> resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { + [[clang::reinitializes]] base::Result<void> resetMap(bpf_map_type map_type, + uint32_t max_entries, + uint32_t map_flags = 0) { int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); if (map_fd < 0) { auto err = ErrnoErrorf("Unable to create map."); @@ -152,14 +179,23 @@ class BpfMap { // Move assignment operator BpfMap<Key, Value>& operator=(BpfMap<Key, Value>&& other) noexcept { - mMapFd = std::move(other.mMapFd); - other.reset(-1); + if (this != &other) { + mMapFd = std::move(other.mMapFd); + other.reset(); + } return *this; } void reset(base::unique_fd fd) = delete; - void reset(int fd) { mMapFd.reset(fd); } + [[clang::reinitializes]] void reset(int fd = -1) { + mMapFd.reset(fd); + if ((fd >= 0) && isAtLeastKernelVersion(4, 14, 0)) { + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + if (bpfGetFdMapFlags(mMapFd) != 0) abort(); // TODO: fix for BpfMapRO + } + } bool isValid() const { return mMapFd != -1; } @@ -195,15 +231,6 @@ class BpfMap { }; template <class Key, class Value> -base::Result<void> BpfMap<Key, Value>::init(const char* path) { - mMapFd.reset(mapRetrieveRW(path)); - if (mMapFd == -1) { - return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); - } - return {}; -} - -template <class Key, class Value> base::Result<void> BpfMap<Key, Value>::iterate( const std::function<base::Result<void>(const Key& key, const BpfMap<Key, Value>& map)>& filter) const { @@ -269,8 +296,15 @@ base::Result<void> BpfMap<Key, Value>::iterateWithValue( template <class Key, class Value> class BpfMapRO : public BpfMap<Key, Value> { public: + BpfMapRO<Key, Value>() {}; + explicit BpfMapRO<Key, Value>(const char* pathname) : BpfMap<Key, Value>(pathname, BPF_F_RDONLY) {} + + // Function that tries to get map from a pinned path. + [[clang::reinitializes]] base::Result<void> init(const char* path) { + return BpfMap<Key,Value>::init(path, mapRetrieveRO(path)); + } }; } // namespace bpf diff --git a/common/native/bpf_headers/include/bpf/BpfUtils.h b/common/native/bpf_headers/include/bpf/BpfUtils.h index 8f1b9a28..7801c3ef 100644 --- a/common/native/bpf_headers/include/bpf/BpfUtils.h +++ b/common/native/bpf_headers/include/bpf/BpfUtils.h @@ -92,7 +92,7 @@ static inline int setrlimitForTest() { #define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) -static inline unsigned kernelVersion() { +static inline unsigned uncachedKernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) return 0; @@ -108,6 +108,11 @@ static inline unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } +static inline unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); } diff --git a/common/native/bpf_headers/include/bpf/bpf_helpers.h b/common/native/bpf_headers/include/bpf/bpf_helpers.h index ac9f9bcb..10686a29 100644 --- a/common/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/common/native/bpf_headers/include/bpf/bpf_helpers.h @@ -19,6 +19,17 @@ * * ******************************************************************************/ +// The actual versions of the bpfloader that shipped in various Android releases + +// Android P/Q/R: BpfLoader was initially part of netd, +// this was later split out into a standalone binary, but was unversioned. + +// Android S / 12 (api level 31) - added 'tethering' mainline eBPF support +#define BPFLOADER_S_VERSION 2u + +// Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared' +#define BPFLOADER_T_BETA3_VERSION 13u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. @@ -126,11 +137,12 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, ____btf_map_##name = { } /* type safe macro to declare a map and related accessor functions */ -#define DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, usr, grp, md) \ +#define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ + selinux, pindir, share) \ const struct bpf_map_def SECTION("maps") the_map = { \ .type = BPF_MAP_TYPE_##TYPE, \ - .key_size = sizeof(TypeOfKey), \ - .value_size = sizeof(TypeOfValue), \ + .key_size = sizeof(KeyType), \ + .value_size = sizeof(ValueType), \ .max_entries = (num_entries), \ .map_flags = 0, \ .uid = (usr), \ @@ -140,34 +152,40 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ .min_kver = KVER_NONE, \ .max_kver = KVER_INF, \ + .selinux_context = selinux, \ + .pin_subdir = pindir, \ + .shared = share, \ }; \ - BPF_ANNOTATE_KV_PAIR(the_map, TypeOfKey, TypeOfValue); \ + BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ - static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ - const TypeOfKey* k) { \ + static inline __always_inline __unused ValueType* bpf_##the_map##_lookup_elem( \ + const KeyType* k) { \ return bpf_map_lookup_elem_unsafe(&the_map, k); \ }; \ \ static inline __always_inline __unused int bpf_##the_map##_update_elem( \ - const TypeOfKey* k, const TypeOfValue* v, unsigned long long flags) { \ + const KeyType* k, const ValueType* v, unsigned long long flags) { \ return bpf_map_update_elem_unsafe(&the_map, k, v, flags); \ }; \ \ - static inline __always_inline __unused int bpf_##the_map##_delete_elem(const TypeOfKey* k) { \ + static inline __always_inline __unused int bpf_##the_map##_delete_elem(const KeyType* k) { \ return bpf_map_delete_elem_unsafe(&the_map, k); \ }; -#define DEFINE_BPF_MAP(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, AID_ROOT, 0600) +#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ + DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, "", "", false) -#define DEFINE_BPF_MAP_GWO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0620) +#define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, AID_ROOT, 0600) -#define DEFINE_BPF_MAP_GRO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0640) +#define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0620) -#define DEFINE_BPF_MAP_GRW(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0660) +#define DEFINE_BPF_MAP_GRO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0640) + +#define DEFINE_BPF_MAP_GRW(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0660) static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; @@ -178,8 +196,8 @@ 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_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ - opt) \ +#define DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \ + selinux, pindir) \ const struct bpf_prog_def SECTION("progs") the_prog##_def = { \ .uid = (prog_uid), \ .gid = (prog_gid), \ @@ -188,10 +206,16 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g .optional = (opt), \ .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .selinux_context = selinux, \ + .pin_subdir = pindir, \ }; \ SECTION(SECTION_NAME) \ int the_prog +#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + opt) \ + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, "", "") + // 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. diff --git a/common/native/bpf_headers/include/bpf/bpf_map_def.h b/common/native/bpf_headers/include/bpf/bpf_map_def.h index 13716681..14a02959 100644 --- a/common/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/common/native/bpf_headers/include/bpf/bpf_map_def.h @@ -111,6 +111,15 @@ _Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long // BPF wants 8, but 32-bit x86 wants 4 //_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8"); +// Length of strings (incl. selinux_context and pin_subdir) +// in the bpf_map_def and bpf_prog_def structs. +// +// WARNING: YOU CANNOT *EVER* CHANGE THESE +// as this would affect the structure size in backwards incompatible ways +// and break mainline module loading on older Android T devices +#define BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE 32 +#define BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE 32 + /* * 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. @@ -142,14 +151,33 @@ struct bpf_map_def { 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 + // The following fields were added in version 0.2 (S) // kernelVersion() must be >= min_kver and < max_kver unsigned int min_kver; unsigned int max_kver; + + // The following fields were added in version 0.18 (T) + // + // These are fixed length strings, padded with null bytes + // + // Warning: supported values depend on .o location + // (additionally a newer Android OS and/or bpfloader may support more values) + // + // overrides default selinux context (which is based on pin subdir) + char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; + // + // overrides default prefix (which is based on .o location) + char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; + + bool shared; // use empty string as 'file' component of pin path - allows cross .o map sharing + char pad0[3]; // manually pad up to 4 byte alignment, may be used for extensions in the future }; +_Static_assert(sizeof(((struct bpf_map_def *)0)->selinux_context) == 32, "must be 32 bytes"); +_Static_assert(sizeof(((struct bpf_map_def *)0)->pin_subdir) == 32, "must be 32 bytes"); + // 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(sizeof(struct bpf_map_def) == 116, "sizeof struct bpf_map_def != 116"); _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"); @@ -168,10 +196,15 @@ struct bpf_prog_def { 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 + // The following fields were added in version 0.18, see description up above in bpf_map_def + char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; + char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; }; +_Static_assert(sizeof(((struct bpf_prog_def *)0)->selinux_context) == 32, "must be 32 bytes"); +_Static_assert(sizeof(((struct bpf_prog_def *)0)->pin_subdir) == 32, "must be 32 bytes"); + // 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(sizeof(struct bpf_prog_def) == 92, "sizeof struct bpf_prog_def != 92"); _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"); diff --git a/common/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/common/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index abf83daa..4b29c448 100644 --- a/common/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/common/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -150,6 +150,36 @@ inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, }); } +// requires 4.14+ kernel + +#define DEFINE_BPF_GET_FD_INFO(NAME, FIELD) \ +inline int bpfGetFd ## NAME(const BPF_FD_TYPE map_fd) { \ + struct bpf_map_info map_info = {}; \ + union bpf_attr attr = { .info = { \ + .bpf_fd = BPF_FD_TO_U32(map_fd), \ + .info_len = sizeof(map_info), \ + .info = ptr_to_u64(&map_info), \ + }}; \ + int rv = bpf(BPF_OBJ_GET_INFO_BY_FD, attr); \ + if (rv) return rv; \ + if (attr.info.info_len < offsetof(bpf_map_info, FIELD) + sizeof(map_info.FIELD)) { \ + errno = EOPNOTSUPP; \ + return -1; \ + }; \ + return map_info.FIELD; \ +} + +// All 6 of these fields are already present in Linux v4.14 (even ACK 4.14-P) +// while BPF_OBJ_GET_INFO_BY_FD is not implemented at all in v4.9 (even ACK 4.9-Q) +DEFINE_BPF_GET_FD_INFO(MapType, type) // int bpfGetFdMapType(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MapId, id) // int bpfGetFdMapId(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(KeySize, key_size) // int bpfGetFdKeySize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(ValueSize, value_size) // int bpfGetFdValueSize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MaxEntries, max_entries) // int bpfGetFdMaxEntries(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MapFlags, map_flags) // int bpfGetFdMapFlags(const BPF_FD_TYPE map_fd) + +#undef DEFINE_BPF_GET_FD_INFO + } // namespace bpf } // namespace android diff --git a/common/native/tcutils/kernelversion.h b/common/native/tcutils/kernelversion.h index 3be1ad29..492444ad 100644 --- a/common/native/tcutils/kernelversion.h +++ b/common/native/tcutils/kernelversion.h @@ -32,7 +32,7 @@ namespace android { -static inline unsigned kernelVersion() { +static inline unsigned uncachedKernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) @@ -51,6 +51,11 @@ static inline unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } +static unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); |