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/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 },