• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <errno.h>
18 #include <jni.h>
19 #include <nativehelper/JNIHelp.h>
20 #include <nativehelper/ScopedLocalRef.h>
21 
22 #include "nativehelper/scoped_primitive_array.h"
23 #include "nativehelper/scoped_utf_chars.h"
24 
25 #define BPF_FD_JUST_USE_INT
26 #include "BpfSyscallWrappers.h"
27 
28 #include "bpf/KernelUtils.h"
29 
30 namespace android {
31 
com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv * env,jclass clazz,jstring path,jint mode,jint keySize,jint valueSize)32 static jint com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv *env, jclass clazz,
33         jstring path, jint mode, jint keySize, jint valueSize) {
34     ScopedUtfChars pathname(env, path);
35 
36     jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast<unsigned>(mode));
37 
38     if (fd < 0) {
39         jniThrowErrnoException(env, "nativeBpfFdGet", errno);
40         return -1;
41     }
42 
43     if (bpf::isAtLeastKernelVersion(4, 14, 0)) {
44         // These likely fail with -1 and set errno to EINVAL on <4.14
45         if (bpf::bpfGetFdKeySize(fd) != keySize) {
46             close(fd);
47             jniThrowErrnoException(env, "nativeBpfFdGet KeySize", EBADFD);
48             return -1;
49         }
50         if (bpf::bpfGetFdValueSize(fd) != valueSize) {
51             close(fd);
52             jniThrowErrnoException(env, "nativeBpfFdGet ValueSize", EBADFD);
53             return -1;
54         }
55     }
56 
57     return fd;
58 }
59 
com_android_net_module_util_BpfMap_nativeWriteToMapEntry(JNIEnv * env,jobject self,jint fd,jbyteArray key,jbyteArray value,jint flags)60 static void com_android_net_module_util_BpfMap_nativeWriteToMapEntry(JNIEnv *env, jobject self,
61         jint fd, jbyteArray key, jbyteArray value, jint flags) {
62     ScopedByteArrayRO keyRO(env, key);
63     ScopedByteArrayRO valueRO(env, value);
64 
65     int ret = bpf::writeToMapEntry(static_cast<int>(fd), keyRO.get(), valueRO.get(),
66             static_cast<int>(flags));
67 
68     if (ret) jniThrowErrnoException(env, "nativeWriteToMapEntry", errno);
69 }
70 
throwIfNotEnoent(JNIEnv * env,const char * functionName,int ret,int err)71 static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, int err) {
72     if (ret == 0) return true;
73 
74     if (err != ENOENT) jniThrowErrnoException(env, functionName, err);
75     return false;
76 }
77 
com_android_net_module_util_BpfMap_nativeDeleteMapEntry(JNIEnv * env,jobject self,jint fd,jbyteArray key)78 static jboolean com_android_net_module_util_BpfMap_nativeDeleteMapEntry(JNIEnv *env, jobject self,
79         jint fd, jbyteArray key) {
80     ScopedByteArrayRO keyRO(env, key);
81 
82     // On success, zero is returned.  If the element is not found, -1 is returned and errno is set
83     // to ENOENT.
84     int ret = bpf::deleteMapEntry(static_cast<int>(fd), keyRO.get());
85 
86     return throwIfNotEnoent(env, "nativeDeleteMapEntry", ret, errno);
87 }
88 
com_android_net_module_util_BpfMap_nativeGetNextMapKey(JNIEnv * env,jobject self,jint fd,jbyteArray key,jbyteArray nextKey)89 static jboolean com_android_net_module_util_BpfMap_nativeGetNextMapKey(JNIEnv *env, jobject self,
90         jint fd, jbyteArray key, jbyteArray nextKey) {
91     // If key is found, the operation returns zero and sets the next key pointer to the key of the
92     // next element.  If key is not found, the operation returns zero and sets the next key pointer
93     // to the key of the first element.  If key is the last element, -1 is returned and errno is
94     // set to ENOENT.  Other possible errno values are ENOMEM, EFAULT, EPERM, and EINVAL.
95     ScopedByteArrayRW nextKeyRW(env, nextKey);
96     int ret;
97     if (key == nullptr) {
98         // Called by getFirstKey. Find the first key in the map.
99         ret = bpf::getNextMapKey(static_cast<int>(fd), nullptr, nextKeyRW.get());
100     } else {
101         ScopedByteArrayRO keyRO(env, key);
102         ret = bpf::getNextMapKey(static_cast<int>(fd), keyRO.get(), nextKeyRW.get());
103     }
104 
105     return throwIfNotEnoent(env, "nativeGetNextMapKey", ret, errno);
106 }
107 
com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv * env,jobject self,jint fd,jbyteArray key,jbyteArray value)108 static jboolean com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv *env, jobject self,
109         jint fd, jbyteArray key, jbyteArray value) {
110     ScopedByteArrayRO keyRO(env, key);
111     ScopedByteArrayRW valueRW(env, value);
112 
113     // If an element is found, the operation returns zero and stores the element's value into
114     // "value".  If no element is found, the operation returns -1 and sets errno to ENOENT.
115     int ret = bpf::findMapEntry(static_cast<int>(fd), keyRO.get(), valueRW.get());
116 
117     return throwIfNotEnoent(env, "nativeFindMapEntry", ret, errno);
118 }
119 
120 /*
121  * JNI registration.
122  */
123 static const JNINativeMethod gMethods[] = {
124     /* name, signature, funcPtr */
125     { "nativeBpfFdGet", "(Ljava/lang/String;III)I",
126         (void*) com_android_net_module_util_BpfMap_nativeBpfFdGet },
127     { "nativeWriteToMapEntry", "(I[B[BI)V",
128         (void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry },
129     { "nativeDeleteMapEntry", "(I[B)Z",
130         (void*) com_android_net_module_util_BpfMap_nativeDeleteMapEntry },
131     { "nativeGetNextMapKey", "(I[B[B)Z",
132         (void*) com_android_net_module_util_BpfMap_nativeGetNextMapKey },
133     { "nativeFindMapEntry", "(I[B[B)Z",
134         (void*) com_android_net_module_util_BpfMap_nativeFindMapEntry },
135 
136 };
137 
register_com_android_net_module_util_BpfMap(JNIEnv * env,char const * class_name)138 int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name) {
139     return jniRegisterNativeMethods(env,
140             class_name,
141             gMethods, NELEM(gMethods));
142 }
143 
144 }; // namespace android
145