Loading core/java/com/android/internal/util/ArrayUtils.java +0 −45 Original line number Diff line number Diff line Loading @@ -84,51 +84,6 @@ public class ArrayUtils { return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen); } /** * This is like <code>new byte[length]</code>, but it allocates the array as non-movable. This * prevents copies of the data from being left on the Java heap as a result of heap compaction. * Use this when the array will contain sensitive data such as a password or cryptographic key * that needs to be wiped from memory when no longer needed. The owner of the array is still * responsible for the zeroization; {@link #zeroize(byte[])} should be used to do so. * * @param length the length of the array to allocate * @return the new array */ public static byte[] newNonMovableByteArray(int length) { return (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, length); } /** * Like {@link #newNonMovableByteArray(int)}, but allocates a char array. * * @param length the length of the array to allocate * @return the new array */ public static char[] newNonMovableCharArray(int length) { return (char[]) VMRuntime.getRuntime().newNonMovableArray(char.class, length); } /** * Zeroizes a byte array as securely as possible. Use this when the array contains sensitive * data such as a password or cryptographic key. * <p> * This zeroizes the array in a way that is guaranteed to not be optimized out by the compiler. * If supported by the architecture, it zeroizes the data not just in the L1 data cache but also * in other levels of the memory hierarchy up to and including main memory (but not above that). * <p> * This works on any <code>byte[]</code>, but to ensure that copies of the array aren't left on * the Java heap the array should have been allocated with {@link #newNonMovableByteArray(int)}. * Use on other arrays might also introduce performance anomalies. * * @param array the array to zeroize */ public static native void zeroize(byte[] array); /** * Like {@link #zeroize(byte[])}, but for char arrays. */ public static native void zeroize(char[] array); /** * Checks if the beginnings of two byte arrays are equal. * Loading core/jni/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,6 @@ cc_library_shared_for_libandroid_runtime { "android_view_VelocityTracker.cpp", "android_view_VerifiedKeyEvent.cpp", "android_view_VerifiedMotionEvent.cpp", "com_android_internal_util_ArrayUtils.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", "core_jni_helpers.cpp", ":deviceproductinfoconstants_aidl", Loading core/jni/AndroidRuntime.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -215,7 +215,6 @@ extern int register_com_android_internal_os_Zygote(JNIEnv *env); extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); extern int register_com_android_internal_security_VerityUtils(JNIEnv* env); extern int register_com_android_internal_util_ArrayUtils(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); extern int register_android_window_WindowInfosListener(JNIEnv* env); extern int register_android_window_ScreenCapture(JNIEnv* env); Loading Loading @@ -1614,7 +1613,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_com_android_internal_security_VerityUtils), REG_JNI(register_com_android_internal_util_ArrayUtils), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), Loading core/jni/com_android_internal_util_ArrayUtils.cppdeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * Copyright (C) 2024 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. */ #define LOG_TAG "ArrayUtils" #include <android-base/logging.h> #include <jni.h> #include <nativehelper/JNIHelp.h> #include <string.h> #include <unistd.h> #include <utils/Log.h> namespace android { static size_t GetCacheLineSize() { long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); if (size <= 0) { ALOGE("Unable to determine L1 data cache line size. Assuming 32 bytes"); return 32; } return size; } #ifdef __aarch64__ static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) { // Execute 'dc cvac' at least once on each cache line in the memory region. // // 'dc cvac' stands for "Data Cache line Clean by Virtual Address to point-of-Coherency". // It writes the cache line back to the "point-of-coherency", i.e. main memory. // // Since the memory region is not guaranteed to be cache-line-aligned, we use an "extra" // instruction after the loop to make sure the last cache line gets covered. for (size_t i = 0; i < size; i += cache_line_size) { asm volatile("dc cvac, %0" ::"r"(p + i)); } asm volatile("dc cvac, %0" ::"r"(p + size - 1)); } #elif defined(__i386__) || defined(__x86_64__) static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) { for (size_t i = 0; i < size; i += cache_line_size) { asm volatile("clflush (%0)" ::"r"(p + i)); } asm volatile("clflush (%0)" ::"r"(p + size - 1)); } #elif defined(__riscv) static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) { // This should eventually work, but it is not ready to be enabled yet: // 1.) The Android emulator needs to add support for zicbom. // 2.) Kernel needs to enable zicbom in usermode. // 3.) Android clang needs to add zicbom to the target. #if 0 for (size_t i = 0; i < size; i += cache_line_size) { asm volatile("cbo.clean (%0)" ::"r"(p + i)); } asm volatile("cbo.clean (%0)" ::"r"(p + size - 1)); #endif } #elif defined(__arm__) // arm32 has a cacheflush() syscall, but it is undocumented and only flushes the icache. // It is not the same as cacheflush(2) as documented in the Linux man-pages project. static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {} #else #error "Unknown architecture" #endif static void ZeroizePrimitiveArray(JNIEnv* env, jclass clazz, jarray array, size_t component_len) { static const size_t cache_line_size = GetCacheLineSize(); size_t size = env->GetArrayLength(array) * component_len; if (size == 0) { return; } // ART guarantees that GetPrimitiveArrayCritical never copies. jboolean isCopy; void* elems = env->GetPrimitiveArrayCritical(array, &isCopy); CHECK(!isCopy); #ifdef __BIONIC__ memset_explicit(elems, 0, size); #else memset(elems, 0, size); #endif // Clean the data cache so that the data gets zeroized in main memory right away. Without this, // it might not be written to main memory until the cache line happens to be evicted. CleanDataCache(static_cast<const uint8_t*>(elems), size, cache_line_size); env->ReleasePrimitiveArrayCritical(array, elems, /* mode= */ 0); } static void ZeroizeByteArray(JNIEnv* env, jclass clazz, jbyteArray array) { ZeroizePrimitiveArray(env, clazz, array, sizeof(jbyte)); } static void ZeroizeCharArray(JNIEnv* env, jclass clazz, jcharArray array) { ZeroizePrimitiveArray(env, clazz, array, sizeof(jchar)); } static const JNINativeMethod sMethods[] = { {"zeroize", "([B)V", (void*)ZeroizeByteArray}, {"zeroize", "([C)V", (void*)ZeroizeCharArray}, }; int register_com_android_internal_util_ArrayUtils(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/internal/util/ArrayUtils", sMethods, NELEM(sMethods)); } } // namespace android core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java +0 −47 Original line number Diff line number Diff line Loading @@ -496,51 +496,4 @@ public class ArrayUtilsTest { // expected } } // Note: the zeroize() tests only test the behavior that can be tested from a Java test. // They do not verify that no copy of the data is left anywhere. @Test @SmallTest public void testZeroizeNonMovableByteArray() { final int length = 10; byte[] array = ArrayUtils.newNonMovableByteArray(length); assertArrayEquals(array, new byte[length]); Arrays.fill(array, (byte) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new byte[length]); } @Test @SmallTest public void testZeroizeRegularByteArray() { final int length = 10; byte[] array = new byte[length]; assertArrayEquals(array, new byte[length]); Arrays.fill(array, (byte) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new byte[length]); } @Test @SmallTest public void testZeroizeNonMovableCharArray() { final int length = 10; char[] array = ArrayUtils.newNonMovableCharArray(length); assertArrayEquals(array, new char[length]); Arrays.fill(array, (char) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new char[length]); } @Test @SmallTest public void testZeroizeRegularCharArray() { final int length = 10; char[] array = new char[length]; assertArrayEquals(array, new char[length]); Arrays.fill(array, (char) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new char[length]); } } Loading
core/java/com/android/internal/util/ArrayUtils.java +0 −45 Original line number Diff line number Diff line Loading @@ -84,51 +84,6 @@ public class ArrayUtils { return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen); } /** * This is like <code>new byte[length]</code>, but it allocates the array as non-movable. This * prevents copies of the data from being left on the Java heap as a result of heap compaction. * Use this when the array will contain sensitive data such as a password or cryptographic key * that needs to be wiped from memory when no longer needed. The owner of the array is still * responsible for the zeroization; {@link #zeroize(byte[])} should be used to do so. * * @param length the length of the array to allocate * @return the new array */ public static byte[] newNonMovableByteArray(int length) { return (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, length); } /** * Like {@link #newNonMovableByteArray(int)}, but allocates a char array. * * @param length the length of the array to allocate * @return the new array */ public static char[] newNonMovableCharArray(int length) { return (char[]) VMRuntime.getRuntime().newNonMovableArray(char.class, length); } /** * Zeroizes a byte array as securely as possible. Use this when the array contains sensitive * data such as a password or cryptographic key. * <p> * This zeroizes the array in a way that is guaranteed to not be optimized out by the compiler. * If supported by the architecture, it zeroizes the data not just in the L1 data cache but also * in other levels of the memory hierarchy up to and including main memory (but not above that). * <p> * This works on any <code>byte[]</code>, but to ensure that copies of the array aren't left on * the Java heap the array should have been allocated with {@link #newNonMovableByteArray(int)}. * Use on other arrays might also introduce performance anomalies. * * @param array the array to zeroize */ public static native void zeroize(byte[] array); /** * Like {@link #zeroize(byte[])}, but for char arrays. */ public static native void zeroize(char[] array); /** * Checks if the beginnings of two byte arrays are equal. * Loading
core/jni/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,6 @@ cc_library_shared_for_libandroid_runtime { "android_view_VelocityTracker.cpp", "android_view_VerifiedKeyEvent.cpp", "android_view_VerifiedMotionEvent.cpp", "com_android_internal_util_ArrayUtils.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", "core_jni_helpers.cpp", ":deviceproductinfoconstants_aidl", Loading
core/jni/AndroidRuntime.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -215,7 +215,6 @@ extern int register_com_android_internal_os_Zygote(JNIEnv *env); extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); extern int register_com_android_internal_security_VerityUtils(JNIEnv* env); extern int register_com_android_internal_util_ArrayUtils(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); extern int register_android_window_WindowInfosListener(JNIEnv* env); extern int register_android_window_ScreenCapture(JNIEnv* env); Loading Loading @@ -1614,7 +1613,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_com_android_internal_security_VerityUtils), REG_JNI(register_com_android_internal_util_ArrayUtils), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), Loading
core/jni/com_android_internal_util_ArrayUtils.cppdeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * Copyright (C) 2024 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. */ #define LOG_TAG "ArrayUtils" #include <android-base/logging.h> #include <jni.h> #include <nativehelper/JNIHelp.h> #include <string.h> #include <unistd.h> #include <utils/Log.h> namespace android { static size_t GetCacheLineSize() { long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); if (size <= 0) { ALOGE("Unable to determine L1 data cache line size. Assuming 32 bytes"); return 32; } return size; } #ifdef __aarch64__ static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) { // Execute 'dc cvac' at least once on each cache line in the memory region. // // 'dc cvac' stands for "Data Cache line Clean by Virtual Address to point-of-Coherency". // It writes the cache line back to the "point-of-coherency", i.e. main memory. // // Since the memory region is not guaranteed to be cache-line-aligned, we use an "extra" // instruction after the loop to make sure the last cache line gets covered. for (size_t i = 0; i < size; i += cache_line_size) { asm volatile("dc cvac, %0" ::"r"(p + i)); } asm volatile("dc cvac, %0" ::"r"(p + size - 1)); } #elif defined(__i386__) || defined(__x86_64__) static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) { for (size_t i = 0; i < size; i += cache_line_size) { asm volatile("clflush (%0)" ::"r"(p + i)); } asm volatile("clflush (%0)" ::"r"(p + size - 1)); } #elif defined(__riscv) static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) { // This should eventually work, but it is not ready to be enabled yet: // 1.) The Android emulator needs to add support for zicbom. // 2.) Kernel needs to enable zicbom in usermode. // 3.) Android clang needs to add zicbom to the target. #if 0 for (size_t i = 0; i < size; i += cache_line_size) { asm volatile("cbo.clean (%0)" ::"r"(p + i)); } asm volatile("cbo.clean (%0)" ::"r"(p + size - 1)); #endif } #elif defined(__arm__) // arm32 has a cacheflush() syscall, but it is undocumented and only flushes the icache. // It is not the same as cacheflush(2) as documented in the Linux man-pages project. static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {} #else #error "Unknown architecture" #endif static void ZeroizePrimitiveArray(JNIEnv* env, jclass clazz, jarray array, size_t component_len) { static const size_t cache_line_size = GetCacheLineSize(); size_t size = env->GetArrayLength(array) * component_len; if (size == 0) { return; } // ART guarantees that GetPrimitiveArrayCritical never copies. jboolean isCopy; void* elems = env->GetPrimitiveArrayCritical(array, &isCopy); CHECK(!isCopy); #ifdef __BIONIC__ memset_explicit(elems, 0, size); #else memset(elems, 0, size); #endif // Clean the data cache so that the data gets zeroized in main memory right away. Without this, // it might not be written to main memory until the cache line happens to be evicted. CleanDataCache(static_cast<const uint8_t*>(elems), size, cache_line_size); env->ReleasePrimitiveArrayCritical(array, elems, /* mode= */ 0); } static void ZeroizeByteArray(JNIEnv* env, jclass clazz, jbyteArray array) { ZeroizePrimitiveArray(env, clazz, array, sizeof(jbyte)); } static void ZeroizeCharArray(JNIEnv* env, jclass clazz, jcharArray array) { ZeroizePrimitiveArray(env, clazz, array, sizeof(jchar)); } static const JNINativeMethod sMethods[] = { {"zeroize", "([B)V", (void*)ZeroizeByteArray}, {"zeroize", "([C)V", (void*)ZeroizeCharArray}, }; int register_com_android_internal_util_ArrayUtils(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/internal/util/ArrayUtils", sMethods, NELEM(sMethods)); } } // namespace android
core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java +0 −47 Original line number Diff line number Diff line Loading @@ -496,51 +496,4 @@ public class ArrayUtilsTest { // expected } } // Note: the zeroize() tests only test the behavior that can be tested from a Java test. // They do not verify that no copy of the data is left anywhere. @Test @SmallTest public void testZeroizeNonMovableByteArray() { final int length = 10; byte[] array = ArrayUtils.newNonMovableByteArray(length); assertArrayEquals(array, new byte[length]); Arrays.fill(array, (byte) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new byte[length]); } @Test @SmallTest public void testZeroizeRegularByteArray() { final int length = 10; byte[] array = new byte[length]; assertArrayEquals(array, new byte[length]); Arrays.fill(array, (byte) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new byte[length]); } @Test @SmallTest public void testZeroizeNonMovableCharArray() { final int length = 10; char[] array = ArrayUtils.newNonMovableCharArray(length); assertArrayEquals(array, new char[length]); Arrays.fill(array, (char) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new char[length]); } @Test @SmallTest public void testZeroizeRegularCharArray() { final int length = 10; char[] array = new char[length]; assertArrayEquals(array, new char[length]); Arrays.fill(array, (char) 0xff); ArrayUtils.zeroize(array); assertArrayEquals(array, new char[length]); } }