blob: 8cb10782310c89da555c2b7e62d3fc3531c66076 [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
Steven Moreland2279b252017-07-19 09:50:45 -070020#include <nativehelper/JNIHelp.h>
Stephen Smalleyc07fca32012-01-13 08:31:39 -050021#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>
Elliott Hughes93bb56e2016-09-11 14:50:12 -070026#include <memory>
Steven Moreland2279b252017-07-19 09:50:45 -070027#include <nativehelper/ScopedLocalRef.h>
28#include <nativehelper/ScopedUtfChars.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};
Elliott Hughes93bb56e2016-09-11 14:50:12 -070037typedef std::unique_ptr<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
Makoto Onuki9700015b2018-07-27 17:06:30 -070063static jstring getFdConInner(JNIEnv *env, jobject fileDescriptor, bool isSocket) {
64 if (isSELinuxDisabled) {
65 return NULL;
66 }
67
68 if (fileDescriptor == NULL) {
69 jniThrowNullPointerException(env,
70 "Trying to check security context of a null FileDescriptor.");
71 return NULL;
72 }
73
74 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
75 if (env->ExceptionCheck()) {
76 ALOGE("getFdCon => getFD for %p failed", fileDescriptor);
77 return NULL;
78 }
79
80 security_context_t tmp = NULL;
81 int ret;
82 if (isSocket) {
83 ret = getpeercon(fd, &tmp);
84 } else{
85 ret = fgetfilecon(fd, &tmp);
86 }
87 Unique_SecurityContext context(tmp);
88
89 ScopedLocalRef<jstring> contextStr(env, NULL);
90 if (ret != -1) {
91 contextStr.reset(env->NewStringUTF(context.get()));
92 }
93
94 ALOGV("getFdCon(%d) => %s", fd, context.get());
95 return contextStr.release();
96}
97
Kenny Rootcd19e3f2012-10-19 14:15:26 -070098/*
Kenny Rootcd19e3f2012-10-19 14:15:26 -070099 * Function: getPeerCon
100 * Purpose: retrieves security context of peer socket
101 * Parameters:
102 * fileDescriptor: peer socket file as a FileDescriptor object
103 * Returns: jstring representing the security_context of socket or NULL if error
104 * Exceptions: NullPointerException if fileDescriptor object is NULL
105 */
106static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
Makoto Onuki9700015b2018-07-27 17:06:30 -0700107 return getFdConInner(env, fileDescriptor, true);
108}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500109
Makoto Onuki9700015b2018-07-27 17:06:30 -0700110/*
111 * Function: getFdCon
112 * Purpose: retrieves security context of a file descriptor.
113 * Parameters:
114 * fileDescriptor: a FileDescriptor object
115 * Returns: jstring representing the security_context of socket or NULL if error
116 * Exceptions: NullPointerException if fileDescriptor object is NULL
117 */
118static jstring getFdCon(JNIEnv *env, jobject, jobject fileDescriptor) {
119 return getFdConInner(env, fileDescriptor, false);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700120}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500121
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700122/*
123 * Function: setFSCreateCon
124 * Purpose: set security context used for creating a new file system object
125 * Parameters:
126 * context: security_context_t representing the new context of a file system object,
127 * set to NULL to return to the default policy behavior
128 * Returns: true on success, false on error
129 * Exception: none
130 */
131static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
132 if (isSELinuxDisabled) {
133 return false;
134 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500135
Elliott Hughes93bb56e2016-09-11 14:50:12 -0700136 std::unique_ptr<ScopedUtfChars> context;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700137 const char* context_c_str = NULL;
138 if (contextStr != NULL) {
139 context.reset(new ScopedUtfChars(env, contextStr));
140 context_c_str = context->c_str();
141 if (context_c_str == NULL) {
142 return false;
143 }
144 }
145
146 int ret = setfscreatecon(const_cast<char *>(context_c_str));
147
148 ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500149
150 return (ret == 0) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700151}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500152
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700153/*
154 * Function: setFileCon
155 * Purpose: set the security context of a file object
156 * Parameters:
157 * path: the location of the file system object
158 * context: the new security context of the file system object
159 * Returns: true on success, false on error
160 * Exception: NullPointerException is thrown if either path or context strign are NULL
161 */
162static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
163 if (isSELinuxDisabled) {
164 return false;
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500165 }
166
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700167 ScopedUtfChars path(env, pathStr);
168 if (path.c_str() == NULL) {
169 return false;
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500170 }
171
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700172 ScopedUtfChars context(env, contextStr);
173 if (context.c_str() == NULL) {
174 return false;
175 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500176
177 // GetStringUTFChars returns const char * yet setfilecon needs char *
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700178 char *tmp = const_cast<char *>(context.c_str());
179 int ret = setfilecon(path.c_str(), tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500180
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700181 ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500182 return (ret == 0) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700183}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500184
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700185/*
186 * Function: getFileCon
187 * Purpose: retrieves the context associated with the given path in the file system
188 * Parameters:
189 * path: given path in the file system
190 * Returns:
191 * string representing the security context string of the file object
192 * the string may be NULL if an error occured
193 * Exceptions: NullPointerException if the path object is null
194 */
195static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
196 if (isSELinuxDisabled) {
197 return NULL;
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500198 }
199
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700200 ScopedUtfChars path(env, pathStr);
201 if (path.c_str() == NULL) {
202 return NULL;
203 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500204
Richard Haines81ad2842013-05-22 15:12:16 +0100205 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700206 int ret = getfilecon(path.c_str(), &tmp);
207 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500208
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700209 ScopedLocalRef<jstring> securityString(env, NULL);
210 if (ret != -1) {
211 securityString.reset(env->NewStringUTF(context.get()));
212 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500213
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700214 ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
215 return securityString.release();
216}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500217
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700218/*
219 * Function: getCon
220 * Purpose: Get the context of the current process.
221 * Parameters: none
222 * Returns: a jstring representing the security context of the process,
223 * the jstring may be NULL if there was an error
224 * Exceptions: none
225 */
226static jstring getCon(JNIEnv *env, jobject) {
227 if (isSELinuxDisabled) {
228 return NULL;
229 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500230
Richard Haines81ad2842013-05-22 15:12:16 +0100231 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700232 int ret = getcon(&tmp);
233 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500234
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700235 ScopedLocalRef<jstring> securityString(env, NULL);
236 if (ret != -1) {
237 securityString.reset(env->NewStringUTF(context.get()));
238 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500239
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700240 ALOGV("getCon() => %s", context.get());
241 return securityString.release();
242}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500243
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700244/*
245 * Function: getPidCon
246 * Purpose: Get the context of a process identified by its pid
247 * Parameters:
248 * pid: a jint representing the process
249 * Returns: a jstring representing the security context of the pid,
250 * the jstring may be NULL if there was an error
251 * Exceptions: none
252 */
253static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
254 if (isSELinuxDisabled) {
255 return NULL;
256 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500257
Richard Haines81ad2842013-05-22 15:12:16 +0100258 security_context_t tmp = NULL;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700259 int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
260 Unique_SecurityContext context(tmp);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500261
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700262 ScopedLocalRef<jstring> securityString(env, NULL);
263 if (ret != -1) {
264 securityString.reset(env->NewStringUTF(context.get()));
265 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500266
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700267 ALOGV("getPidCon(%d) => %s", pid, context.get());
268 return securityString.release();
269}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500270
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700271/*
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700272 * Function: checkSELinuxAccess
273 * Purpose: Check permissions between two security contexts.
274 * Parameters: subjectContextStr: subject security context as a string
275 * objectContextStr: object security context as a string
276 * objectClassStr: object's security class name as a string
277 * permissionStr: permission name as a string
278 * Returns: boolean: (true) if permission was granted, (false) otherwise
279 * Exceptions: None
280 */
281static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
282 jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
283 if (isSELinuxDisabled) {
284 return true;
285 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500286
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700287 ScopedUtfChars subjectContext(env, subjectContextStr);
288 if (subjectContext.c_str() == NULL) {
289 return false;
290 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500291
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700292 ScopedUtfChars objectContext(env, objectContextStr);
293 if (objectContext.c_str() == NULL) {
294 return false;
295 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500296
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700297 ScopedUtfChars objectClass(env, objectClassStr);
298 if (objectClass.c_str() == NULL) {
299 return false;
300 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500301
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700302 ScopedUtfChars permission(env, permissionStr);
303 if (permission.c_str() == NULL) {
304 return false;
305 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500306
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700307 char *tmp1 = const_cast<char *>(subjectContext.c_str());
308 char *tmp2 = const_cast<char *>(objectContext.c_str());
309 int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
310 NULL);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500311
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700312 ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
313 objectClass.c_str(), permission.c_str(), accessGranted);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500314
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500315 return (accessGranted == 0) ? true : false;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700316}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500317
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700318/*
319 * Function: native_restorecon
320 * Purpose: restore default SELinux security context
321 * Parameters: pathname: the pathname for the file to be relabeled
322 * Returns: boolean: (true) file label successfully restored, (false) otherwise
323 * Exceptions: none
324 */
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700325static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jint flags) {
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700326 if (isSELinuxDisabled) {
327 return true;
328 }
rpcraig554cb0c2012-07-05 06:41:43 -0400329
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700330 ScopedUtfChars pathname(env, pathnameStr);
331 if (pathname.c_str() == NULL) {
Colin Crossd0696952014-02-06 20:17:48 -0800332 ALOGV("restorecon(%p) => threw exception", pathnameStr);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700333 return false;
334 }
335
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700336 int ret = selinux_android_restorecon(pathname.c_str(), flags);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700337 ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
rpcraig554cb0c2012-07-05 06:41:43 -0400338 return (ret == 0);
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700339}
rpcraig554cb0c2012-07-05 06:41:43 -0400340
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700341/*
342 * JNI registration.
343 */
Daniel Micay76f6a862015-09-19 17:31:01 -0400344static const JNINativeMethod method_table[] = {
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500345 /* name, signature, funcPtr */
346 { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500347 { "getContext" , "()Ljava/lang/String;" , (void*)getCon },
348 { "getFileContext" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)getFileCon },
349 { "getPeerContext" , "(Ljava/io/FileDescriptor;)Ljava/lang/String;" , (void*)getPeerCon },
Makoto Onuki9700015b2018-07-27 17:06:30 -0700350 { "getFileContext" , "(Ljava/io/FileDescriptor;)Ljava/lang/String;" , (void*)getFdCon },
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500351 { "getPidContext" , "(I)Ljava/lang/String;" , (void*)getPidCon },
352 { "isSELinuxEnforced" , "()Z" , (void*)isSELinuxEnforced},
353 { "isSELinuxEnabled" , "()Z" , (void*)isSELinuxEnabled },
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700354 { "native_restorecon" , "(Ljava/lang/String;I)Z" , (void*)native_restorecon},
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500355 { "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon },
356 { "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon },
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700357};
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500358
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700359static int log_callback(int type, const char *fmt, ...) {
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500360 va_list ap;
Stephen Smalleye0dda3c2014-01-29 12:55:58 -0500361 int priority;
362
363 switch (type) {
364 case SELINUX_WARNING:
365 priority = ANDROID_LOG_WARN;
366 break;
367 case SELINUX_INFO:
368 priority = ANDROID_LOG_INFO;
369 break;
370 default:
371 priority = ANDROID_LOG_ERROR;
372 break;
373 }
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500374 va_start(ap, fmt);
Stephen Smalleye0dda3c2014-01-29 12:55:58 -0500375 LOG_PRI_VA(priority, "SELinux", fmt, ap);
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500376 va_end(ap);
377 return 0;
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700378}
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500379
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700380int register_android_os_SELinux(JNIEnv *env) {
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500381 union selinux_callback cb;
382 cb.func_log = log_callback;
383 selinux_set_callback(SELINUX_CB_LOG, cb);
384
385 isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
386
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800387 return RegisterMethodsOrDie(env, "android/os/SELinux", method_table, NELEM(method_table));
Kenny Rootcd19e3f2012-10-19 14:15:26 -0700388}
389
Stephen Smalleyc07fca32012-01-13 08:31:39 -0500390}