Add cts test for removal of installDrmEngine

b/9545965

Change-Id: I45d5d9e91600126429f27e8171b3e3a1f1ae83a4
diff --git a/tests/tests/drm/Android.mk b/tests/tests/drm/Android.mk
index 3264c32..8b76cd8 100644
--- a/tests/tests/drm/Android.mk
+++ b/tests/tests/drm/Android.mk
@@ -16,8 +16,8 @@
 
 include $(CLEAR_VARS)
 
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
+
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
@@ -31,7 +31,13 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
+LOCAL_JNI_SHARED_LIBRARIES := \
+	libctsdrm_jni \
+	libdrmtestplugin
+
 # uncomment when dalvik.annotation.Test* are removed or part of SDK
 #LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/drm/jni/Android.mk b/tests/tests/drm/jni/Android.mk
new file mode 100644
index 0000000..06b2df9
--- /dev/null
+++ b/tests/tests/drm/jni/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libctsdrm_jni
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+		CtsDrmJniOnLoad.cpp \
+		android_drm_cts_NativeCodeTest.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := liblog libdl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/drm/jni/CtsDrmJniOnLoad.cpp b/tests/tests/drm/jni/CtsDrmJniOnLoad.cpp
new file mode 100644
index 0000000..a9ec3da
--- /dev/null
+++ b/tests/tests/drm/jni/CtsDrmJniOnLoad.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 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 <stdio.h>
+
+extern int register_android_drm_cts_NativeCodeTest(JNIEnv*);
+
+jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+    JNIEnv *env = NULL;
+
+    if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
+        return JNI_ERR;
+    }
+
+    if (register_android_drm_cts_NativeCodeTest(env)) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_4;
+}
diff --git a/tests/tests/drm/jni/android_drm_cts_NativeCodeTest.cpp b/tests/tests/drm/jni/android_drm_cts_NativeCodeTest.cpp
new file mode 100644
index 0000000..398a44e
--- /dev/null
+++ b/tests/tests/drm/jni/android_drm_cts_NativeCodeTest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 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 <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <utils/Log.h>
+
+/*
+ * Returns true iff this device may be vulnerable to installation of rogue drm
+ * plugins, as determined by the existance of the _installDrmEngine symbol in the
+ * libdrmframework_jni.so library.
+ */
+static jboolean android_drm_cts_InstallDrmEngineTest(JNIEnv* env, jobject thiz)
+{
+    jboolean result = false;
+
+    // install /system/lib/libdrmtestplugin.so
+    FILE *f = popen("service call drm.drmManager 6 i32 0 i32 31 i32 1937339183 i32 795698548 "
+                    "i32 794978668 i32 1684171116 i32 1702129010 i32 1819309171 i32 1852401525 "
+                    "i32 7303982 i32 1598902849", "r");
+    if (f) {
+        char buffer[128];
+        if (fgets(buffer, sizeof(buffer), f) != NULL) {
+            const char *match = "Result: Parcel(00000000    '....')";
+            if (!strncmp(buffer, match, strlen(match))) {
+                result = true;
+            }
+        }
+        pclose(f);
+    }
+    return result;
+}
+
+static JNINativeMethod gMethods[] = {
+    {  "doInstallDrmEngineTest", "()Z",
+       (void *) android_drm_cts_InstallDrmEngineTest },
+};
+
+int register_android_drm_cts_NativeCodeTest(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("android/drm/cts/NativeCodeTest");
+    return env->RegisterNatives(clazz, gMethods,
+            sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/drm/lib/Android.mk b/tests/tests/drm/lib/Android.mk
new file mode 100644
index 0000000..3ebc4a0
--- /dev/null
+++ b/tests/tests/drm/lib/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libdrmtestplugin
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+		TestPlugin.cpp
+
+LOCAL_C_INCLUDES := \
+	$(JNI_H_INCLUDE) \
+	$(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libutils
+
+LOCAL_STATIC_LIBRARIES := \
+	libdrmframeworkcommon
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/drm/lib/TestPlugin.cpp b/tests/tests/drm/lib/TestPlugin.cpp
new file mode 100644
index 0000000..d32ff96
--- /dev/null
+++ b/tests/tests/drm/lib/TestPlugin.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2010 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_NDEBUG 0
+#define LOG_TAG "TestPlugin"
+#include <utils/Log.h>
+
+#include <drm/DrmRights.h>
+#include <drm/DrmConstraints.h>
+#include <drm/DrmMetadata.h>
+#include <drm/DrmInfo.h>
+#include <drm/DrmInfoEvent.h>
+#include <drm/DrmInfoStatus.h>
+#include <drm/DrmConvertedStatus.h>
+#include <drm/DrmInfoRequest.h>
+#include <drm/DrmSupportInfo.h>
+#include <TestPlugin.h>
+
+using namespace android;
+
+
+// This extern "C" is mandatory to be managed by TPlugInManager
+extern "C" IDrmEngine* create() {
+    return new TestPlugIn();
+}
+
+// This extern "C" is mandatory to be managed by TPlugInManager
+extern "C" void destroy(IDrmEngine* pPlugIn) {
+    delete pPlugIn;
+    pPlugIn = NULL;
+}
+
+TestPlugIn::TestPlugIn()
+    : DrmEngineBase() {
+
+}
+
+TestPlugIn::~TestPlugIn() {
+
+}
+
+DrmMetadata* TestPlugIn::onGetMetadata(int uniqueId, const String8* path) {
+    return NULL;
+}
+
+DrmConstraints* TestPlugIn::onGetConstraints(
+        int uniqueId, const String8* path, int action) {
+    return NULL;
+}
+
+DrmInfoStatus* TestPlugIn::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+    return NULL;
+}
+
+status_t TestPlugIn::onSetOnInfoListener(
+            int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onInitialize(int uniqueId) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onTerminate(int uniqueId) {
+    return DRM_NO_ERROR;
+}
+
+DrmSupportInfo* TestPlugIn::onGetSupportInfo(int uniqueId) {
+    DrmSupportInfo* drmSupportInfo = new DrmSupportInfo();
+    return drmSupportInfo;
+}
+
+status_t TestPlugIn::onSaveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath) {
+    return DRM_NO_ERROR;
+}
+
+DrmInfo* TestPlugIn::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+    return NULL;
+}
+
+bool TestPlugIn::onCanHandle(int uniqueId, const String8& path) {
+    return false;
+}
+
+String8 TestPlugIn::onGetOriginalMimeType(int uniqueId, const String8& path) {
+    return String8("video/none");
+}
+
+int TestPlugIn::onGetDrmObjectType(
+            int uniqueId, const String8& path, const String8& mimeType) {
+    return DrmObjectType::UNKNOWN;
+}
+
+int TestPlugIn::onCheckRightsStatus(int uniqueId, const String8& path, int action) {
+    int rightsStatus = RightsStatus::RIGHTS_VALID;
+    return rightsStatus;
+}
+
+status_t TestPlugIn::onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+            int action, bool reserve) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+            int playbackStatus, int64_t position) {
+    return DRM_NO_ERROR;
+}
+
+bool TestPlugIn::onValidateAction(int uniqueId, const String8& path,
+            int action, const ActionDescription& description) {
+    return true;
+}
+
+status_t TestPlugIn::onRemoveRights(int uniqueId, const String8& path) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onRemoveAllRights(int uniqueId) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onOpenConvertSession(int uniqueId, int convertId) {
+    return DRM_NO_ERROR;
+}
+
+DrmConvertedStatus* TestPlugIn::onConvertData(
+            int uniqueId, int convertId, const DrmBuffer* inputData) {
+    return new DrmConvertedStatus(DrmConvertedStatus::STATUS_OK, NULL, 0);
+}
+
+DrmConvertedStatus* TestPlugIn::onCloseConvertSession(int uniqueId, int convertId) {
+    return new DrmConvertedStatus(DrmConvertedStatus::STATUS_OK, NULL, 0);
+}
+
+status_t TestPlugIn::onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, int fd, off64_t offset, off64_t length) {
+    return DRM_ERROR_CANNOT_HANDLE;
+}
+
+status_t TestPlugIn::onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, const char* uri) {
+    return DRM_ERROR_CANNOT_HANDLE;
+}
+
+status_t TestPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+    return DRM_NO_ERROR;
+}
+
+status_t TestPlugIn::onFinalizeDecryptUnit(
+            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    return DRM_NO_ERROR;
+}
+
+ssize_t TestPlugIn::onPread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off64_t offset) {
+    return 0;
+}
+
diff --git a/tests/tests/drm/lib/TestPlugin.h b/tests/tests/drm/lib/TestPlugin.h
new file mode 100644
index 0000000..3499aa0
--- /dev/null
+++ b/tests/tests/drm/lib/TestPlugin.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef __DRM_TEST_PLUGIN_H__
+#define __DRM_TEST_PLUGIN_H__
+
+#include <DrmEngineBase.h>
+
+namespace android {
+
+class TestPlugIn : public DrmEngineBase {
+
+public:
+    TestPlugIn();
+    virtual ~TestPlugIn();
+
+protected:
+    DrmConstraints* onGetConstraints(int uniqueId, const String8* path, int action);
+
+    DrmMetadata* onGetMetadata(int uniqueId, const String8* path);
+
+    status_t onInitialize(int uniqueId);
+
+    status_t onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
+
+    status_t onTerminate(int uniqueId);
+
+    bool onCanHandle(int uniqueId, const String8& path);
+
+    DrmInfoStatus* onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+    status_t onSaveRights(int uniqueId, const DrmRights& drmRights,
+            const String8& rightsPath, const String8& contentPath);
+
+    DrmInfo* onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
+
+    String8 onGetOriginalMimeType(int uniqueId, const String8& path);
+
+    int onGetDrmObjectType(int uniqueId, const String8& path, const String8& mimeType);
+
+    int onCheckRightsStatus(int uniqueId, const String8& path, int action);
+
+    status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+
+    status_t onSetPlaybackStatus(
+            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+
+    bool onValidateAction(
+            int uniqueId, const String8& path, int action, const ActionDescription& description);
+
+    status_t onRemoveRights(int uniqueId, const String8& path);
+
+    status_t onRemoveAllRights(int uniqueId);
+
+    status_t onOpenConvertSession(int uniqueId, int convertId);
+
+    DrmConvertedStatus* onConvertData(int uniqueId, int convertId, const DrmBuffer* inputData);
+
+    DrmConvertedStatus* onCloseConvertSession(int uniqueId, int convertId);
+
+    DrmSupportInfo* onGetSupportInfo(int uniqueId);
+
+    status_t onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, int fd, off64_t offset, off64_t length);
+
+    status_t onOpenDecryptSession(
+            int uniqueId, DecryptHandle* decryptHandle, const char* uri);
+
+    status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+
+    status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+            int decryptUnitId, const DrmBuffer* headerInfo);
+
+    status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
+
+    status_t onFinalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+
+    ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+            void* buffer, ssize_t numBytes, off64_t offset);
+
+private:
+    DecryptHandle* openDecryptSessionImpl();
+};
+
+};
+
+#endif /* __DRM_TEST_PLUGIN_H__ */
diff --git a/tests/tests/drm/src/android/drm/cts/NativeCodeTest.java b/tests/tests/drm/src/android/drm/cts/NativeCodeTest.java
new file mode 100644
index 0000000..856cb88
--- /dev/null
+++ b/tests/tests/drm/src/android/drm/cts/NativeCodeTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 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.drm.cts;
+
+import junit.framework.TestCase;
+
+public class NativeCodeTest extends TestCase {
+
+    static {
+        System.loadLibrary("ctsdrm_jni");
+    }
+
+    public void testInstallDrmEngine() throws Exception {
+        assertFalse("Device is vulnerable to arbitrary code execution in drmserver process.",
+                    doInstallDrmEngineTest());
+    }
+
+    /**
+     * Returns true iff this device is vulnerable to arbitrary code execution in drm server
+     */
+    private static native boolean doInstallDrmEngineTest();
+}