verify java map key/value struct size matches file descriptor
(this should avoid kernel reading/writing from out of bounds)
Test: TreeHugger
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I71fe71eee4e4e6a917477eef5fd2266439e803f3
diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java
index 2267f31..9042085 100644
--- a/staticlibs/device/com/android/net/module/util/BpfMap.java
+++ b/staticlibs/device/com/android/net/module/util/BpfMap.java
@@ -67,8 +67,10 @@
private static ConcurrentHashMap<Pair<String, Integer>, ParcelFileDescriptor> sFdCache =
new ConcurrentHashMap<>();
- private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode)
+ private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode,
+ int keySize, int valueSize)
throws ErrnoException, NullPointerException {
+ // TODO: key should include keySize & valueSize, but really we should match specific types
Pair<String, Integer> key = Pair.create(path, mode);
// unlocked fetch is safe: map is concurrent read capable, and only inserted into
ParcelFileDescriptor fd = sFdCache.get(key);
@@ -79,7 +81,7 @@
fd = sFdCache.get(key);
if (fd != null) return fd;
// okay, we really haven't opened this before...
- fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode));
+ fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode, keySize, valueSize));
sFdCache.put(key, fd);
return fd;
}
@@ -94,11 +96,11 @@
*/
public BpfMap(@NonNull final String path, final int flag, final Class<K> key,
final Class<V> value) throws ErrnoException, NullPointerException {
- mMapFd = cachedBpfFdGet(path, flag);
mKeyClass = key;
mValueClass = value;
mKeySize = Struct.getSize(key);
mValueSize = Struct.getSize(value);
+ mMapFd = cachedBpfFdGet(path, flag, mKeySize, mValueSize);
}
/**
@@ -295,7 +297,7 @@
}
}
- private static native int nativeBpfFdGet(String path, int mode)
+ private static native int nativeBpfFdGet(String path, int mode, int keySize, int valueSize)
throws ErrnoException, NullPointerException;
// Note: the following methods appear to not require the object by virtue of taking the
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
index 28d4b8b..e2cb676 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
@@ -16,6 +16,7 @@
#pragma once
+#include <errno.h>
#include <linux/if_ether.h>
#include <linux/pfkeyv2.h>
#include <net/if.h>
@@ -25,9 +26,10 @@
#include <sys/socket.h>
#include <sys/utsname.h>
-#include <android-base/unique_fd.h>
#include <log/log.h>
+#include "KernelVersion.h"
+
namespace android {
namespace bpf {
@@ -84,27 +86,5 @@
return res;
}
-#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
-
-static inline unsigned uncachedKernelVersion() {
- struct utsname buf;
- if (uname(&buf)) return 0;
-
- unsigned kver_major = 0;
- unsigned kver_minor = 0;
- unsigned kver_sub = 0;
- (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub);
- 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);
-}
-
} // namespace bpf
} // namespace android
diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h b/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h
new file mode 100644
index 0000000..e0e53a9
--- /dev/null
+++ b/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+namespace android {
+namespace bpf {
+
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
+
+static inline unsigned uncachedKernelVersion() {
+ struct utsname buf;
+ if (uname(&buf)) return 0;
+
+ unsigned kver_major = 0;
+ unsigned kver_minor = 0;
+ unsigned kver_sub = 0;
+ (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub);
+ 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);
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp
index cd254d4..8babcce 100644
--- a/staticlibs/native/bpfmapjni/Android.bp
+++ b/staticlibs/native/bpfmapjni/Android.bp
@@ -23,7 +23,7 @@
"com_android_net_module_util_TcUtils.cpp",
],
header_libs: [
- "bpf_syscall_wrappers",
+ "bpf_headers",
"jni_headers",
],
shared_libs: [
diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp
index 2e88fc8..2146d17 100644
--- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp
+++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp
@@ -25,15 +25,34 @@
#define BPF_FD_JUST_USE_INT
#include "BpfSyscallWrappers.h"
+#include "bpf/KernelVersion.h"
+
namespace android {
static jint com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv *env, jclass clazz,
- jstring path, jint mode) {
+ jstring path, jint mode, jint keySize, jint valueSize) {
ScopedUtfChars pathname(env, path);
jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast<unsigned>(mode));
- if (fd < 0) jniThrowErrnoException(env, "nativeBpfFdGet", errno);
+ if (fd < 0) {
+ jniThrowErrnoException(env, "nativeBpfFdGet", errno);
+ return -1;
+ }
+
+ if (bpf::isAtLeastKernelVersion(4, 14, 0)) {
+ // These likely fail with -1 and set errno to EINVAL on <4.14
+ if (bpf::bpfGetFdKeySize(fd) != keySize) {
+ close(fd);
+ jniThrowErrnoException(env, "nativeBpfFdGet KeySize", EBADFD);
+ return -1;
+ }
+ if (bpf::bpfGetFdValueSize(fd) != valueSize) {
+ close(fd);
+ jniThrowErrnoException(env, "nativeBpfFdGet ValueSize", EBADFD);
+ return -1;
+ }
+ }
return fd;
}
@@ -103,7 +122,7 @@
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "nativeBpfFdGet", "(Ljava/lang/String;I)I",
+ { "nativeBpfFdGet", "(Ljava/lang/String;III)I",
(void*) com_android_net_module_util_BpfMap_nativeBpfFdGet },
{ "nativeWriteToMapEntry", "(I[B[BI)V",
(void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry },