diff options
author | Maciej Żenczykowski <maze@google.com> | 2022-05-25 12:58:31 -0700 |
---|---|---|
committer | Maciej Żenczykowski <maze@google.com> | 2022-06-21 01:03:08 +0000 |
commit | 02869ff64ea48bf4fb75595aa81312d2b353c521 (patch) | |
tree | 4d66eab71022b9b344ed7c924fc9d30f79c4660b /common | |
parent | 76286d5800efd3108c1062a8a2155f7bdb87c497 (diff) | |
download | net-02869ff64ea48bf4fb75595aa81312d2b353c521.tar.gz |
BpfMap key/value access size verification
(beginning there of)
Bug: 218408035
Test: TreeHugger
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Ie7cf8cd51b4e272fc76a281df6231ed27955ed3f
(cherry picked from commit 62315472e581ea119fb8f44d3a03b41a8ca80b3b)
Merged-In: Ie7cf8cd51b4e272fc76a281df6231ed27955ed3f
Diffstat (limited to 'common')
-rw-r--r-- | common/native/bpf_headers/include/bpf/BpfMap.h | 41 | ||||
-rw-r--r-- | common/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h | 30 |
2 files changed, 62 insertions, 9 deletions
diff --git a/common/native/bpf_headers/include/bpf/BpfMap.h b/common/native/bpf_headers/include/bpf/BpfMap.h index 86c0756e..a7720eab 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 { @@ -100,14 +104,16 @@ class BpfMap { } // 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); #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 +158,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; } @@ -200,6 +215,14 @@ base::Result<void> BpfMap<Key, Value>::init(const char* path) { 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 {}; } 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 |