OSDN Git Service

Bluetooth: Check descriptors size in BluetoothHidDeviceAppSdpSettings
[android-x86/frameworks-base.git] / core / jni / android_os_SELinux.cpp
1 /*
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
17 #define LOG_TAG "SELinuxJNI"
18 #include <utils/Log.h>
19
20 #include <nativehelper/JNIHelp.h>
21 #include "jni.h"
22 #include "core_jni_helpers.h"
23 #include "selinux/selinux.h"
24 #include "selinux/android.h"
25 #include <errno.h>
26 #include <memory>
27 #include <nativehelper/ScopedLocalRef.h>
28 #include <nativehelper/ScopedUtfChars.h>
29
30 namespace android {
31
32 struct SecurityContext_Delete {
33     void operator()(security_context_t p) const {
34         freecon(p);
35     }
36 };
37 typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext;
38
39 static jboolean isSELinuxDisabled = true;
40
41 /*
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  */
48 static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
49     return !isSELinuxDisabled;
50 }
51
52 /*
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  */
59 static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
60     return (security_getenforce() == 1) ? true : false;
61 }
62
63 /*
64  * 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  */
71 static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
72     if (isSELinuxDisabled) {
73         return NULL;
74     }
75
76     if (fileDescriptor == NULL) {
77         jniThrowNullPointerException(env,
78                 "Trying to check security context of a null peer socket.");
79         return NULL;
80     }
81
82     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
83     if (env->ExceptionCheck()) {
84         ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
85         return NULL;
86     }
87
88     security_context_t tmp = NULL;
89     int ret = getpeercon(fd, &tmp);
90     Unique_SecurityContext context(tmp);
91
92     ScopedLocalRef<jstring> contextStr(env, NULL);
93     if (ret != -1) {
94         contextStr.reset(env->NewStringUTF(context.get()));
95     }
96
97     ALOGV("getPeerCon(%d) => %s", fd, context.get());
98     return contextStr.release();
99 }
100
101 /*
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  */
110 static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
111     if (isSELinuxDisabled) {
112         return false;
113     }
114
115     std::unique_ptr<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);
128
129     return (ret == 0) ? true : false;
130 }
131
132 /*
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  */
141 static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
142     if (isSELinuxDisabled) {
143         return false;
144     }
145
146     ScopedUtfChars path(env, pathStr);
147     if (path.c_str() == NULL) {
148         return false;
149     }
150
151     ScopedUtfChars context(env, contextStr);
152     if (context.c_str() == NULL) {
153         return false;
154     }
155
156     // GetStringUTFChars returns const char * yet setfilecon needs char *
157     char *tmp = const_cast<char *>(context.c_str());
158     int ret = setfilecon(path.c_str(), tmp);
159
160     ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
161     return (ret == 0) ? true : false;
162 }
163
164 /*
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  */
174 static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
175     if (isSELinuxDisabled) {
176         return NULL;
177     }
178
179     ScopedUtfChars path(env, pathStr);
180     if (path.c_str() == NULL) {
181         return NULL;
182     }
183
184     security_context_t tmp = NULL;
185     int ret = getfilecon(path.c_str(), &tmp);
186     Unique_SecurityContext context(tmp);
187
188     ScopedLocalRef<jstring> securityString(env, NULL);
189     if (ret != -1) {
190         securityString.reset(env->NewStringUTF(context.get()));
191     }
192
193     ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
194     return securityString.release();
195 }
196
197 /*
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  */
205 static jstring getCon(JNIEnv *env, jobject) {
206     if (isSELinuxDisabled) {
207         return NULL;
208     }
209
210     security_context_t tmp = NULL;
211     int ret = getcon(&tmp);
212     Unique_SecurityContext context(tmp);
213
214     ScopedLocalRef<jstring> securityString(env, NULL);
215     if (ret != -1) {
216         securityString.reset(env->NewStringUTF(context.get()));
217     }
218
219     ALOGV("getCon() => %s", context.get());
220     return securityString.release();
221 }
222
223 /*
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  */
232 static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
233     if (isSELinuxDisabled) {
234         return NULL;
235     }
236
237     security_context_t tmp = NULL;
238     int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
239     Unique_SecurityContext context(tmp);
240
241     ScopedLocalRef<jstring> securityString(env, NULL);
242     if (ret != -1) {
243         securityString.reset(env->NewStringUTF(context.get()));
244     }
245
246     ALOGV("getPidCon(%d) => %s", pid, context.get());
247     return securityString.release();
248 }
249
250 /*
251  * 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  */
260 static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
261         jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
262     if (isSELinuxDisabled) {
263         return true;
264     }
265
266     ScopedUtfChars subjectContext(env, subjectContextStr);
267     if (subjectContext.c_str() == NULL) {
268         return false;
269     }
270
271     ScopedUtfChars objectContext(env, objectContextStr);
272     if (objectContext.c_str() == NULL) {
273         return false;
274     }
275
276     ScopedUtfChars objectClass(env, objectClassStr);
277     if (objectClass.c_str() == NULL) {
278         return false;
279     }
280
281     ScopedUtfChars permission(env, permissionStr);
282     if (permission.c_str() == NULL) {
283         return false;
284     }
285
286     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);
290
291     ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
292             objectClass.c_str(), permission.c_str(), accessGranted);
293
294     return (accessGranted == 0) ? true : false;
295 }
296
297 /*
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  */
304 static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jint flags) {
305     if (isSELinuxDisabled) {
306         return true;
307     }
308
309     ScopedUtfChars pathname(env, pathnameStr);
310     if (pathname.c_str() == NULL) {
311         ALOGV("restorecon(%p) => threw exception", pathnameStr);
312         return false;
313     }
314
315     int ret = selinux_android_restorecon(pathname.c_str(), flags);
316     ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
317     return (ret == 0);
318 }
319
320 /*
321  * JNI registration.
322  */
323 static const JNINativeMethod method_table[] = {
324     /* name,                     signature,                    funcPtr */
325     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
326     { "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 },
332     { "native_restorecon"        , "(Ljava/lang/String;I)Z"                       , (void*)native_restorecon},
333     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
334     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
335 };
336
337 static int log_callback(int type, const char *fmt, ...) {
338     va_list ap;
339     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     }
352     va_start(ap, fmt);
353     LOG_PRI_VA(priority, "SELinux", fmt, ap);
354     va_end(ap);
355     return 0;
356 }
357
358 int register_android_os_SELinux(JNIEnv *env) {
359     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
365     return RegisterMethodsOrDie(env, "android/os/SELinux", method_table, NELEM(method_table));
366 }
367
368 }