OSDN Git Service

Merge "Fix NPE with inPurgeable Bitmaps in getAllocationByteCount" into klp-dev
[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 "JNIHelp.h"
21 #include "jni.h"
22 #include "android_runtime/AndroidRuntime.h"
23 #include "selinux/selinux.h"
24 #include "selinux/android.h"
25 #include <errno.h>
26 #include <ScopedLocalRef.h>
27 #include <ScopedUtfChars.h>
28 #include <UniquePtr.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 UniquePtr<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: setSELinuxEnforce
65  * Purpose: set the SE Linux enforcing mode
66  * Parameters: true (enforcing) or false (permissive)
67  * Return value: true (success) or false (fail)
68  * Exceptions: none
69  */
70 static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
71     if (isSELinuxDisabled) {
72         return false;
73     }
74
75     int enforce = value ? 1 : 0;
76
77     return (security_setenforce(enforce) != -1) ? true : false;
78 }
79
80 /*
81  * Function: getPeerCon
82  * Purpose: retrieves security context of peer socket
83  * Parameters:
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
87  */
88 static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
89     if (isSELinuxDisabled) {
90         return NULL;
91     }
92
93     if (fileDescriptor == NULL) {
94         jniThrowNullPointerException(env,
95                 "Trying to check security context of a null peer socket.");
96         return NULL;
97     }
98
99     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
100     if (env->ExceptionOccurred() != NULL) {
101         ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
102         return NULL;
103     }
104
105     security_context_t tmp = NULL;
106     int ret = getpeercon(fd, &tmp);
107     Unique_SecurityContext context(tmp);
108
109     ScopedLocalRef<jstring> contextStr(env, NULL);
110     if (ret != -1) {
111         contextStr.reset(env->NewStringUTF(context.get()));
112     }
113
114     ALOGV("getPeerCon(%d) => %s", fd, context.get());
115     return contextStr.release();
116 }
117
118 /*
119  * Function: setFSCreateCon
120  * Purpose: set security context used for creating a new file system object
121  * Parameters:
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
125  * Exception: none
126  */
127 static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
128     if (isSELinuxDisabled) {
129         return false;
130     }
131
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) {
138             return false;
139         }
140     }
141
142     int ret = setfscreatecon(const_cast<char *>(context_c_str));
143
144     ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
145
146     return (ret == 0) ? true : false;
147 }
148
149 /*
150  * Function: setFileCon
151  * Purpose:  set the security context of a file object
152  * Parameters:
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
157  */
158 static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
159     if (isSELinuxDisabled) {
160         return false;
161     }
162
163     ScopedUtfChars path(env, pathStr);
164     if (path.c_str() == NULL) {
165         return false;
166     }
167
168     ScopedUtfChars context(env, contextStr);
169     if (context.c_str() == NULL) {
170         return false;
171     }
172
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);
176
177     ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
178     return (ret == 0) ? true : false;
179 }
180
181 /*
182  * Function: getFileCon
183  * Purpose: retrieves the context associated with the given path in the file system
184  * Parameters:
185  *        path: given path in the file system
186  * Returns:
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
190  */
191 static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
192     if (isSELinuxDisabled) {
193         return NULL;
194     }
195
196     ScopedUtfChars path(env, pathStr);
197     if (path.c_str() == NULL) {
198         return NULL;
199     }
200
201     security_context_t tmp = NULL;
202     int ret = getfilecon(path.c_str(), &tmp);
203     Unique_SecurityContext context(tmp);
204
205     ScopedLocalRef<jstring> securityString(env, NULL);
206     if (ret != -1) {
207         securityString.reset(env->NewStringUTF(context.get()));
208     }
209
210     ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
211     return securityString.release();
212 }
213
214 /*
215  * Function: getCon
216  * Purpose: Get the context of the current process.
217  * Parameters: none
218  * Returns: a jstring representing the security context of the process,
219  *          the jstring may be NULL if there was an error
220  * Exceptions: none
221  */
222 static jstring getCon(JNIEnv *env, jobject) {
223     if (isSELinuxDisabled) {
224         return NULL;
225     }
226
227     security_context_t tmp = NULL;
228     int ret = getcon(&tmp);
229     Unique_SecurityContext context(tmp);
230
231     ScopedLocalRef<jstring> securityString(env, NULL);
232     if (ret != -1) {
233         securityString.reset(env->NewStringUTF(context.get()));
234     }
235
236     ALOGV("getCon() => %s", context.get());
237     return securityString.release();
238 }
239
240 /*
241  * Function: getPidCon
242  * Purpose: Get the context of a process identified by its pid
243  * Parameters:
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
247  * Exceptions: none
248  */
249 static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
250     if (isSELinuxDisabled) {
251         return NULL;
252     }
253
254     security_context_t tmp = NULL;
255     int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
256     Unique_SecurityContext context(tmp);
257
258     ScopedLocalRef<jstring> securityString(env, NULL);
259     if (ret != -1) {
260         securityString.reset(env->NewStringUTF(context.get()));
261     }
262
263     ALOGV("getPidCon(%d) => %s", pid, context.get());
264     return securityString.release();
265 }
266
267 /*
268  * Function: getBooleanNames
269  * Purpose: Gets a list of the SELinux boolean names.
270  * Parameters: None
271  * Returns: an array of strings  containing the SELinux boolean names.
272  *          returns NULL string on error
273  * Exceptions: None
274  */
275 static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
276     if (isSELinuxDisabled) {
277         return NULL;
278     }
279
280     char **list;
281     int len;
282     if (security_get_boolean_names(&list, &len) == -1) {
283         return NULL;
284     }
285
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());
291         free(list[i]);
292     }
293     free(list);
294
295     return stringArray;
296 }
297
298 /*
299  * Function: getBooleanValue
300  * Purpose: Gets the value for the given SELinux boolean name.
301  * Parameters:
302  *            String: The name of the SELinux boolean.
303  * Returns: a boolean: (true) boolean is set or (false) it is not.
304  * Exceptions: None
305  */
306 static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
307     if (isSELinuxDisabled) {
308         return false;
309     }
310
311     if (nameStr == NULL) {
312         return false;
313     }
314
315     ScopedUtfChars name(env, nameStr);
316     int ret = security_get_boolean_active(name.c_str());
317
318     ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
319     return (ret == 1) ? true : false;
320 }
321
322 /*
323  * Function: setBooleanNames
324  * Purpose: Sets the value for the given SELinux boolean name.
325  * Parameters:
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.
329  * Exceptions: None
330  */
331 static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
332     if (isSELinuxDisabled) {
333         return false;
334     }
335
336     if (nameStr == NULL) {
337         return false;
338     }
339
340     ScopedUtfChars name(env, nameStr);
341     int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
342     if (ret) {
343         return false;
344     }
345
346     if (security_commit_booleans() == -1) {
347         return false;
348     }
349
350     return true;
351 }
352
353 /*
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
361  * Exceptions: None
362  */
363 static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
364         jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
365     if (isSELinuxDisabled) {
366         return true;
367     }
368
369     ScopedUtfChars subjectContext(env, subjectContextStr);
370     if (subjectContext.c_str() == NULL) {
371         return false;
372     }
373
374     ScopedUtfChars objectContext(env, objectContextStr);
375     if (objectContext.c_str() == NULL) {
376         return false;
377     }
378
379     ScopedUtfChars objectClass(env, objectClassStr);
380     if (objectClass.c_str() == NULL) {
381         return false;
382     }
383
384     ScopedUtfChars permission(env, permissionStr);
385     if (permission.c_str() == NULL) {
386         return false;
387     }
388
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(),
392             NULL);
393
394     ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
395             objectClass.c_str(), permission.c_str(), accessGranted);
396
397     return (accessGranted == 0) ? true : false;
398 }
399
400 /*
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
405  * Exceptions: none
406  */
407 static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
408     if (isSELinuxDisabled) {
409         return true;
410     }
411
412     ScopedUtfChars pathname(env, pathnameStr);
413     if (pathname.c_str() == NULL) {
414         ALOGV("restorecon(%p) => threw exception", pathname);
415         return false;
416     }
417
418     int ret = selinux_android_restorecon(pathname.c_str());
419     ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
420     return (ret == 0);
421 }
422
423 /*
424  * JNI registration.
425  */
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},
442 };
443
444 static int log_callback(int type, const char *fmt, ...) {
445     va_list ap;
446     va_start(ap, fmt);
447     LOG_PRI_VA(ANDROID_LOG_ERROR, "SELinux", fmt, ap);
448     va_end(ap);
449     return 0;
450 }
451
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);
456
457     isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
458
459     return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
460             NELEM(method_table));
461 }
462
463 }