2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "SELinuxJNI"
18 #include <utils/Log.h>
22 #include "android_runtime/AndroidRuntime.h"
23 #include "selinux/selinux.h"
24 #include "selinux/android.h"
26 #include <ScopedLocalRef.h>
27 #include <ScopedUtfChars.h>
28 #include <UniquePtr.h>
32 struct SecurityContext_Delete {
33 void operator()(security_context_t p) const {
37 typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
39 static jboolean isSELinuxDisabled = true;
42 * Function: isSELinuxEnabled
43 * Purpose: checks whether SELinux is enabled/disbaled
45 * Return value : true (enabled) or false (disabled)
48 static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
49 return !isSELinuxDisabled;
53 * Function: isSELinuxEnforced
54 * Purpose: return the current SELinux enforce mode
56 * Return value: true (enforcing) or false (permissive)
59 static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
60 return (security_getenforce() == 1) ? true : false;
64 * Function: setSELinuxEnforce
65 * Purpose: set the SE Linux enforcing mode
66 * Parameters: true (enforcing) or false (permissive)
67 * Return value: true (success) or false (fail)
70 static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
71 if (isSELinuxDisabled) {
75 int enforce = value ? 1 : 0;
77 return (security_setenforce(enforce) != -1) ? true : false;
81 * Function: getPeerCon
82 * Purpose: retrieves security context of peer socket
84 * fileDescriptor: peer socket file as a FileDescriptor object
85 * Returns: jstring representing the security_context of socket or NULL if error
86 * Exceptions: NullPointerException if fileDescriptor object is NULL
88 static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
89 if (isSELinuxDisabled) {
93 if (fileDescriptor == NULL) {
94 jniThrowNullPointerException(env,
95 "Trying to check security context of a null peer socket.");
99 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
100 if (env->ExceptionOccurred() != NULL) {
101 ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
105 security_context_t tmp = NULL;
106 int ret = getpeercon(fd, &tmp);
107 Unique_SecurityContext context(tmp);
109 ScopedLocalRef<jstring> contextStr(env, NULL);
111 contextStr.reset(env->NewStringUTF(context.get()));
114 ALOGV("getPeerCon(%d) => %s", fd, context.get());
115 return contextStr.release();
119 * Function: setFSCreateCon
120 * Purpose: set security context used for creating a new file system object
122 * context: security_context_t representing the new context of a file system object,
123 * set to NULL to return to the default policy behavior
124 * Returns: true on success, false on error
127 static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
128 if (isSELinuxDisabled) {
132 UniquePtr<ScopedUtfChars> context;
133 const char* context_c_str = NULL;
134 if (contextStr != NULL) {
135 context.reset(new ScopedUtfChars(env, contextStr));
136 context_c_str = context->c_str();
137 if (context_c_str == NULL) {
142 int ret = setfscreatecon(const_cast<char *>(context_c_str));
144 ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
146 return (ret == 0) ? true : false;
150 * Function: setFileCon
151 * Purpose: set the security context of a file object
153 * path: the location of the file system object
154 * context: the new security context of the file system object
155 * Returns: true on success, false on error
156 * Exception: NullPointerException is thrown if either path or context strign are NULL
158 static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
159 if (isSELinuxDisabled) {
163 ScopedUtfChars path(env, pathStr);
164 if (path.c_str() == NULL) {
168 ScopedUtfChars context(env, contextStr);
169 if (context.c_str() == NULL) {
173 // GetStringUTFChars returns const char * yet setfilecon needs char *
174 char *tmp = const_cast<char *>(context.c_str());
175 int ret = setfilecon(path.c_str(), tmp);
177 ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
178 return (ret == 0) ? true : false;
182 * Function: getFileCon
183 * Purpose: retrieves the context associated with the given path in the file system
185 * path: given path in the file system
187 * string representing the security context string of the file object
188 * the string may be NULL if an error occured
189 * Exceptions: NullPointerException if the path object is null
191 static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
192 if (isSELinuxDisabled) {
196 ScopedUtfChars path(env, pathStr);
197 if (path.c_str() == NULL) {
201 security_context_t tmp = NULL;
202 int ret = getfilecon(path.c_str(), &tmp);
203 Unique_SecurityContext context(tmp);
205 ScopedLocalRef<jstring> securityString(env, NULL);
207 securityString.reset(env->NewStringUTF(context.get()));
210 ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
211 return securityString.release();
216 * Purpose: Get the context of the current process.
218 * Returns: a jstring representing the security context of the process,
219 * the jstring may be NULL if there was an error
222 static jstring getCon(JNIEnv *env, jobject) {
223 if (isSELinuxDisabled) {
227 security_context_t tmp = NULL;
228 int ret = getcon(&tmp);
229 Unique_SecurityContext context(tmp);
231 ScopedLocalRef<jstring> securityString(env, NULL);
233 securityString.reset(env->NewStringUTF(context.get()));
236 ALOGV("getCon() => %s", context.get());
237 return securityString.release();
241 * Function: getPidCon
242 * Purpose: Get the context of a process identified by its pid
244 * pid: a jint representing the process
245 * Returns: a jstring representing the security context of the pid,
246 * the jstring may be NULL if there was an error
249 static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
250 if (isSELinuxDisabled) {
254 security_context_t tmp = NULL;
255 int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
256 Unique_SecurityContext context(tmp);
258 ScopedLocalRef<jstring> securityString(env, NULL);
260 securityString.reset(env->NewStringUTF(context.get()));
263 ALOGV("getPidCon(%d) => %s", pid, context.get());
264 return securityString.release();
268 * Function: getBooleanNames
269 * Purpose: Gets a list of the SELinux boolean names.
271 * Returns: an array of strings containing the SELinux boolean names.
272 * returns NULL string on error
275 static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
276 if (isSELinuxDisabled) {
282 if (security_get_boolean_names(&list, &len) == -1) {
286 jclass stringClass = env->FindClass("java/lang/String");
287 jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL);
288 for (int i = 0; i < len; i++) {
289 ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i]));
290 env->SetObjectArrayElement(stringArray, i, obj.get());
299 * Function: getBooleanValue
300 * Purpose: Gets the value for the given SELinux boolean name.
302 * String: The name of the SELinux boolean.
303 * Returns: a boolean: (true) boolean is set or (false) it is not.
306 static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
307 if (isSELinuxDisabled) {
311 if (nameStr == NULL) {
315 ScopedUtfChars name(env, nameStr);
316 int ret = security_get_boolean_active(name.c_str());
318 ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
319 return (ret == 1) ? true : false;
323 * Function: setBooleanNames
324 * Purpose: Sets the value for the given SELinux boolean name.
326 * String: The name of the SELinux boolean.
327 * Boolean: The new value of the SELinux boolean.
328 * Returns: a boolean indicating whether or not the operation succeeded.
331 static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
332 if (isSELinuxDisabled) {
336 if (nameStr == NULL) {
340 ScopedUtfChars name(env, nameStr);
341 int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
346 if (security_commit_booleans() == -1) {
354 * Function: checkSELinuxAccess
355 * Purpose: Check permissions between two security contexts.
356 * Parameters: subjectContextStr: subject security context as a string
357 * objectContextStr: object security context as a string
358 * objectClassStr: object's security class name as a string
359 * permissionStr: permission name as a string
360 * Returns: boolean: (true) if permission was granted, (false) otherwise
363 static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
364 jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
365 if (isSELinuxDisabled) {
369 ScopedUtfChars subjectContext(env, subjectContextStr);
370 if (subjectContext.c_str() == NULL) {
374 ScopedUtfChars objectContext(env, objectContextStr);
375 if (objectContext.c_str() == NULL) {
379 ScopedUtfChars objectClass(env, objectClassStr);
380 if (objectClass.c_str() == NULL) {
384 ScopedUtfChars permission(env, permissionStr);
385 if (permission.c_str() == NULL) {
389 char *tmp1 = const_cast<char *>(subjectContext.c_str());
390 char *tmp2 = const_cast<char *>(objectContext.c_str());
391 int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
394 ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
395 objectClass.c_str(), permission.c_str(), accessGranted);
397 return (accessGranted == 0) ? true : false;
401 * Function: native_restorecon
402 * Purpose: restore default SELinux security context
403 * Parameters: pathname: the pathname for the file to be relabeled
404 * Returns: boolean: (true) file label successfully restored, (false) otherwise
407 static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
408 if (isSELinuxDisabled) {
412 ScopedUtfChars pathname(env, pathnameStr);
413 if (pathname.c_str() == NULL) {
414 ALOGV("restorecon(%p) => threw exception", pathname);
418 int ret = selinux_android_restorecon(pathname.c_str());
419 ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
426 static JNINativeMethod method_table[] = {
427 /* name, signature, funcPtr */
428 { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
429 { "getBooleanNames" , "()[Ljava/lang/String;" , (void*)getBooleanNames },
430 { "getBooleanValue" , "(Ljava/lang/String;)Z" , (void*)getBooleanValue },
431 { "getContext" , "()Ljava/lang/String;" , (void*)getCon },
432 { "getFileContext" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)getFileCon },
433 { "getPeerContext" , "(Ljava/io/FileDescriptor;)Ljava/lang/String;" , (void*)getPeerCon },
434 { "getPidContext" , "(I)Ljava/lang/String;" , (void*)getPidCon },
435 { "isSELinuxEnforced" , "()Z" , (void*)isSELinuxEnforced},
436 { "isSELinuxEnabled" , "()Z" , (void*)isSELinuxEnabled },
437 { "native_restorecon" , "(Ljava/lang/String;)Z" , (void*)native_restorecon},
438 { "setBooleanValue" , "(Ljava/lang/String;Z)Z" , (void*)setBooleanValue },
439 { "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon },
440 { "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon },
441 { "setSELinuxEnforce" , "(Z)Z" , (void*)setSELinuxEnforce},
444 static int log_callback(int type, const char *fmt, ...) {
447 LOG_PRI_VA(ANDROID_LOG_ERROR, "SELinux", fmt, ap);
452 int register_android_os_SELinux(JNIEnv *env) {
453 union selinux_callback cb;
454 cb.func_log = log_callback;
455 selinux_set_callback(SELINUX_CB_LOG, cb);
457 isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
459 return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
460 NELEM(method_table));