summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Kralevich <nnk@google.com>2014-10-23 17:04:21 -0700
committerThe Android Automerger <android-build@google.com>2014-10-27 20:29:30 -0700
commitcc0740bfa7c0646bdef00ead54922cbb32e8f242 (patch)
tree588bd5750d995dbf843c8e775c0eec9bb5c256e6
parentf3e388168a15fc092feab11b8430876730aca644 (diff)
downloadplatform_cts-cc0740bfa7c0646bdef00ead54922cbb32e8f242.tar.gz
platform_cts-cc0740bfa7c0646bdef00ead54922cbb32e8f242.tar.bz2
platform_cts-cc0740bfa7c0646bdef00ead54922cbb32e8f242.zip
Fix NoExecutePermissionTest
Don't look for magic keywords such as [heap] or [stack], as they aren't guaranteed to be present in /proc/self/maps. Instead, determine the address of 1) a stack pointer 2) a heap pointer 3) an executable pointer and check to see if they have the expected page permissions. Bug: 16873288 Change-Id: I16f6066d1b5d26bc491e413de1d10e98aec9c81c
-rw-r--r--tests/tests/os/jni/Android.mk3
-rw-r--r--tests/tests/os/jni/CtsOsJniOnLoad.cpp6
-rw-r--r--tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp86
-rw-r--r--tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java51
4 files changed, 112 insertions, 34 deletions
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
index 3d3bc33f836..32a5a9c0931 100644
--- a/tests/tests/os/jni/Android.mk
+++ b/tests/tests/os/jni/Android.mk
@@ -25,7 +25,8 @@ LOCAL_SRC_FILES := \
CtsOsJniOnLoad.cpp \
android_os_cts_CpuInstructions.cpp.arm \
android_os_cts_TaggedPointer.cpp \
- android_os_cts_OSFeatures.cpp
+ android_os_cts_OSFeatures.cpp \
+ android_os_cts_NoExecutePermissionTest.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
diff --git a/tests/tests/os/jni/CtsOsJniOnLoad.cpp b/tests/tests/os/jni/CtsOsJniOnLoad.cpp
index c6b88f50f19..39209157935 100644
--- a/tests/tests/os/jni/CtsOsJniOnLoad.cpp
+++ b/tests/tests/os/jni/CtsOsJniOnLoad.cpp
@@ -25,6 +25,8 @@ extern int register_android_os_cts_TaggedPointer(JNIEnv*);
extern int register_android_os_cts_OSFeatures(JNIEnv*);
+extern int register_android_os_cts_NoExecutePermissionTest(JNIEnv*);
+
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
@@ -48,5 +50,9 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
+ if (register_android_os_cts_NoExecutePermissionTest(env)) {
+ return JNI_ERR;
+ }
+
return JNI_VERSION_1_4;
}
diff --git a/tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp b/tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp
new file mode 100644
index 00000000000..e30599c49e0
--- /dev/null
+++ b/tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <cutils/log.h>
+#include <inttypes.h>
+
+static jboolean isAddressExecutable(uintptr_t address) {
+ char line[1024];
+ jboolean retval = false;
+ FILE *fp = fopen("/proc/self/maps", "re");
+ if (fp == NULL) {
+ ALOGE("Unable to open /proc/self/maps: %s", strerror(errno));
+ return false;
+ }
+ while(fgets(line, sizeof(line), fp) != NULL) {
+ uintptr_t start;
+ uintptr_t end;
+ char permissions[10];
+ int scan = sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %9s ", &start, &end, permissions);
+ if ((scan == 3) && (start <= address) && (address < end)) {
+ retval = (permissions[2] == 'x');
+ break;
+ }
+ }
+ fclose(fp);
+ return retval;
+}
+
+static jboolean android_os_cts_NoExecutePermissionTest_isMyCodeExecutable(JNIEnv*, jobject)
+{
+ return isAddressExecutable((uintptr_t) __builtin_return_address(0));
+}
+
+static jboolean android_os_cts_NoExecutePermissionTest_isStackExecutable(JNIEnv*, jobject)
+{
+ unsigned int foo;
+ return isAddressExecutable((uintptr_t) &foo);
+}
+
+
+static jboolean android_os_cts_NoExecutePermissionTest_isHeapExecutable(JNIEnv*, jobject)
+{
+ unsigned int* foo = (unsigned int *) malloc(sizeof(unsigned int));
+ if (foo == NULL) {
+ ALOGE("Unable to allocate memory");
+ return false;
+ }
+ jboolean result = isAddressExecutable((uintptr_t) foo);
+ free(foo);
+ return result;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "isMyCodeExecutable", "()Z",
+ (void *) android_os_cts_NoExecutePermissionTest_isMyCodeExecutable },
+ { "isStackExecutable", "()Z",
+ (void *) android_os_cts_NoExecutePermissionTest_isStackExecutable },
+ { "isHeapExecutable", "()Z",
+ (void *) android_os_cts_NoExecutePermissionTest_isHeapExecutable }
+};
+
+int register_android_os_cts_NoExecutePermissionTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/os/cts/NoExecutePermissionTest");
+
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java b/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java
index 43afb535495..224ab46f220 100644
--- a/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java
+++ b/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java
@@ -28,45 +28,26 @@ import junit.framework.TestCase;
*/
public class NoExecutePermissionTest extends TestCase {
- public void testNoExecutePermission() throws FileNotFoundException {
+ static {
+ System.loadLibrary("ctsos_jni");
+ }
+
+ public void testNoExecuteStack() {
if (!cpuHasNxSupport()) {
return;
}
+ assertFalse(isStackExecutable());
+ }
- String heapPermissions = null;
- String stackPermissions = null;
-
- Scanner scanner = null;
- try {
- scanner = new Scanner(new File("/proc/self/maps"));
- while (scanner.hasNextLine()) {
- String line = scanner.nextLine().trim();
- String[] fields = line.split("\\s+");
-
- // Sample line:
- // 0001d000-00024000 rw-p 00000000 00:00 0 [heap]
- if (fields != null && fields.length >= 1) {
- String permissions = fields[1];
- if (fields.length >= 6) {
- String tag = fields[5];
- if ("[heap]".equals(tag)) {
- heapPermissions = permissions;
- } else if ("[stack]".equals(tag)) {
- stackPermissions = permissions;
- }
- }
- }
- }
- } finally {
- if (scanner != null) {
- scanner.close();
- }
+ public void testNoExecuteHeap() {
+ if (!cpuHasNxSupport()) {
+ return;
}
+ assertFalse(isHeapExecutable());
+ }
- if (heapPermissions != null) {
- assertEquals("NX (No Execute) not enabled for heap", "rw-p", heapPermissions);
- }
- assertEquals("NX (No Execute) not enabled for stack", "rw-p", stackPermissions);
+ public void testExecuteCode() {
+ assertTrue(isMyCodeExecutable());
}
private static boolean cpuHasNxSupport() {
@@ -84,4 +65,8 @@ public class NoExecutePermissionTest extends TestCase {
// have NX support.
return true;
}
+
+ private static native boolean isStackExecutable();
+ private static native boolean isHeapExecutable();
+ private static native boolean isMyCodeExecutable();
}