1 /*
2 * Copyright (C) 2017 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 <jni.h>
18 #include <nativehelper/JNIHelp.h>
19 #include <nativehelper/ScopedLocalRef.h>
20 #include <nativehelper/ScopedUtfChars.h>
21 #include <selinux/selinux.h>
22 #include <android/log.h>
23 #include <sys/socket.h>
24 #include <linux/netlink.h>
25 #include <linux/rtnetlink.h>
26 #include <memory>
27
28 struct SecurityContext_Delete {
operator ()SecurityContext_Delete29 void operator()(char* p) const {
30 freecon(p);
31 }
32 };
33 typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext;
34
35 /**
36 * Function: checkNetlinkRouteGetlink
37 * Purpose: Checks to see if RTM_GETLINK is allowed on a netlink route socket.
38 * Returns: 13 (expected) if RTM_GETLINK fails with permission denied.
39 * 0 if socket creation fails
40 * -1 if bind() succeeds.
41 */
checkNetlinkRouteGetlink()42 static jint checkNetlinkRouteGetlink() {
43 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
44 if (sock < 0) {
45 __android_log_print(ANDROID_LOG_ERROR, "SELLinuxTargetSdkTest", "socket creation failed.");
46 return 0;
47 }
48 struct NetlinkMessage {
49 nlmsghdr hdr;
50 rtgenmsg msg;
51 } request;
52 memset(&request, 0, sizeof(request));
53 request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
54 request.hdr.nlmsg_type = RTM_GETLINK;
55 request.hdr.nlmsg_len = sizeof(request);
56 request.msg.rtgen_family = AF_UNSPEC;
57
58 int ret = send(sock, &request, sizeof(request), 0);
59 if (ret < 0) {
60 return errno;
61 }
62
63 return -1;
64 }
65
66 /**
67 * Function: checkNetlinkRouteGetneigh
68 * Purpose: Checks to see if RTM_GETNEIGH{TBL} is allowed on a netlink route socket.
69 * Returns: 3 (expected) if RTM_GETNEIGH and RTM_GETNEIGHTBL both fail with permission denied.
70 * 1 if only RTM_GETNEIGH fails with permission denied.
71 * 2 if only RTM_GETNEIGHTBL fails with permission denied.
72 * 0 if both succeed.
73 * -1 if socket creation fails
74 */
checkNetlinkRouteGetneigh()75 static jint checkNetlinkRouteGetneigh() {
76 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
77 if (sock < 0)
78 {
79 __android_log_print(ANDROID_LOG_ERROR, "SELinuxTargetSdkTest", "socket creation failed.");
80 return -1;
81 }
82 struct NetlinkMessage
83 {
84 nlmsghdr hdr;
85 rtgenmsg msg;
86 } request;
87 memset(&request, 0, sizeof(request));
88 request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
89 request.hdr.nlmsg_len = sizeof(request);
90 request.msg.rtgen_family = AF_UNSPEC;
91
92 int return_value = 0;
93
94 request.hdr.nlmsg_type = RTM_GETNEIGH;
95 int ret = send(sock, &request, sizeof(request), 0);
96 if (ret < 0 && errno == 13)
97 {
98 return_value |= 1;
99 }
100
101 request.hdr.nlmsg_type = RTM_GETNEIGHTBL;
102 ret = send(sock, &request, sizeof(request), 0);
103 if (ret < 0 && errno == 13)
104 {
105 return_value |= 1 << 1;
106 }
107
108 return return_value;
109 }
110
111 /**
112 * Function: checkNetlinkRouteBind
113 * Purpose: Checks to see if bind() is allowed on a netlink route socket.
114 * Returns: 13 (expected) if bind() fails with permission denied.
115 * 0 if socket creation fails
116 * -1 if bind() succeeds.
117 */
checkNetlinkRouteBind()118 static jint checkNetlinkRouteBind() {
119 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
120 if (sock < 0) {
121 __android_log_print(ANDROID_LOG_ERROR, "SELLinuxTargetSdkTest", "socket creation failed.");
122 return 0;
123 }
124
125 struct sockaddr_nl addr;
126 addr.nl_family = AF_NETLINK;
127 addr.nl_pid = getpid();
128 addr.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR;
129
130 int ret = bind(sock,(struct sockaddr *)&addr,sizeof(addr));
131 if (ret < 0) {
132 return errno;
133 }
134
135 return -1;
136 }
137
138 /*
139 * Function: getFileContext
140 * Purpose: retrieves the context associated with the given path in the file system
141 * Parameters:
142 * path: given path in the file system
143 * Returns:
144 * string representing the security context string of the file object
145 * the string may be NULL if an error occured
146 * Exceptions: NullPointerException if the path object is null
147 */
getFileContext(JNIEnv * env,jobject,jstring pathStr)148 static jstring getFileContext(JNIEnv *env, jobject, jstring pathStr) {
149 ScopedUtfChars path(env, pathStr);
150 if (path.c_str() == NULL) {
151 return NULL;
152 }
153
154 char* tmp = NULL;
155 int ret = getfilecon(path.c_str(), &tmp);
156 Unique_SecurityContext context(tmp);
157
158 ScopedLocalRef<jstring> securityString(env, NULL);
159 if (ret != -1) {
160 securityString.reset(env->NewStringUTF(context.get()));
161 }
162
163 return securityString.release();
164 }
165
166 static JNINativeMethod gMethods[] = {
167 { "getFileContext", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getFileContext },
168 { "checkNetlinkRouteBind", "()I", (void*) checkNetlinkRouteBind },
169 { "checkNetlinkRouteGetlink", "()I", (void*) checkNetlinkRouteGetlink },
170 { "checkNetlinkRouteGetneigh", "()I", (void*) checkNetlinkRouteGetneigh },
171 };
172
register_android_security_SELinuxTargetSdkTest(JNIEnv * env)173 int register_android_security_SELinuxTargetSdkTest(JNIEnv* env)
174 {
175 jclass clazz = env->FindClass("android/security/SELinuxTargetSdkTestBase");
176
177 return env->RegisterNatives(clazz, gMethods,
178 sizeof(gMethods) / sizeof(JNINativeMethod));
179 }
180