1 /*
2  * Copyright (C) 2013 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 <selinux/selinux.h>
19 #include <JNIHelp.h>
20 #include <ScopedLocalRef.h>
21 #include <ScopedUtfChars.h>
22 #include <UniquePtr.h>
23 
24 struct SecurityContext_Delete {
operator ()SecurityContext_Delete25     void operator()(security_context_t p) const {
26         freecon(p);
27     }
28 };
29 typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
30 
31 /*
32  * Function: checkSELinuxAccess
33  * Purpose: Check permissions between two security contexts.
34  * Parameters: subjectContextStr: subject security context as a string
35  *             objectContextStr: object security context as a string
36  *             objectClassStr: object's security class name as a string
37  *             permissionStr: permission name as a string
38  * Returns: boolean: (true) if permission was granted, (false) otherwise
39  * Exceptions: NullPointerException if any argument is NULL
40  */
android_security_cts_SELinuxTest_checkSELinuxAccess(JNIEnv * env,jobject,jstring subjectContextStr,jstring objectContextStr,jstring objectClassStr,jstring permissionStr,jstring auxStr)41 static jboolean android_security_cts_SELinuxTest_checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
42         jstring objectContextStr, jstring objectClassStr, jstring permissionStr, jstring auxStr) {
43     if (subjectContextStr == NULL || objectContextStr == NULL || objectClassStr == NULL
44             || permissionStr == NULL || auxStr == NULL) {
45         jniThrowNullPointerException(env, NULL);
46         return false;
47     }
48 
49     ScopedUtfChars subjectContext(env, subjectContextStr);
50     ScopedUtfChars objectContext(env, objectContextStr);
51     ScopedUtfChars objectClass(env, objectClassStr);
52     ScopedUtfChars permission(env, permissionStr);
53     ScopedUtfChars aux(env, auxStr);
54 
55     char *tmp1 = const_cast<char *>(subjectContext.c_str());
56     char *tmp2 = const_cast<char *>(objectContext.c_str());
57     char *tmp3 = const_cast<char *>(aux.c_str());
58     int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(), tmp3);
59     return (accessGranted == 0) ? true : false;
60 }
61 
android_security_cts_SELinuxTest_checkSELinuxContext(JNIEnv * env,jobject,jstring contextStr)62 static jboolean android_security_cts_SELinuxTest_checkSELinuxContext(JNIEnv *env, jobject, jstring contextStr) {
63     if (contextStr == NULL) {
64         jniThrowNullPointerException(env, NULL);
65         return false;
66     }
67 
68     ScopedUtfChars context(env, contextStr);
69 
70     char *tmp = const_cast<char *>(context.c_str());
71     int validContext = security_check_context(tmp);
72     return (validContext == 0) ? true : false;
73 }
74 
75 /*
76  * Function: getFileContext
77  * Purpose: retrieves the context associated with the given path in the file system
78  * Parameters:
79  *        path: given path in the file system
80  * Returns:
81  *        string representing the security context string of the file object
82  *        the string may be NULL if an error occured
83  * Exceptions: NullPointerException if the path object is null
84  */
getFileContext(JNIEnv * env,jobject,jstring pathStr)85 static jstring getFileContext(JNIEnv *env, jobject, jstring pathStr) {
86     ScopedUtfChars path(env, pathStr);
87     if (path.c_str() == NULL) {
88         return NULL;
89     }
90 
91     security_context_t tmp = NULL;
92     int ret = getfilecon(path.c_str(), &tmp);
93     Unique_SecurityContext context(tmp);
94 
95     ScopedLocalRef<jstring> securityString(env, NULL);
96     if (ret != -1) {
97         securityString.reset(env->NewStringUTF(context.get()));
98     }
99 
100     return securityString.release();
101 }
102 
103 static JNINativeMethod gMethods[] = {
104     {  "checkSELinuxAccess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
105             (void *) android_security_cts_SELinuxTest_checkSELinuxAccess },
106     {  "checkSELinuxContext", "(Ljava/lang/String;)Z",
107             (void *) android_security_cts_SELinuxTest_checkSELinuxContext },
108     { "getFileContext", "(Ljava/lang/String;)Ljava/lang/String;",
109             (void*) getFileContext },
110 };
111 
log_callback(int type,const char * fmt,...)112 static int log_callback(int type __attribute__((unused)), const char *fmt __attribute__((unused)), ...)
113 {
114     /* do nothing - silence the avc denials */
115     return 0;
116 }
117 
register_android_security_cts_SELinuxTest(JNIEnv * env)118 int register_android_security_cts_SELinuxTest(JNIEnv* env)
119 {
120     jclass clazz = env->FindClass("android/security/cts/SELinuxTest");
121     union selinux_callback cb;
122     cb.func_log = log_callback;
123     selinux_set_callback(SELINUX_CB_LOG, cb);
124 
125     return env->RegisterNatives(clazz, gMethods,
126             sizeof(gMethods) / sizeof(JNINativeMethod));
127 }
128