Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afd10322 authored by Kenny Root's avatar Kenny Root Committed by Android Git Automerger
Browse files

am d9520336: am 20345bd8: Merge "Update SELinux JNI to use helpers"

* commit 'd9520336':
  Update SELinux JNI to use helpers
parents dfdacaf2 d9520336
Loading
Loading
Loading
Loading
+331 −352
Original line number Diff line number Diff line
@@ -23,16 +23,20 @@
#include "selinux/selinux.h"
#include "selinux/android.h"
#include <errno.h>
#include <ScopedLocalRef.h>
#include <ScopedUtfChars.h>
#include <UniquePtr.h>

namespace android {

  static jboolean isSELinuxDisabled = true;

  static void throw_NullPointerException(JNIEnv *env, const char* msg) {
    jclass clazz;
    clazz = env->FindClass("java/lang/NullPointerException");
    env->ThrowNew(clazz, msg);
struct SecurityContext_Delete {
    void operator()(security_context_t p) const {
        freecon(p);
    }
};
typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;

static jboolean isSELinuxDisabled = true;

/*
 * Function: isSELinuxEnabled
@@ -41,8 +45,7 @@ namespace android {
 * Return value : true (enabled) or false (disabled)
 * Exceptions: none
 */
  static jboolean isSELinuxEnabled(JNIEnv *env, jobject classz) {

static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
    return !isSELinuxDisabled;
}

@@ -53,7 +56,7 @@ namespace android {
 * Return value: true (enforcing) or false (permissive)
 * Exceptions: none
 */
  static jboolean isSELinuxEnforced(JNIEnv *env, jobject clazz) {
static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
    return (security_getenforce() == 1) ? true : false;
}

@@ -64,11 +67,12 @@ namespace android {
 * Return value: true (success) or false (fail)
 * Exceptions: none
 */
  static jboolean setSELinuxEnforce(JNIEnv *env, jobject clazz, jboolean value) {
    if (isSELinuxDisabled)
static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
    if (isSELinuxDisabled) {
        return false;
    }

    int enforce = (value) ? 1 : 0;
    int enforce = value ? 1 : 0;

    return (security_setenforce(enforce) != -1) ? true : false;
}
@@ -81,37 +85,34 @@ namespace android {
 * Returns: jstring representing the security_context of socket or NULL if error
 * Exceptions: NullPointerException if fileDescriptor object is NULL
 */
  static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
    if (isSELinuxDisabled)
static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
    if (isSELinuxDisabled) {
        return NULL;
    }

    if (fileDescriptor == NULL) {
      throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
        jniThrowNullPointerException(env,
                "Trying to check security context of a null peer socket.");
        return NULL;
    }

    security_context_t context = NULL;
    jstring securityString = NULL;

    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);

    if (env->ExceptionOccurred() != NULL) {
      ALOGE("There was an issue with retrieving the file descriptor");
      goto bail;
        ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
        return NULL;
    }

    if (getpeercon(fd, &context) == -1)
      goto bail;

    ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);

    securityString = env->NewStringUTF(context);
    security_context_t tmp;
    int ret = getpeercon(fd, &tmp);
    Unique_SecurityContext context(tmp);

  bail:
    if (context != NULL)
      freecon(context);
    ScopedLocalRef<jstring> contextStr(env, NULL);
    if (ret != -1) {
        contextStr.reset(env->NewStringUTF(context.get()));
    }

    return securityString;
    ALOGV("getPeerCon(%d) => %s", fd, contextStr.get());
    return contextStr.release();
}

/*
@@ -123,29 +124,24 @@ namespace android {
 * Returns: true on success, false on error
 * Exception: none
 */
  static jboolean setFSCreateCon(JNIEnv *env, jobject clazz, jstring context) {
    if (isSELinuxDisabled)
static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
    if (isSELinuxDisabled) {
        return false;

    char * securityContext = NULL;
    const char *constant_securityContext = NULL;

    if (context != NULL) {
      constant_securityContext = env->GetStringUTFChars(context, NULL);

      // GetStringUTFChars returns const char * yet setfscreatecon needs char *
      securityContext = const_cast<char *>(constant_securityContext);
    }

    int ret;
    if ((ret = setfscreatecon(securityContext)) == -1)
      goto bail;
    UniquePtr<ScopedUtfChars> context;
    const char* context_c_str = NULL;
    if (contextStr != NULL) {
        context.reset(new ScopedUtfChars(env, contextStr));
        context_c_str = context->c_str();
        if (context_c_str == NULL) {
            return false;
        }
    }

    ALOGV("setFSCreateCon: set new security context to '%s' ", context == NULL ? "default", context);
    int ret = setfscreatecon(const_cast<char *>(context_c_str));

  bail:
    if (constant_securityContext != NULL)
      env->ReleaseStringUTFChars(context, constant_securityContext);
    ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);

    return (ret == 0) ? true : false;
}
@@ -155,39 +151,30 @@ namespace android {
 * Purpose:  set the security context of a file object
 * Parameters:
 *       path: the location of the file system object
   *       con: the new security context of the file system object
 *       context: the new security context of the file system object
 * Returns: true on success, false on error
 * Exception: NullPointerException is thrown if either path or context strign are NULL
 */
  static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) {
    if (isSELinuxDisabled)
static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
    if (isSELinuxDisabled) {
        return false;
    }

    if (path == NULL) {
      throw_NullPointerException(env, "Trying to change the security context of a NULL file object.");
    ScopedUtfChars path(env, pathStr);
    if (path.c_str() == NULL) {
        return false;
    }

    if (con == NULL) {
      throw_NullPointerException(env, "Trying to set the security context of a file object with NULL.");
    ScopedUtfChars context(env, contextStr);
    if (context.c_str() == NULL) {
        return false;
    }

    const char *objectPath = env->GetStringUTFChars(path, NULL);
    const char *constant_con = env->GetStringUTFChars(con, NULL);

    // GetStringUTFChars returns const char * yet setfilecon needs char *
    char *newCon = const_cast<char *>(constant_con);

    int ret;
    if ((ret = setfilecon(objectPath, newCon)) == -1)
      goto bail;

    ALOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath);
    char *tmp = const_cast<char *>(context.c_str());
    int ret = setfilecon(path.c_str(), tmp);

  bail:
    env->ReleaseStringUTFChars(path, objectPath);
    env->ReleaseStringUTFChars(con, constant_con);
    ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
    return (ret == 0) ? true : false;
}

@@ -201,34 +188,27 @@ namespace android {
 *        the string may be NULL if an error occured
 * Exceptions: NullPointerException if the path object is null
 */
  static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) {
    if (isSELinuxDisabled)
static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
    if (isSELinuxDisabled) {
        return NULL;
    }

    if (path == NULL) {
      throw_NullPointerException(env, "Trying to check security context of a null path.");
    ScopedUtfChars path(env, pathStr);
    if (path.c_str() == NULL) {
        return NULL;
    }

    const char *objectPath = env->GetStringUTFChars(path, NULL);

    security_context_t context = NULL;
    jstring securityString = NULL;

    if (getfilecon(objectPath, &context) == -1)
      goto bail;

    ALOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath);
    security_context_t tmp;
    int ret = getfilecon(path.c_str(), &tmp);
    Unique_SecurityContext context(tmp);

    securityString = env->NewStringUTF(context);

  bail:
    if (context != NULL)
      freecon(context);

    env->ReleaseStringUTFChars(path, objectPath);
    ScopedLocalRef<jstring> securityString(env, NULL);
    if (ret != -1) {
        securityString.reset(env->NewStringUTF(context.get()));
    }

    return securityString;
    ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
    return securityString.release();
}

/*
@@ -239,25 +219,22 @@ namespace android {
 *          the jstring may be NULL if there was an error
 * Exceptions: none
 */
  static jstring getCon(JNIEnv *env, jobject clazz) {
    if (isSELinuxDisabled)
static jstring getCon(JNIEnv *env, jobject) {
    if (isSELinuxDisabled) {
        return NULL;
    }

    security_context_t context = NULL;
    jstring securityString = NULL;

    if (getcon(&context) == -1)
      goto bail;

    ALOGV("getCon: Successfully retrieved context '%s'", context);

    securityString = env->NewStringUTF(context);
    security_context_t tmp;
    int ret = getcon(&tmp);
    Unique_SecurityContext context(tmp);

  bail:
    if (context != NULL)
      freecon(context);
    ScopedLocalRef<jstring> securityString(env, NULL);
    if (ret != -1) {
        securityString.reset(env->NewStringUTF(context.get()));
    }

    return securityString;
    ALOGV("getCon() => %s", context.get());
    return securityString.release();
}

/*
@@ -269,27 +246,22 @@ namespace android {
 *          the jstring may be NULL if there was an error
 * Exceptions: none
 */
  static jstring getPidCon(JNIEnv *env, jobject clazz, jint pid) {
    if (isSELinuxDisabled)
static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
    if (isSELinuxDisabled) {
        return NULL;
    }

    security_context_t context = NULL;
    jstring securityString = NULL;

    pid_t checkPid = (pid_t)pid;

    if (getpidcon(checkPid, &context) == -1)
      goto bail;

    ALOGV("getPidCon: Successfully retrived context '%s' for pid '%d'", context, checkPid);

    securityString = env->NewStringUTF(context);
    security_context_t tmp;
    int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
    Unique_SecurityContext context(tmp);

  bail:
    if (context != NULL)
      freecon(context);
    ScopedLocalRef<jstring> securityString(env, NULL);
    if (ret != -1) {
        securityString.reset(env->NewStringUTF(context.get()));
    }

    return securityString;
    ALOGV("getPidCon(%d) => %s", pid, context.get());
    return securityString.release();
}

/*
@@ -300,25 +272,22 @@ namespace android {
 *          returns NULL string on error
 * Exceptions: None
 */
  static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv clazz) {
    if (isSELinuxDisabled)
static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
    if (isSELinuxDisabled) {
        return NULL;
    }

    char **list;
    int i, len, ret;
    jclass stringClass;
    jobjectArray stringArray = NULL;

    if (security_get_boolean_names(&list, &len) == -1)
    int len;
    if (security_get_boolean_names(&list, &len) == -1) {
        return NULL;
    }

    stringClass = env->FindClass("java/lang/String");
    stringArray = env->NewObjectArray(len, stringClass, env->NewStringUTF(""));
    for (i = 0; i < len; i++) {
      jstring obj;
      obj = env->NewStringUTF(list[i]);
      env->SetObjectArrayElement(stringArray, i, obj);
      env->DeleteLocalRef(obj);
    jclass stringClass = env->FindClass("java/lang/String");
    jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL);
    for (int i = 0; i < len; i++) {
        ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i]));
        env->SetObjectArrayElement(stringArray, i, obj.get());
        free(list[i]);
    }
    free(list);
@@ -334,18 +303,19 @@ namespace android {
 * Returns: a boolean: (true) boolean is set or (false) it is not.
 * Exceptions: None
 */
  static jboolean getBooleanValue(JNIEnv *env, jobject clazz, jstring name) {
    if (isSELinuxDisabled)
static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
    if (isSELinuxDisabled) {
        return false;
    }

    const char *boolean_name;
    int ret;

    if (name == NULL)
    if (nameStr == NULL) {
        return false;
    boolean_name = env->GetStringUTFChars(name, NULL);
    ret = security_get_boolean_active(boolean_name);
    env->ReleaseStringUTFChars(name, boolean_name);
    }

    ScopedUtfChars name(env, nameStr);
    int ret = security_get_boolean_active(name.c_str());

    ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
    return (ret == 1) ? true : false;
}

@@ -358,23 +328,24 @@ namespace android {
 * Returns: a boolean indicating whether or not the operation succeeded.
 * Exceptions: None
 */
  static jboolean setBooleanValue(JNIEnv *env, jobject clazz, jstring name, jboolean value) {
    if (isSELinuxDisabled)
static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
    if (isSELinuxDisabled) {
        return false;
    }

    const char *boolean_name = NULL;
    int ret;

    if (name == NULL)
    if (nameStr == NULL) {
        return false;
    boolean_name = env->GetStringUTFChars(name, NULL);
    ret = security_set_boolean(boolean_name, (value) ? 1 : 0);
    env->ReleaseStringUTFChars(name, boolean_name);
    if (ret)
    }

    ScopedUtfChars name(env, nameStr);
    int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
    if (ret) {
        return false;
    }

    if (security_commit_booleans() == -1)
    if (security_commit_booleans() == -1) {
        return false;
    }

    return true;
}
@@ -382,44 +353,47 @@ namespace android {
/*
 * Function: checkSELinuxAccess
 * Purpose: Check permissions between two security contexts.
   * Parameters: scon: subject security context as a string
   *             tcon: object security context as a string
   *             tclass: object's security class name as a string
   *             perm: permission name as a string
 * Parameters: subjectContextStr: subject security context as a string
 *             objectContextStr: object security context as a string
 *             objectClassStr: object's security class name as a string
 *             permissionStr: permission name as a string
 * Returns: boolean: (true) if permission was granted, (false) otherwise
 * Exceptions: None
 */
  static jboolean checkSELinuxAccess(JNIEnv *env, jobject clazz, jstring scon, jstring tcon, jstring tclass, jstring perm) {
    if (isSELinuxDisabled)
static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
        jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
    if (isSELinuxDisabled) {
        return true;
    }

    int accessGranted = -1;

    const char *const_scon, *const_tcon, *mytclass, *myperm;
    char *myscon, *mytcon;

    if (scon == NULL || tcon == NULL || tclass == NULL || perm == NULL)
      goto bail;
    ScopedUtfChars subjectContext(env, subjectContextStr);
    if (subjectContext.c_str() == NULL) {
        return false;
    }

    const_scon = env->GetStringUTFChars(scon, NULL);
    const_tcon = env->GetStringUTFChars(tcon, NULL);
    mytclass   = env->GetStringUTFChars(tclass, NULL);
    myperm     = env->GetStringUTFChars(perm, NULL);
    ScopedUtfChars objectContext(env, objectContextStr);
    if (objectContext.c_str() == NULL) {
        return false;
    }

    // selinux_check_access needs char* for some
    myscon = const_cast<char *>(const_scon);
    mytcon = const_cast<char *>(const_tcon);
    ScopedUtfChars objectClass(env, objectClassStr);
    if (objectClass.c_str() == NULL) {
        return false;
    }

    accessGranted = selinux_check_access(myscon, mytcon, mytclass, myperm, NULL);
    ScopedUtfChars permission(env, permissionStr);
    if (permission.c_str() == NULL) {
        return false;
    }

    ALOGV("selinux_check_access returned %d", accessGranted);
    char *tmp1 = const_cast<char *>(subjectContext.c_str());
    char *tmp2 = const_cast<char *>(objectContext.c_str());
    int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
            NULL);

    env->ReleaseStringUTFChars(scon, const_scon);
    env->ReleaseStringUTFChars(tcon, const_tcon);
    env->ReleaseStringUTFChars(tclass, mytclass);
    env->ReleaseStringUTFChars(perm, myperm);
    ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
            objectClass.c_str(), permission.c_str(), accessGranted);

  bail:
    return (accessGranted == 0) ? true : false;
}

@@ -430,13 +404,19 @@ namespace android {
 * Returns: boolean: (true) file label successfully restored, (false) otherwise
 * Exceptions: none
 */
  static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
    if (isSELinuxDisabled)
static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
    if (isSELinuxDisabled) {
        return true;
    }

    const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL));
    int ret = selinux_android_restorecon(file);
    env->ReleaseStringUTFChars(pathname, file);
    ScopedUtfChars pathname(env, pathnameStr);
    if (pathname.c_str() == NULL) {
        ALOGV("restorecon(%p) => threw exception", pathname);
        return false;
    }

    int ret = selinux_android_restorecon(pathname.c_str());
    ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
    return (ret == 0);
}

@@ -444,7 +424,6 @@ namespace android {
 * JNI registration.
 */
static JNINativeMethod method_table[] = {

    /* name,                     signature,                    funcPtr */
    { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
    { "getBooleanNames"          , "()[Ljava/lang/String;"                        , (void*)getBooleanNames  },
@@ -477,8 +456,8 @@ namespace android {

    isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;

    return AndroidRuntime::registerNativeMethods(
         env, "android/os/SELinux",
         method_table, NELEM(method_table));
    return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
            NELEM(method_table));
}

}