Merge "Some SELinux specific CTS tests."
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 5821ec0..4997da2 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -24,10 +24,11 @@
 LOCAL_SRC_FILES := \
 		CtsSecurityJniOnLoad.cpp \
 		android_security_cts_CharDeviceTest.cpp \
-		android_security_cts_NativeCodeTest.cpp
+		android_security_cts_NativeCodeTest.cpp \
+		android_security_cts_SELinuxTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libselinux
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 7244fc2..6243ac9 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -19,6 +19,7 @@
 
 extern int register_android_security_cts_CharDeviceTest(JNIEnv*);
 extern int register_android_security_cts_NativeCodeTest(JNIEnv*);
+extern int register_android_security_cts_SELinuxTest(JNIEnv*);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
@@ -35,5 +36,9 @@
         return JNI_ERR;
     }
 
+    if (register_android_security_cts_SELinuxTest(env)) {
+        return JNI_ERR;
+    }
+
     return JNI_VERSION_1_4;
 }
diff --git a/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp b/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp
new file mode 100644
index 0000000..3bee3a5
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <selinux/selinux.h>
+#include <JNIHelp.h>
+#include <ScopedUtfChars.h>
+
+/*
+ * Function: checkSELinuxAccess
+ * Purpose: Check permissions between two security contexts.
+ * 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: NullPointerException if any argument is NULL
+ */
+static jboolean android_security_cts_SELinuxTest_checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
+        jstring objectContextStr, jstring objectClassStr, jstring permissionStr, jstring auxStr) {
+    if (subjectContextStr == NULL || objectContextStr == NULL || objectClassStr == NULL
+            || permissionStr == NULL || auxStr == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return false;
+    }
+
+    ScopedUtfChars subjectContext(env, subjectContextStr);
+    ScopedUtfChars objectContext(env, objectContextStr);
+    ScopedUtfChars objectClass(env, objectClassStr);
+    ScopedUtfChars permission(env, permissionStr);
+    ScopedUtfChars aux(env, auxStr);
+
+    char *tmp1 = const_cast<char *>(subjectContext.c_str());
+    char *tmp2 = const_cast<char *>(objectContext.c_str());
+    char *tmp3 = const_cast<char *>(aux.c_str());
+    int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(), tmp3);
+    return (accessGranted == 0) ? true : false;
+}
+
+
+static JNINativeMethod gMethods[] = {
+    {  "checkSELinuxAccess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+            (void *) android_security_cts_SELinuxTest_checkSELinuxAccess },
+};
+
+int register_android_security_cts_SELinuxTest(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("android/security/cts/SELinuxTest");
+    return env->RegisterNatives(clazz, gMethods,
+            sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/security/src/android/security/cts/SELinuxTest.java b/tests/tests/security/src/android/security/cts/SELinuxTest.java
new file mode 100644
index 0000000..838eb8a
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/SELinuxTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import junit.framework.TestCase;
+
+/**
+ * Verify that the SELinux configuration is sane.
+ */
+public class SELinuxTest extends TestCase {
+
+    static {
+        System.loadLibrary("ctssecurity_jni");
+    }
+
+    public void testMyJni() {
+        try {
+            checkSELinuxAccess(null, null, null, null, null);
+            fail("should have thrown");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+
+    public void testCheckAccessSane() {
+        assertFalse(checkSELinuxAccess("a", "b", "c", "d", "e"));
+    }
+
+    public void testRild() {
+        assertTrue(checkSELinuxAccess("u:r:rild:s0", "u:object_r:rild_prop:s0", "property_service", "set", "ril.ecclist"));
+    }
+
+    public void testZygote() {
+        assertFalse(checkSELinuxAccess("u:r:zygote:s0", "u:object_r:runas_exec:s0", "file", "getattr", "/system/bin/run-as"));
+        // Also check init, just as a sanity check (init is unconfined, so it should pass)
+        assertTrue(checkSELinuxAccess("u:r:init:s0", "u:object_r:runas_exec:s0", "file", "getattr", "/system/bin/run-as"));
+    }
+
+    private static native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm, String extra);
+}