blob: 8ba77aed1d0444551f4bb372c62ec6a84a5f5cc2 [file] [log] [blame]
rpcraig554cb0c2012-07-05 06:41:43 -04001/*
2 * Copyright (C) 2012 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
Stephen Smalleyc07fca32012-01-13 08:31:39 -050017#define LOG_TAG "SELinuxJNI"
18#include <utils/Log.h>
19
20#include "JNIHelp.h"
21#include "jni.h"
Andreas Gampeed6b9df2014-11-20 22:02:20 -080022#include "core_jni_helpers.h"
Stephen Smalleyc07fca32012-01-13 08:31:39 -050023#include "selinux/selinux.h"
rpcraig554cb0c2012-07-05 06:41:43 -040024#include "selinux/android.h"
Stephen Smalleyc07fca32012-01-13 08:31:39 -050025#include <errno.h>
Kenny Rootcd19e3f2012-10-19 14:15:26 -070026#include <ScopedLocalRef.h>
27#include <ScopedUtfChars.h>
28#include <UniquePtr.h>
Stephen Smalleyc07fca32012-01-13 08:31:39 -050029
30namespace android {
31
Kenny Rootcd19e3f2012-10-19 14:15:26 -070032struct SecurityContext_Delete {
33 void operator()(security_context_t p) const {
34 freecon(p);
35 }
36};
37typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
Stephen Smalleyc07fca32012-01-13 08:31:39 -050038
Kenny Rootcd19e3f2012-10-19 14:15:26 -070039static jboolean isSELinuxDisabled = true;
Stephen Smalleyc07fca32012-01-13 08:31:39 -050040
Kenny Rootcd19e3f2012-10-19 14:15:26 -070041/*
42 * Function: isSELinuxEnabled
43 * Purpose: checks whether SELinux is enabled/disbaled
44 * Parameters: none
45 * Return value : true (enabled) or false (disabled)
46 * Exceptions: none
47 */
48static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
Stephen Smalleyc07fca32012-01-13 08:31:39 -050049 return !isSELinuxDisabled;
Kenny Rootcd19e3f2012-10-19 14:15:26 -070050}
Stephen Smalleyc07fca32012-01-13 08:31:39 -050051
Kenny Rootcd19e3f2012-10-19 14:15:26 -070052/*
53 * Function: isSELinuxEnforced
54 * Purpose: return the current SELinux enforce mode
55 * Parameters: none
56 * Return value: true (enforcing) or false (permissive)
57 * Exceptions: none
58 */
59static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
Stephen Smalleyc07fca32012-01-13 08:31:39 -050060 return (security_getenforce() == 1) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -070061}
Stephen Smalleyc07fca32012-01-13 08:31:39 -050062
Kenny Rootcd19e3f2012-10-19 14:15:26 -070063/*
Kenny Rootcd19e3f2012-10-19 14:15:26 -070064 * Function: getPeerCon
65 * Purpose: retrieves security context of peer socket
66 * Parameters:
67 * fileDescriptor: peer socket file as a FileDescriptor object
68 * Returns: jstring representing the security_context of socket or NULL if error
69 * Exceptions: NullPointerException if fileDescriptor object is NULL
70 */
71static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
72 if (isSELinuxDisabled) {
73 return NULL;
74 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -050075
76 if (fileDescriptor == NULL) {
Kenny Rootcd19e3f2012-10-19 14:15:26 -070077 jniThrowNullPointerException(env,
78 "Trying to check security context of a null peer socket.");
79 return NULL;
Stephen Smalleyc07fca32012-01-13 08:31:39 -050080 }
81
Stephen Smalleyc07fca32012-01-13 08:31:39 -050082 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
Mathieu Chartier98671c32014-08-20 10:04:08 -070083 if (env->ExceptionCheck()) {
Kenny Rootcd19e3f2012-10-19 14:15:26 -070084 ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
85 return NULL;
Stephen Smalleyc07fca32012-01-13 08:31:39 -050086 }
87
Richard Haines81ad2842013-05-22 15:12:16 +010088 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -070089 int ret = getpeercon(fd, &tmp);
90 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -050091
Kenny Rootcd19e3f2012-10-19 14:15:26 -070092 ScopedLocalRef<jstring> contextStr(env, NULL);
93 if (ret != -1) {
94 contextStr.reset(env->NewStringUTF(context.get()));
Stephen Smalleyc07fca32012-01-13 08:31:39 -050095 }
96
Richard Haines81ad2842013-05-22 15:12:16 +010097 ALOGV("getPeerCon(%d) => %s", fd, context.get());
Kenny Rootcd19e3f2012-10-19 14:15:26 -070098 return contextStr.release();
99}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500100
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700101/*
102 * Function: setFSCreateCon
103 * Purpose: set security context used for creating a new file system object
104 * Parameters:
105 * context: security_context_t representing the new context of a file system object,
106 * set to NULL to return to the default policy behavior
107 * Returns: true on success, false on error
108 * Exception: none
109 */
110static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
111 if (isSELinuxDisabled) {
112 return false;
113 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500114
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700115 UniquePtr<ScopedUtfChars> context;
116 const char* context_c_str = NULL;
117 if (contextStr != NULL) {
118 context.reset(new ScopedUtfChars(env, contextStr));
119 context_c_str = context->c_str();
120 if (context_c_str == NULL) {
121 return false;
122 }
123 }
124
125 int ret = setfscreatecon(const_cast<char *>(context_c_str));
126
127 ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500128
129 return (ret == 0) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700130}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500131
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700132/*
133 * Function: setFileCon
134 * Purpose: set the security context of a file object
135 * Parameters:
136 * path: the location of the file system object
137 * context: the new security context of the file system object
138 * Returns: true on success, false on error
139 * Exception: NullPointerException is thrown if either path or context strign are NULL
140 */
141static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
142 if (isSELinuxDisabled) {
143 return false;
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500144 }
145
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700146 ScopedUtfChars path(env, pathStr);
147 if (path.c_str() == NULL) {
148 return false;
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500149 }
150
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700151 ScopedUtfChars context(env, contextStr);
152 if (context.c_str() == NULL) {
153 return false;
154 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500155
156 // GetStringUTFChars returns const char * yet setfilecon needs char *
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700157 char *tmp = const_cast<char *>(context.c_str());
158 int ret = setfilecon(path.c_str(), tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500159
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700160 ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500161 return (ret == 0) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700162}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500163
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700164/*
165 * Function: getFileCon
166 * Purpose: retrieves the context associated with the given path in the file system
167 * Parameters:
168 * path: given path in the file system
169 * Returns:
170 * string representing the security context string of the file object
171 * the string may be NULL if an error occured
172 * Exceptions: NullPointerException if the path object is null
173 */
174static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
175 if (isSELinuxDisabled) {
176 return NULL;
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500177 }
178
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700179 ScopedUtfChars path(env, pathStr);
180 if (path.c_str() == NULL) {
181 return NULL;
182 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500183
Richard Haines81ad2842013-05-22 15:12:16 +0100184 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700185 int ret = getfilecon(path.c_str(), &tmp);
186 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500187
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700188 ScopedLocalRef<jstring> securityString(env, NULL);
189 if (ret != -1) {
190 securityString.reset(env->NewStringUTF(context.get()));
191 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500192
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700193 ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
194 return securityString.release();
195}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500196
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700197/*
198 * Function: getCon
199 * Purpose: Get the context of the current process.
200 * Parameters: none
201 * Returns: a jstring representing the security context of the process,
202 * the jstring may be NULL if there was an error
203 * Exceptions: none
204 */
205static jstring getCon(JNIEnv *env, jobject) {
206 if (isSELinuxDisabled) {
207 return NULL;
208 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500209
Richard Haines81ad2842013-05-22 15:12:16 +0100210 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700211 int ret = getcon(&tmp);
212 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500213
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700214 ScopedLocalRef<jstring> securityString(env, NULL);
215 if (ret != -1) {
216 securityString.reset(env->NewStringUTF(context.get()));
217 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500218
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700219 ALOGV("getCon() => %s", context.get());
220 return securityString.release();
221}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500222
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700223/*
224 * Function: getPidCon
225 * Purpose: Get the context of a process identified by its pid
226 * Parameters:
227 * pid: a jint representing the process
228 * Returns: a jstring representing the security context of the pid,
229 * the jstring may be NULL if there was an error
230 * Exceptions: none
231 */
232static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
233 if (isSELinuxDisabled) {
234 return NULL;
235 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500236
Richard Haines81ad2842013-05-22 15:12:16 +0100237 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700238 int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
239 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500240
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700241 ScopedLocalRef<jstring> securityString(env, NULL);
242 if (ret != -1) {
243 securityString.reset(env->NewStringUTF(context.get()));
244 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500245
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700246 ALOGV("getPidCon(%d) => %s", pid, context.get());
247 return securityString.release();
248}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500249
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700250/*
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700251 * Function: checkSELinuxAccess
252 * Purpose: Check permissions between two security contexts.
253 * Parameters: subjectContextStr: subject security context as a string
254 * objectContextStr: object security context as a string
255 * objectClassStr: object's security class name as a string
256 * permissionStr: permission name as a string
257 * Returns: boolean: (true) if permission was granted, (false) otherwise
258 * Exceptions: None
259 */
260static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
261 jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
262 if (isSELinuxDisabled) {
263 return true;
264 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500265
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700266 ScopedUtfChars subjectContext(env, subjectContextStr);
267 if (subjectContext.c_str() == NULL) {
268 return false;
269 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500270
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700271 ScopedUtfChars objectContext(env, objectContextStr);
272 if (objectContext.c_str() == NULL) {
273 return false;
274 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500275
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700276 ScopedUtfChars objectClass(env, objectClassStr);
277 if (objectClass.c_str() == NULL) {
278 return false;
279 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500280
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700281 ScopedUtfChars permission(env, permissionStr);
282 if (permission.c_str() == NULL) {
283 return false;
284 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500285
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700286 char *tmp1 = const_cast<char *>(subjectContext.c_str());
287 char *tmp2 = const_cast<char *>(objectContext.c_str());
288 int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
289 NULL);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500290
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700291 ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
292 objectClass.c_str(), permission.c_str(), accessGranted);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500293
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500294 return (accessGranted == 0) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700295}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500296
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700297/*
298 * Function: native_restorecon
299 * Purpose: restore default SELinux security context
300 * Parameters: pathname: the pathname for the file to be relabeled
301 * Returns: boolean: (true) file label successfully restored, (false) otherwise
302 * Exceptions: none
303 */
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700304static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jint flags) {
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700305 if (isSELinuxDisabled) {
306 return true;
307 }
rpcraig554cb0c2012-07-05 06:41:43 -0400308
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700309 ScopedUtfChars pathname(env, pathnameStr);
310 if (pathname.c_str() == NULL) {
Colin Crossd0696952014-02-06 20:17:48 -0800311 ALOGV("restorecon(%p) => threw exception", pathnameStr);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700312 return false;
313 }
314
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700315 int ret = selinux_android_restorecon(pathname.c_str(), flags);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700316 ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
rpcraig554cb0c2012-07-05 06:41:43 -0400317 return (ret == 0);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700318}
rpcraig554cb0c2012-07-05 06:41:43 -0400319
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700320/*
321 * JNI registration.
322 */
Daniel Micay76f6a862015-09-19 17:31:01 -0400323static const JNINativeMethod method_table[] = {
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500324 /* name, signature, funcPtr */
325 { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500326 { "getContext" , "()Ljava/lang/String;" , (void*)getCon },
327 { "getFileContext" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)getFileCon },
328 { "getPeerContext" , "(Ljava/io/FileDescriptor;)Ljava/lang/String;" , (void*)getPeerCon },
329 { "getPidContext" , "(I)Ljava/lang/String;" , (void*)getPidCon },
330 { "isSELinuxEnforced" , "()Z" , (void*)isSELinuxEnforced},
331 { "isSELinuxEnabled" , "()Z" , (void*)isSELinuxEnabled },
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700332 { "native_restorecon" , "(Ljava/lang/String;I)Z" , (void*)native_restorecon},
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500333 { "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon },
334 { "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon },
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700335};
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500336
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700337static int log_callback(int type, const char *fmt, ...) {
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500338 va_list ap;
Stephen Smalleye0dda3c2014-01-29 12:55:58 -0500339 int priority;
340
341 switch (type) {
342 case SELINUX_WARNING:
343 priority = ANDROID_LOG_WARN;
344 break;
345 case SELINUX_INFO:
346 priority = ANDROID_LOG_INFO;
347 break;
348 default:
349 priority = ANDROID_LOG_ERROR;
350 break;
351 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500352 va_start(ap, fmt);
Stephen Smalleye0dda3c2014-01-29 12:55:58 -0500353 LOG_PRI_VA(priority, "SELinux", fmt, ap);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500354 va_end(ap);
355 return 0;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700356}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500357
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700358int register_android_os_SELinux(JNIEnv *env) {
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500359 union selinux_callback cb;
360 cb.func_log = log_callback;
361 selinux_set_callback(SELINUX_CB_LOG, cb);
362
363 isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
364
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800365 return RegisterMethodsOrDie(env, "android/os/SELinux", method_table, NELEM(method_table));
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700366}
367
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500368}