diff options
author | Nick Kralevich <nnk@google.com> | 2014-10-23 17:04:21 -0700 |
---|---|---|
committer | The Android Automerger <android-build@google.com> | 2014-10-27 20:29:30 -0700 |
commit | cc0740bfa7c0646bdef00ead54922cbb32e8f242 (patch) | |
tree | 588bd5750d995dbf843c8e775c0eec9bb5c256e6 | |
parent | f3e388168a15fc092feab11b8430876730aca644 (diff) | |
download | platform_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.mk | 3 | ||||
-rw-r--r-- | tests/tests/os/jni/CtsOsJniOnLoad.cpp | 6 | ||||
-rw-r--r-- | tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp | 86 | ||||
-rw-r--r-- | tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java | 51 |
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(); } |