FPII-1886:CR:935198-Several information exposure vulnerabilities in Mediaserver can permit a bypass of security checks.

1. Made changes to clear config before reading it from parcel in IAudioFlinger
2. Added initialization of variables and ensure no info leak when writing them to Parcel.
3. Added initialization of local variables to avoid data leak
Files affected
media/libmedia/IAudioFlinger.cpp
media/libmedia/IAudioPolicyService.cpp
Bug: 23540907
Change-Id:Ie8eb867ffc52251446e12b712cb28ddc95429fcd
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 46d0868..cbf0756 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -32,7 +32,8 @@
 		android_security_cts_SELinuxTest.cpp \
 		android_security_cts_MMapExecutableTest.cpp \
 		android_security_cts_NetlinkSocket.cpp \
-		android_security_cts_AudioPolicyBinderTest.cpp
+		android_security_cts_AudioPolicyBinderTest.cpp \
+		android_security_cts_AudioEffectBinderTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index ca8e841..75ebf66 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -27,6 +27,7 @@
 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_AudioEffectBinderTest(JNIEnv* env);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
@@ -75,5 +76,9 @@
         return JNI_ERR;
     }
 
+    if (register_android_security_cts_AudioEffectBinderTest(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..25f3f80
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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()->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 = 0; // AUDIO_IO_HANDLE_NONE
+    status_t status;
+    int32_t id;
+    int enabled;
+    sp<IEffect> effect = audioFlinger->createEffect(&descriptor, effectClient,
+            priority, io, sessionId, &status, &id, &enabled);
+    if (effect.get() == NULL || status != NO_ERROR) {
+        ALOGW("could not create effect");
+        return JNI_TRUE;
+    }
+
+    sp<DeathRecipient> deathRecipient(new DeathRecipient());
+    effect->asBinder()->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/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();
+}