Merge remote-tracking branch \'goog/mnc-cts-release\' into HEAD
am: 79a816d6c0
* commit '79a816d6c08e18870e52c67f6ddbd7b89d3c973a':
Squashed mnc-dev changes:
diff --git a/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java b/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java
index 7fc5917..e097b5a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java
@@ -31,7 +31,7 @@
public void testValues(){
Config[] config = Config.values();
- assertEquals(4, config.length);
+ assertTrue(config.length >= 4);
assertEquals(Config.ALPHA_8, config[0]);
assertEquals(Config.RGB_565, config[1]);
assertEquals(Config.ARGB_4444, config[2]);
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 25bc6ac..d8d8dfa 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 2d55fb6..327eefc 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,11 +31,15 @@
android_security_cts_SELinuxTest.cpp \
android_security_cts_MMapExecutableTest.cpp \
android_security_cts_AudioPolicyBinderTest.cpp \
- android_security_cts_EncryptionTest.cpp
+ android_security_cts_EncryptionTest.cpp \
+ android_security_cts_MediaPlayerInfoLeakTest.cpp \
+ android_security_cts_AudioEffectBinderTest.cpp \
+ android_security_cts_AudioFlingerBinderTest.cpp \
+ android_security_cts_StagefrightFoundationTest.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog libbinder libutils libmedia libselinux libdl libcutils libcrypto
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libbinder libutils libmedia libselinux libdl libcutils libcrypto libstagefright_foundation
LOCAL_C_INCLUDES += ndk/sources/cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index c60b866..b09821c 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -25,7 +25,11 @@
extern int register_android_security_cts_SELinuxTest(JNIEnv*);
extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
+extern int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env);
extern int register_android_security_cts_EncryptionTest(JNIEnv* env);
+extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
+extern int register_android_security_cts_AudioEffectBinderTest(JNIEnv* env);
+extern int register_android_security_cts_StagefrightFoundationTest(JNIEnv* env);
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
@@ -70,5 +74,21 @@
return JNI_ERR;
}
+ if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
+ return JNI_ERR;
+ }
+
+ if (register_android_security_cts_AudioEffectBinderTest(env)) {
+ return JNI_ERR;
+ }
+
+ if (register_android_security_cts_AudioFlingerBinderTest(env)) {
+ return JNI_ERR;
+ }
+
+ if (register_android_security_cts_StagefrightFoundationTest(env)) {
+ return JNI_ERR;
+ }
+
return JNI_VERSION_1_4;
}
diff --git a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
new file mode 100644
index 0000000..4c27416
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015 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 "AudioEffectBinderTest-JNI"
+
+#include <jni.h>
+#include <media/AudioEffect.h>
+#include <media/IEffect.h>
+
+using namespace android;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
+ */
+
+struct EffectClient : public BnEffectClient {
+ EffectClient() { }
+ virtual void controlStatusChanged(bool controlGranted __unused) { }
+ virtual void enableStatusChanged(bool enabled __unused) { }
+ virtual void commandExecuted(uint32_t cmdCode __unused,
+ uint32_t cmdSize __unused,
+ void *pCmdData __unused,
+ uint32_t replySize __unused,
+ void *pReplyData __unused) { }
+};
+
+struct DeathRecipient : public IBinder::DeathRecipient {
+ DeathRecipient() : mDied(false) { }
+ virtual void binderDied(const wp<IBinder>& who __unused) { mDied = true; }
+ bool died() const { return mDied; }
+ bool mDied;
+};
+
+static bool isIEffectCommandSecure(IEffect *effect)
+{
+ // some magic constants here
+ const int COMMAND_SIZE = 1024 + 12; // different than reply size to get different heap frag
+ char cmdData[COMMAND_SIZE];
+ memset(cmdData, 0xde, sizeof(cmdData));
+
+ const int REPLY_DATA_SIZE = 256;
+ char replyData[REPLY_DATA_SIZE];
+ bool secure = true;
+ for (int k = 0; k < 10; ++k) {
+ Parcel data;
+ data.writeInterfaceToken(effect->getInterfaceDescriptor());
+ data.writeInt32(0); // 0 is EFFECT_CMD_INIT
+ data.writeInt32(sizeof(cmdData));
+ data.write(cmdData, sizeof(cmdData));
+ data.writeInt32(sizeof(replyData));
+
+ Parcel reply;
+ status_t status = effect->asBinder(effect)->transact(3, data, &reply); // 3 is COMMAND
+ ALOGV("transact status: %d", status);
+ if (status != NO_ERROR) {
+ ALOGW("invalid transaction status %d", status);
+ continue;
+ }
+
+ ALOGV("reply data avail %zu", reply.dataAvail());
+ status = reply.readInt32();
+ ALOGV("reply status %d", status);
+ if (status == NO_ERROR) {
+ continue;
+ }
+
+ int size = reply.readInt32();
+ ALOGV("reply size %d", size);
+ if (size != sizeof(replyData)) { // we expect 0 or full reply data if command failed
+ ALOGW_IF(size != 0, "invalid reply size: %d", size);
+ continue;
+ }
+
+ // Note that if reply.read() returns success, it should completely fill replyData.
+ status = reply.read(replyData, sizeof(replyData));
+ if (status != NO_ERROR) {
+ ALOGW("invalid reply read - ignoring");
+ continue;
+ }
+ unsigned int *out = (unsigned int *)replyData;
+ for (size_t index = 0; index < sizeof(replyData) / sizeof(*out); ++index) {
+ if (out[index] != 0) {
+ secure = false;
+ ALOGI("leaked data = %#08x", out[index]);
+ }
+ }
+ }
+ ALOGI("secure: %s", secure ? "YES" : "NO");
+ return secure;
+}
+
+static jboolean android_security_cts_AudioEffect_test_isCommandSecure()
+{
+ const sp<IAudioFlinger> &audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger.get() == NULL) {
+ ALOGE("could not get audioflinger");
+ return JNI_FALSE;
+ }
+
+ static const effect_uuid_t EFFECT_UIID_EQUALIZER = // type
+ { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }};
+ sp<EffectClient> effectClient(new EffectClient());
+ effect_descriptor_t descriptor;
+ memset(&descriptor, 0, sizeof(descriptor));
+ descriptor.type = EFFECT_UIID_EQUALIZER;
+ descriptor.uuid = *EFFECT_UUID_NULL;
+ const int32_t priority = 0;
+ const int sessionId = AUDIO_SESSION_OUTPUT_MIX;
+ const audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
+ const String16 opPackageName("Exploitable");
+ status_t status;
+ int32_t id;
+ int enabled;
+ sp<IEffect> effect = audioFlinger->createEffect(&descriptor, effectClient,
+ priority, io, sessionId, opPackageName, &status, &id, &enabled);
+ if (effect.get() == NULL || status != NO_ERROR) {
+ ALOGW("could not create effect");
+ return JNI_TRUE;
+ }
+
+ sp<DeathRecipient> deathRecipient(new DeathRecipient());
+ IInterface::asBinder(effect)->linkToDeath(deathRecipient);
+
+ // check exploit
+ if (!isIEffectCommandSecure(effect.get())) {
+ ALOGE("not secure!");
+ return JNI_FALSE;
+ }
+
+ sleep(1); // wait to check death
+ if (deathRecipient->died()) {
+ ALOGE("effect binder died");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+int register_android_security_cts_AudioEffectBinderTest(JNIEnv *env)
+{
+ static JNINativeMethod methods[] = {
+ { "native_test_isCommandSecure", "()Z",
+ (void *) android_security_cts_AudioEffect_test_isCommandSecure },
+ };
+
+ jclass clazz = env->FindClass("android/security/cts/AudioEffectBinderTest");
+ return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
+}
diff --git a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
new file mode 100644
index 0000000..fb80d6b
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2015 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 "AudioFlingerBinderTest-JNI"
+
+#include <jni.h>
+#include <binder/IServiceManager.h>
+#include <media/IAudioFlinger.h>
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+using namespace android;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
+ */
+
+#define TEST_ARRAY_SIZE 10000
+#define MAX_ARRAY_SIZE 1024
+#define TEST_PATTERN 0x55
+
+class MyDeathClient: public IBinder::DeathRecipient
+{
+public:
+ MyDeathClient() :
+ mAfIsDead(false) {
+ }
+
+ bool afIsDead() const { return mAfIsDead; }
+
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who __unused) { mAfIsDead = true; }
+
+private:
+ bool mAfIsDead;
+};
+
+
+static bool connectAudioFlinger(sp<IAudioFlinger>& af, sp<MyDeathClient> &dr)
+{
+ int64_t startTime = 0;
+ while (af == 0) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16("media.audio_flinger"));
+ if (binder == 0) {
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ } else if ((uptimeMillis()-startTime) > 10000) {
+ ALOGE("timeout while getting audio flinger service");
+ return false;
+ }
+ sleep(1);
+ } else {
+ af = interface_cast<IAudioFlinger>(binder);
+ dr = new MyDeathClient();
+ binder->linkToDeath(dr);
+ }
+ }
+ return true;
+}
+
+/*
+ * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
+ * is opened.
+ */
+jboolean android_security_cts_AudioFlinger_test_setMasterMute(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ // force opening of a duplicating output
+ status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "0", "");
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ bool mute;
+ status = AudioSystem::getMasterMute(&mute);
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ AudioSystem::setMasterMute(!mute);
+
+ sleep(1);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ AudioSystem::setMasterMute(mute);
+
+ AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "0", "");
+
+ AudioSystem::setMasterMute(false);
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_setMasterVolume(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ // force opening of a duplicating output
+ status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "0", "");
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ float vol;
+ status = AudioSystem::getMasterVolume(&vol);
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ AudioSystem::setMasterVolume(vol < 0.5 ? 1.0 : 0.0);
+
+ sleep(1);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ AudioSystem::setMasterMute(vol);
+
+ AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "0", "");
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_listAudioPorts(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ unsigned int num_ports = TEST_ARRAY_SIZE;
+ struct audio_port *ports =
+ (struct audio_port *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_port));
+
+ memset(ports, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_port));
+
+ status_t status = af->listAudioPorts(&num_ports, ports);
+
+ sleep(1);
+
+ // Check that the memory content above the max allowed array size was not changed
+ char *ptr = (char *)(ports + MAX_ARRAY_SIZE);
+ for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
+ if (ptr[i * sizeof(struct audio_port)] != TEST_PATTERN) {
+ free(ports);
+ return false;
+ }
+ }
+
+ free(ports);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_listAudioPatches(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ unsigned int num_patches = TEST_ARRAY_SIZE;
+ struct audio_patch *patches =
+ (struct audio_patch *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_patch));
+
+ memset(patches, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_patch));
+
+ status_t status = af->listAudioPatches(&num_patches, patches);
+
+ sleep(1);
+
+ // Check that the memory content above the max allowed array size was not changed
+ char *ptr = (char *)(patches + MAX_ARRAY_SIZE);
+ for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
+ if (ptr[i * sizeof(struct audio_patch)] != TEST_PATTERN) {
+ free(patches);
+ return false;
+ }
+ }
+
+ free(patches);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_createEffect(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ for (int j = 0; j < 10; ++j) {
+ Parcel data, reply;
+ data.writeInterfaceToken(af->getInterfaceDescriptor());
+ data.writeInt32((int32_t)j);
+ status_t status = af->asBinder(af)->transact(40, data, &reply); // 40 is CREATE_EFFECT
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ status = (status_t)reply.readInt32();
+ if (status == NO_ERROR) {
+ continue;
+ }
+
+ int id = reply.readInt32();
+ int enabled = reply.readInt32();
+ sp<IEffect> effect = interface_cast<IEffect>(reply.readStrongBinder());
+ effect_descriptor_t desc;
+ effect_descriptor_t descTarget;
+ memset(&desc, 0, sizeof(effect_descriptor_t));
+ memset(&descTarget, 0, sizeof(effect_descriptor_t));
+ reply.read(&desc, sizeof(effect_descriptor_t));
+ if (id != 0 || enabled != 0 || memcmp(&desc, &descTarget, sizeof(effect_descriptor_t))) {
+ return false;
+ }
+ }
+
+ sleep(1);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ return true;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "native_test_setMasterMute", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_setMasterMute },
+ { "native_test_setMasterVolume", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_setMasterVolume },
+ { "native_test_listAudioPorts", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_listAudioPorts },
+ { "native_test_listAudioPatches", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_listAudioPatches },
+ { "native_test_createEffect", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_createEffect },
+};
+
+int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/security/cts/AudioFlingerBinderTest");
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
index 6807523..6011920 100644
--- a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
@@ -18,6 +18,7 @@
#include <jni.h>
#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <media/IAudioPolicyService.h>
#include <media/AudioSystem.h>
#include <system/audio.h>
@@ -151,12 +152,12 @@
return false;
}
- status_t status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
- if (status == NO_ERROR) {
+ bool status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
+ if (status) {
return false;
}
status = aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0);
- if (status == NO_ERROR) {
+ if (status) {
return false;
}
return true;
@@ -186,6 +187,64 @@
return true;
}
+jint android_security_cts_AudioPolicy_test_getStreamVolumeLeak(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioPolicyService> aps;
+
+ if (!init(aps, NULL, NULL)) {
+ return -1;
+ }
+
+ // Keep synchronized with IAudioPolicyService.cpp!
+ enum {
+ GET_STREAM_VOLUME = 17,
+ };
+
+ Parcel data, reply;
+ status_t err;
+ data.writeInterfaceToken(aps->getInterfaceDescriptor());
+ data.writeInt32(-1); // stream type
+ data.writeInt32(-1); // device
+ IInterface::asBinder(aps)->transact(GET_STREAM_VOLUME, data, &reply);
+ int index = reply.readInt32();
+ err = reply.readInt32();
+
+ return index;
+}
+
+jboolean android_security_cts_AudioPolicy_test_startAudioSource(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioPolicyService> aps;
+
+ if (!init(aps, NULL, NULL)) {
+ return false;
+ }
+
+ // Keep synchronized with IAudioPolicyService.cpp!
+ enum {
+ START_AUDIO_SOURCE = 41,
+ };
+
+ for (int i = 0; i < 10; ++i) {
+ Parcel data, reply;
+ data.writeInterfaceToken(aps->getInterfaceDescriptor());
+ data.writeInt32(-i);
+ IInterface::asBinder(aps)->transact(START_AUDIO_SOURCE, data, &reply);
+ status_t err = (status_t)reply.readInt32();
+ if (err == NO_ERROR) {
+ continue;
+ }
+ audio_io_handle_t handle = (audio_io_handle_t)reply.readInt32();
+ if (handle != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
static JNINativeMethod gMethods[] = {
{ "native_test_startOutput", "()Z",
(void *) android_security_cts_AudioPolicy_test_startOutput },
@@ -195,6 +254,10 @@
(void *) android_security_cts_AudioPolicy_test_isStreamActive },
{ "native_test_isStreamActiveRemotely", "()Z",
(void *) android_security_cts_AudioPolicy_test_isStreamActiveRemotely },
+ { "native_test_getStreamVolumeLeak", "()I",
+ (void *) android_security_cts_AudioPolicy_test_getStreamVolumeLeak },
+ { "native_test_startAudioSource", "()Z",
+ (void *) android_security_cts_AudioPolicy_test_startAudioSource },
};
int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env)
diff --git a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
new file mode 100644
index 0000000..0c61f25
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 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 "MediaPlayerInfoLeakTest-JNI"
+
+#include <jni.h>
+
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+
+#include <media/IMediaPlayer.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaPlayerClient.h>
+
+#include <sys/stat.h>
+
+using namespace android;
+
+static status_t connectMediaPlayer(sp<IMediaPlayer>& iMP)
+{
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
+
+ sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
+ sp<IMediaPlayerClient> client;
+ Parcel data, reply;
+ int dummyAudioSessionId = 1;
+ data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(client));
+ data.writeInt32(dummyAudioSessionId);
+
+ // Keep synchronized with IMediaPlayerService.cpp!
+ enum {
+ CREATE = IBinder::FIRST_CALL_TRANSACTION,
+ };
+ status_t err = IInterface::asBinder(iMPService)->transact(CREATE, data, &reply);
+ if (err == NO_ERROR) {
+ iMP = interface_cast<IMediaPlayer>(reply.readStrongBinder());
+ }
+ return err;
+}
+
+int testMediaPlayerInfoLeak(int command)
+{
+ sp<IMediaPlayer> iMP;
+ if (NO_ERROR != connectMediaPlayer(iMP)) {
+ return false;
+ }
+
+
+ Parcel data, reply;
+ data.writeInterfaceToken(iMP->getInterfaceDescriptor());
+ IInterface::asBinder(iMP)->transact(command, data, &reply);
+
+ int leak = reply.readInt32();
+ status_t err = reply.readInt32();
+ return leak;
+}
+
+jint android_security_cts_MediaPlayer_test_getCurrentPositionLeak(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ // Keep synchronized with IMediaPlayer.cpp!
+ enum {
+ GET_CURRENT_POSITION = 16,
+ };
+ return testMediaPlayerInfoLeak(GET_CURRENT_POSITION);
+}
+
+jint android_security_cts_MediaPlayer_test_getDurationLeak(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ // Keep synchronized with IMediaPlayer.cpp!
+ enum {
+ GET_DURATION = 17,
+ };
+ return testMediaPlayerInfoLeak(GET_DURATION);
+}
+
+static JNINativeMethod gMethods[] = {
+ { "native_test_getCurrentPositionLeak", "()I",
+ (void *) android_security_cts_MediaPlayer_test_getCurrentPositionLeak },
+ { "native_test_getDurationLeak", "()I",
+ (void *) android_security_cts_MediaPlayer_test_getDurationLeak },
+};
+
+int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/security/cts/MediaPlayerInfoLeakTest");
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/security/jni/android_security_cts_StagefrightFoundationTest.cpp b/tests/tests/security/jni/android_security_cts_StagefrightFoundationTest.cpp
new file mode 100644
index 0000000..d16bd38
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_StagefrightFoundationTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 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 "AudioEffectBinderTest-JNI"
+
+#include <cstdio>
+#include <jni.h>
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+using namespace android;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java
+ */
+
+static jboolean android_security_cts_StagefrightFoundation_test_aMessageFromParcel(
+ JNIEnv* env __unused, jobject thiz __unused)
+{
+ const int kMaxNumItems = 64;
+ const int kNumItems = kMaxNumItems + 1 + 1000;
+ char name[128];
+
+ Parcel data;
+ data.writeInt32(0); // what
+ data.writeInt32(kNumItems); // numItems
+ for (int i = 0; i < kMaxNumItems; ++i) {
+ snprintf(name, sizeof(name), "item-%d", i);
+ data.writeCString(name); // name
+ data.writeInt32(0); // kTypeInt32
+ data.writeInt32(i); // value
+ }
+ data.writeCString("evil"); // name
+ data.writeInt32(0); // kTypeInt32
+ data.writeInt32(0); // value
+ // NOTE: This could overwrite mNumItems!
+
+ for (int i = 0; i < 1000; ++i) {
+ snprintf(name, sizeof(name), "evil-%d", i);
+ data.writeCString(name); // name
+ data.writeInt32(0); // kTypeInt32
+ data.writeInt32(0); // value
+ }
+
+ data.setDataPosition(0);
+ sp<AMessage> msg = AMessage::FromParcel(data);
+
+ for (int i = 0; i < kMaxNumItems; ++i) {
+ snprintf(name, sizeof(name), "item-%d", i);
+ int32_t value;
+ if (!msg->findInt32(name, &value)) {
+ ALOGE("cannot find value for %s", name);
+ return JNI_FALSE;
+ }
+ if (value != i) {
+ ALOGE("value is changed: expected %d actual %d", i, value);
+ return JNI_FALSE;
+ }
+ }
+ return JNI_TRUE;
+}
+
+int register_android_security_cts_StagefrightFoundationTest(JNIEnv *env)
+{
+ static JNINativeMethod methods[] = {
+ { "native_test_aMessageFromParcel", "()Z",
+ (void *) android_security_cts_StagefrightFoundation_test_aMessageFromParcel},
+ };
+
+ jclass clazz = env->FindClass("android/security/cts/StagefrightFoundationTest");
+ return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
+}
diff --git a/tests/tests/security/res/raw/cve_2015_1538_1.mp4 b/tests/tests/security/res/raw/cve_2015_1538_1.mp4
new file mode 100644
index 0000000..9e665ea
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_1538_1.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_1538_2.mp4 b/tests/tests/security/res/raw/cve_2015_1538_2.mp4
new file mode 100644
index 0000000..e01cae6
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_1538_2.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_1538_3.mp4 b/tests/tests/security/res/raw/cve_2015_1538_3.mp4
new file mode 100644
index 0000000..9838036
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_1538_3.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_1538_4.mp4 b/tests/tests/security/res/raw/cve_2015_1538_4.mp4
new file mode 100644
index 0000000..14f88d8
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_1538_4.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_1539.mp4 b/tests/tests/security/res/raw/cve_2015_1539.mp4
new file mode 100644
index 0000000..de871b6
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_1539.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3824.mp4 b/tests/tests/security/res/raw/cve_2015_3824.mp4
new file mode 100644
index 0000000..4ff2220
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3824.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3826.mp4 b/tests/tests/security/res/raw/cve_2015_3826.mp4
new file mode 100644
index 0000000..e0d2300
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3826.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3827.mp4 b/tests/tests/security/res/raw/cve_2015_3827.mp4
new file mode 100644
index 0000000..7b58cf9
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3827.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3828.mp4 b/tests/tests/security/res/raw/cve_2015_3828.mp4
new file mode 100644
index 0000000..033902d
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3828.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3829.mp4 b/tests/tests/security/res/raw/cve_2015_3829.mp4
new file mode 100644
index 0000000..71062bc
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3829.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3864.mp4 b/tests/tests/security/res/raw/cve_2015_3864.mp4
new file mode 100644
index 0000000..fc0af68
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3864.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_6598.mp3 b/tests/tests/security/res/raw/cve_2015_6598.mp3
new file mode 100644
index 0000000..ee709e4
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_6598.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/midi_crash.midi b/tests/tests/security/res/raw/midi_crash.midi
new file mode 100644
index 0000000..1880229
--- /dev/null
+++ b/tests/tests/security/res/raw/midi_crash.midi
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java b/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
new file mode 100644
index 0000000..20d9615
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 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 android.media.audiofx.AudioEffect;
+
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+public class AudioEffectBinderTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+ /**
+ * Checks that IEffect::command() cannot leak data.
+ */
+ public void test_isCommandSecure() throws Exception {
+ if (isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
+ assertTrue(native_test_isCommandSecure());
+ }
+ }
+
+ /* see AudioEffect.isEffectTypeAvailable(), implements hidden function */
+ private static boolean isEffectTypeAvailable(UUID type) {
+ AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+ if (desc == null) {
+ return false;
+ }
+
+ for (int i = 0; i < desc.length; i++) {
+ if (desc[i].type.equals(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static native boolean native_test_isCommandSecure();
+}
diff --git a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
new file mode 100644
index 0000000..202bd65
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 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;
+
+public class AudioFlingerBinderTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+ /**
+ * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
+ * is opened.
+ */
+ public void test_setMasterMute() throws Exception {
+ assertTrue(native_test_setMasterMute());
+ }
+
+ /**
+ * Checks that AudioSystem::setMasterVolume() does not crash mediaserver if a duplicated output
+ * is opened.
+ */
+ public void test_setMasterVolume() throws Exception {
+ assertTrue(native_test_setMasterVolume());
+ }
+
+ /**
+ * Checks that IAudioFlinger::listAudioPorts() does not cause a memory overflow when passed a
+ * large number of ports.
+ */
+ public void test_listAudioPorts() throws Exception {
+ assertTrue(native_test_listAudioPorts());
+ }
+
+ /**
+ * Checks that IAudioFlinger::listAudioPatches() does not cause a memory overflow when passed a
+ * large number of ports.
+ */
+ public void test_listAudioPatches() throws Exception {
+ assertTrue(native_test_listAudioPatches());
+ }
+
+ /**
+ * Checks that IAudioFlinger::createEffect() does not leak information on the server side.
+ */
+ public void test_createEffect() throws Exception {
+ assertTrue(native_test_createEffect());
+ }
+
+ private static native boolean native_test_setMasterMute();
+ private static native boolean native_test_setMasterVolume();
+ private static native boolean native_test_listAudioPorts();
+ private static native boolean native_test_listAudioPatches();
+ private static native boolean native_test_createEffect();
+}
diff --git a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
index b307247..82346a1 100644
--- a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
+++ b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
@@ -56,8 +56,27 @@
assertTrue(native_test_isStreamActiveRemotely());
}
+ /**
+ * Checks that IAudioPolicyService::getStreamVolumeIndex() does not leak information
+ * when called with an invalid stream/device type.
+ */
+ public void test_getStreamVolumeLeak() throws Exception {
+ int volume = native_test_getStreamVolumeLeak();
+ assertTrue(String.format("Leaked volume 0x%08X", volume), volume == 0);
+ }
+
+ /**
+ * Checks that IAudioPolicyService::startAudioSource() cannot leak information from
+ * server side.
+ */
+ public void test_startAudioSource() throws Exception {
+ assertTrue(native_test_startAudioSource());
+ }
+
private static native boolean native_test_startOutput();
private static native boolean native_test_stopOutput();
private static native boolean native_test_isStreamActive();
private static native boolean native_test_isStreamActiveRemotely();
+ private static native int native_test_getStreamVolumeLeak();
+ private static native boolean native_test_startAudioSource();
}
diff --git a/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java b/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java
index d188aab..19866de 100644
--- a/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java
+++ b/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java
@@ -26,7 +26,8 @@
import android.security.cts.activity.ISecureRandomService;
import android.security.cts.activity.SecureRandomService;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.cts.util.TimeoutReq;
import java.io.BufferedReader;
import java.io.EOFException;
@@ -37,7 +38,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-@LargeTest
public class ClonedSecureRandomTest extends AndroidTestCase {
private static final int MAX_SHUTDOWN_TRIES = 50;
@@ -93,6 +93,7 @@
* sees two newly started processes with the same PID and compares their
* output.
*/
+ @TimeoutReq(minutes=15)
public void testCheckForDuplicateOutput() throws Exception {
assertEquals("Only supports up to " + MAX_PID + " because of memory requirements",
Integer.toString(MAX_PID), getFirstLineFromFile("/proc/sys/kernel/pid_max"));
diff --git a/tests/tests/security/src/android/security/cts/ListeningPortsTest.java b/tests/tests/security/src/android/security/cts/ListeningPortsTest.java
index 87e957d..54fa406 100644
--- a/tests/tests/security/src/android/security/cts/ListeningPortsTest.java
+++ b/tests/tests/security/src/android/security/cts/ListeningPortsTest.java
@@ -18,11 +18,14 @@
import android.content.pm.PackageManager;
import android.test.AndroidTestCase;
+import android.util.Log;
import junit.framework.AssertionFailedError;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -37,15 +40,31 @@
* is considered a security best practice.
*/
public class ListeningPortsTest extends AndroidTestCase {
+ private static final String TAG = "ListeningPortsTest";
+
+ private static final int CONN_TIMEOUT_IN_MS = 5000;
/** Ports that are allowed to be listening. */
private static final List<String> EXCEPTION_PATTERNS = new ArrayList<String>(6);
static {
// IPv4 exceptions
- EXCEPTION_PATTERNS.add("0.0.0.0:5555"); // emulator port
- EXCEPTION_PATTERNS.add("10.0.2.15:5555"); // net forwarding for emulator
- EXCEPTION_PATTERNS.add("127.0.0.1:5037"); // adb daemon "smart sockets"
+ // Patterns containing ":" are allowed address port combinations
+ // Pattterns contains " " are allowed address UID combinations
+ // Patterns containing both are allowed address, port, and UID combinations
+ EXCEPTION_PATTERNS.add("0.0.0.0:5555"); // emulator port
+ EXCEPTION_PATTERNS.add("0.0.0.0:9101"); // verified ports
+ EXCEPTION_PATTERNS.add("0.0.0.0:9551"); // verified ports
+ EXCEPTION_PATTERNS.add("0.0.0.0:9552"); // verified ports
+ EXCEPTION_PATTERNS.add("10.0.2.15:5555"); // net forwarding for emulator
+ EXCEPTION_PATTERNS.add("127.0.0.1:5037"); // adb daemon "smart sockets"
+ EXCEPTION_PATTERNS.add("0.0.0.0 1020"); // used by the cast receiver
+ EXCEPTION_PATTERNS.add("0.0.0.0 10000"); // used by the cast receiver
+ EXCEPTION_PATTERNS.add("127.0.0.1 10000"); // used by the cast receiver
+ EXCEPTION_PATTERNS.add(":: 1002"); // used by remote control
+ EXCEPTION_PATTERNS.add(":: 1020"); // used by remote control
+ //no current patterns involve address, port and UID combinations
+ //Example for when necessary: EXCEPTION_PATTERNS.add("0.0.0.0:5555 10000")
}
/**
@@ -185,10 +204,16 @@
List<ParsedProcEntry> entries = ParsedProcEntry.parse(procFilePath);
for (ParsedProcEntry entry : entries) {
String addrPort = entry.localAddress.getHostAddress() + ':' + entry.port;
+ String addrUid = entry.localAddress.getHostAddress() + ' ' + entry.uid;
+ String addrPortUid = addrPort + ' ' + entry.uid;
if (isPortListening(entry.state, isTcp)
- && !isException(addrPort)
- && (!entry.localAddress.isLoopbackAddress() ^ loopback)) {
+ && !(isException(addrPort) || isException(addrUid) || isException(addrPortUid))
+ && (!entry.localAddress.isLoopbackAddress() ^ loopback)) {
+ if (isTcp && !isTcpConnectable(entry.localAddress, entry.port)) {
+ continue;
+ }
+
errors += "\nFound port listening on addr="
+ entry.localAddress.getHostAddress() + ", port="
+ entry.port + ", UID=" + entry.uid
@@ -210,6 +235,33 @@
return Arrays.asList(packages).toString();
}
+ private boolean isTcpConnectable(InetAddress address, int port) {
+ Socket socket = new Socket();
+
+ try {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Trying to connect " + address + ":" + port);
+ }
+ socket.connect(new InetSocketAddress(address, port), CONN_TIMEOUT_IN_MS);
+ } catch (IOException ioe) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unable to connect:" + ioe);
+ }
+ return false;
+ } finally {
+ try {
+ socket.close();
+ } catch (IOException closeError) {
+ Log.e(TAG, "Unable to close socket: " + closeError);
+ }
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, address + ":" + port + " is connectable.");
+ }
+ return true;
+ }
+
private static boolean isException(String localAddress) {
return isPatternMatch(EXCEPTION_PATTERNS, localAddress);
}
diff --git a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
new file mode 100644
index 0000000..e34fc05
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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;
+
+public class MediaPlayerInfoLeakTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+
+ /**
+ * Checks that IMediaPlayer::getCurrentPosition() does not leak info in error case
+ */
+ public void test_getCurrentPositionLeak() throws Exception {
+ int pos = native_test_getCurrentPositionLeak();
+ assertTrue(String.format("Leaked pos 0x%08X", pos), pos == 0);
+ }
+
+ /**
+ * Checks that IMediaPlayer::getDuration() does not leak info in error case
+ */
+ public void test_getDurationLeak() throws Exception {
+ int dur = native_test_getDurationLeak();
+ assertTrue(String.format("Leaked dur 0x%08X", dur), dur == 0);
+ }
+
+ private static native int native_test_getCurrentPositionLeak();
+ private static native int native_test_getDurationLeak();
+}
diff --git a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
new file mode 100644
index 0000000..4dc6783
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 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 android.content.res.AssetFileDescriptor;
+import android.media.MediaPlayer;
+import android.os.ConditionVariable;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.cts.security.R;
+
+public class MediaServerCrashTest extends AndroidTestCase {
+ private static final String TAG = "MediaServerCrashTest";
+
+ public void testInvalidMidiNullPointerAccess() throws Exception {
+ testIfMediaServerDied(R.raw.midi_crash);
+ }
+
+ private void testIfMediaServerDied(int res) throws Exception {
+ final MediaPlayer mediaPlayer = new MediaPlayer();
+ final ConditionVariable onPrepareCalled = new ConditionVariable();
+ final ConditionVariable onCompletionCalled = new ConditionVariable();
+
+ onPrepareCalled.close();
+ onCompletionCalled.close();
+ mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ assertTrue(mp == mediaPlayer);
+ assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ Log.w(TAG, "onError " + what);
+ return false;
+ }
+ });
+
+ mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ assertTrue(mp == mediaPlayer);
+ onPrepareCalled.open();
+ }
+ });
+
+ mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ assertTrue(mp == mediaPlayer);
+ onCompletionCalled.open();
+ }
+ });
+
+ AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(res);
+ mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ try {
+ mediaPlayer.prepareAsync();
+ if (!onPrepareCalled.block(5000)) {
+ Log.w(TAG, "testIfMediaServerDied: Timed out waiting for prepare");
+ return;
+ }
+ mediaPlayer.start();
+ if (!onCompletionCalled.block(5000)) {
+ Log.w(TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "playback failed", e);
+ } finally {
+ mediaPlayer.release();
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/PutOverflowTest.java b/tests/tests/security/src/android/security/cts/PutOverflowTest.java
new file mode 100644
index 0000000..e0eb34c
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PutOverflowTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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 android.test.AndroidTestCase;
+import java.lang.reflect.Method;
+
+public class PutOverflowTest extends AndroidTestCase {
+ public void testCrash() throws Exception {
+ try {
+ Class<?> keystoreClass = Class.forName("android.security.KeyStore");
+ Method getInstance = keystoreClass.getMethod("getInstance");
+ Method put = keystoreClass.getMethod("put",
+ String.class, byte[].class, int.class, int.class);
+ Object keystore = getInstance.invoke(null);
+ byte[] buffer = new byte[65536];
+ Boolean result = (Boolean)put.invoke(keystore, "crashFile", buffer, -1, 0);
+ assertTrue("Fix for ANDROID-22802399 not present", result);
+ } catch (ReflectiveOperationException ignored) {
+ // Since this test requires reflection avoid causing undue failures if classes or
+ // methods were changed.
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index 00cbfd8..fdc3058 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -17,6 +17,7 @@
package android.security.cts;
import android.os.IBinder;
+import android.os.DeadObjectException;
import android.os.TransactionTooLargeException;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -108,7 +109,7 @@
// probably not checking for DUMP.
throw e;
}
- } catch (TransactionTooLargeException e) {
+ } catch (TransactionTooLargeException | DeadObjectException e) {
// SELinux likely prevented the dump - assume safe
continue;
} finally {
diff --git a/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java b/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java
new file mode 100644
index 0000000..9999d88
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/StagefrightFoundationTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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;
+
+public class StagefrightFoundationTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+ /**
+ * Checks that IEffect::command() cannot leak data.
+ */
+ public void test_aMessageFromParcel() throws Exception {
+ assertTrue(native_test_aMessageFromParcel());
+ }
+
+ private static native boolean native_test_aMessageFromParcel();
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
new file mode 100644
index 0000000..0f79860
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ *
+ * This code was provided to AOSP by Zimperium Inc and was
+ * written by:
+ *
+ * Simone "evilsocket" Margaritelli
+ * Joshua "jduck" Drake
+ */
+package android.security.cts;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.MediaPlayer;
+import android.os.Looper;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.android.cts.security.R;
+
+
+/**
+ * Verify that the device is not vulnerable to any known Stagefright
+ * vulnerabilities.
+ */
+public class StagefrightTest extends InstrumentationTestCase {
+ static final String TAG = "StagefrightTest";
+
+ public StagefrightTest() {
+ }
+
+ public void testStagefright_cve_2015_1538_1() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_1538_1);
+ }
+
+ public void testStagefright_cve_2015_1538_2() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_1538_2);
+ }
+
+ public void testStagefright_cve_2015_1538_3() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_1538_3);
+ }
+
+ public void testStagefright_cve_2015_1538_4() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_1538_4);
+ }
+
+ public void testStagefright_cve_2015_1539() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_1539);
+ }
+
+ public void testStagefright_cve_2015_3824() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3824);
+ }
+
+ public void testStagefright_cve_2015_3826() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3826);
+ }
+
+ public void testStagefright_cve_2015_3827() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3827);
+ }
+
+ public void testStagefright_cve_2015_3828() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3828);
+ }
+
+ public void testStagefright_cve_2015_3829() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3829);
+ }
+
+ public void testStagefright_cve_2015_3864() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3864);
+ }
+
+ public void testStagefright_cve_2015_6598() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_6598);
+ }
+
+ private void doStagefrightTest(final int rid) throws Exception {
+ class MediaPlayerCrashListener
+ implements MediaPlayer.OnErrorListener,
+ MediaPlayer.OnPreparedListener,
+ MediaPlayer.OnCompletionListener {
+ @Override
+ public boolean onError(MediaPlayer mp, int newWhat, int extra) {
+ what = newWhat;
+ lock.lock();
+ condition.signal();
+ lock.unlock();
+
+ return true; // don't call oncompletion
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ mp.start();
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ what = 0;
+ lock.lock();
+ condition.signal();
+ lock.unlock();
+ }
+
+ public int waitForError() throws InterruptedException {
+ lock.lock();
+ condition.await();
+ lock.unlock();
+ return what;
+ }
+
+ ReentrantLock lock = new ReentrantLock();
+ Condition condition = lock.newCondition();
+ int what;
+ }
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ Looper.prepare();
+
+ MediaPlayer mp = new MediaPlayer();
+ mp.setOnErrorListener(mpcl);
+ mp.setOnPreparedListener(mpcl);
+ mp.setOnCompletionListener(mpcl);
+ try {
+ AssetFileDescriptor fd = getInstrumentation().getContext().getResources()
+ .openRawResourceFd(rid);
+
+ mp.setDataSource(fd.getFileDescriptor(),
+ fd.getStartOffset(),
+ fd.getLength());
+
+ mp.prepareAsync();
+ } catch (Exception e) {
+ }
+
+ Looper.loop();
+ mp.release();
+ }
+ });
+
+ t.start();
+ String name = getInstrumentation().getContext().getResources().getResourceEntryName(rid);
+ String cve = name.replace("_", "-").toUpperCase();
+ assertFalse("Device *IS* vulnerable to " + cve,
+ mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ t.interrupt();
+ }
+}