Merge "verify java map key/value struct size matches file descriptor"

This commit is contained in:
Maciej Żenczykowski
2022-12-22 10:57:40 +00:00
committed by Gerrit Code Review
5 changed files with 81 additions and 31 deletions

View File

@@ -67,8 +67,10 @@ public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V>
private static ConcurrentHashMap<Pair<String, Integer>, ParcelFileDescriptor> sFdCache = private static ConcurrentHashMap<Pair<String, Integer>, ParcelFileDescriptor> sFdCache =
new ConcurrentHashMap<>(); 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 { throws ErrnoException, NullPointerException {
// TODO: key should include keySize & valueSize, but really we should match specific types
Pair<String, Integer> key = Pair.create(path, mode); Pair<String, Integer> key = Pair.create(path, mode);
// unlocked fetch is safe: map is concurrent read capable, and only inserted into // unlocked fetch is safe: map is concurrent read capable, and only inserted into
ParcelFileDescriptor fd = sFdCache.get(key); ParcelFileDescriptor fd = sFdCache.get(key);
@@ -79,7 +81,7 @@ public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V>
fd = sFdCache.get(key); fd = sFdCache.get(key);
if (fd != null) return fd; if (fd != null) return fd;
// okay, we really haven't opened this before... // 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); sFdCache.put(key, fd);
return fd; return fd;
} }
@@ -94,11 +96,11 @@ public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V>
*/ */
public BpfMap(@NonNull final String path, final int flag, final Class<K> key, public BpfMap(@NonNull final String path, final int flag, final Class<K> key,
final Class<V> value) throws ErrnoException, NullPointerException { final Class<V> value) throws ErrnoException, NullPointerException {
mMapFd = cachedBpfFdGet(path, flag);
mKeyClass = key; mKeyClass = key;
mValueClass = value; mValueClass = value;
mKeySize = Struct.getSize(key); mKeySize = Struct.getSize(key);
mValueSize = Struct.getSize(value); mValueSize = Struct.getSize(value);
mMapFd = cachedBpfFdGet(path, flag, mKeySize, mValueSize);
} }
/** /**
@@ -295,7 +297,7 @@ public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V>
} }
} }
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; throws ErrnoException, NullPointerException;
// Note: the following methods appear to not require the object by virtue of taking the // Note: the following methods appear to not require the object by virtue of taking the

View File

@@ -16,6 +16,7 @@
#pragma once #pragma once
#include <errno.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/pfkeyv2.h> #include <linux/pfkeyv2.h>
#include <net/if.h> #include <net/if.h>
@@ -25,9 +26,10 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <android-base/unique_fd.h>
#include <log/log.h> #include <log/log.h>
#include "KernelVersion.h"
namespace android { namespace android {
namespace bpf { namespace bpf {
@@ -84,27 +86,5 @@ static inline int setrlimitForTest() {
return res; 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 bpf
} // namespace android } // namespace android

View File

@@ -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

View File

@@ -23,7 +23,7 @@ cc_library_static {
"com_android_net_module_util_TcUtils.cpp", "com_android_net_module_util_TcUtils.cpp",
], ],
header_libs: [ header_libs: [
"bpf_syscall_wrappers", "bpf_headers",
"jni_headers", "jni_headers",
], ],
shared_libs: [ shared_libs: [

View File

@@ -25,15 +25,34 @@
#define BPF_FD_JUST_USE_INT #define BPF_FD_JUST_USE_INT
#include "BpfSyscallWrappers.h" #include "BpfSyscallWrappers.h"
#include "bpf/KernelVersion.h"
namespace android { namespace android {
static jint com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv *env, jclass clazz, 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); ScopedUtfChars pathname(env, path);
jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast<unsigned>(mode)); 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; return fd;
} }
@@ -103,7 +122,7 @@ static jboolean com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv *en
*/ */
static const JNINativeMethod gMethods[] = { static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */ /* name, signature, funcPtr */
{ "nativeBpfFdGet", "(Ljava/lang/String;I)I", { "nativeBpfFdGet", "(Ljava/lang/String;III)I",
(void*) com_android_net_module_util_BpfMap_nativeBpfFdGet }, (void*) com_android_net_module_util_BpfMap_nativeBpfFdGet },
{ "nativeWriteToMapEntry", "(I[B[BI)V", { "nativeWriteToMapEntry", "(I[B[BI)V",
(void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry }, (void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry },