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

Commit 20345bd8 authored by Kenny Root's avatar Kenny Root Committed by Gerrit Code Review
Browse files

Merge "Update SELinux JNI to use helpers"

parents 42457027 cd19e3f2
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));
}

}