Restrict Automerge: Fix reinterpret_cast security bug

This patch fixes a security bug in SurfaceFlinger.  Bug is due to a
reinterpret_cast used when obtaining a sp<Layer> from an sp<IBinder> passed
from a client.  Without a checking mechanism, client could pass a
malicious data packet.  This is a modified cherry-pick of a patch by Rob Carr
that utilizes a map to identify the appropriate layer based on
the incoming IBinder token.

Original patch commit:

"Author: Robert Carr <racarr@google.com>
Date:   Thu Apr 11 13:18:21 2019 -0700

SurfaceFlinger: Validate layers before casting.

Reinterpret casting random IBinder = no-fun. I first attempted
to use inheritance of "getInterfaceDescriptor" in Layer::Handle but
departing from "standard-layout" (e.g. using virtual methods) means that
downcasting with static/reinterpret_cast is no longer valid. Instead I opted
for the pattern the system-server uses of maintaing a map.

Now that we look up the handle in a map rather than casting IBinder
to Layer::Handle we need to make sure we have unique instances of the
handle. In general this is true but we weren't doing this in the
createWithSurfaceParent where we had an extra call to getHandle. Here
we both refactor createWithSurfaceParent so it works with the new
changes and also add protection for getHandle. We also fix an error
where the handle map was populated outside of lock.
"

Bug: 137284057
Test: build, boot, manual, SurfaceFlinger_test
Change-Id: I9b5f298db2da9cd974c423eb52f261a90f0d17dc
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index bd987dd..38de299 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -76,6 +76,10 @@
 
     sp<SurfaceComposerClient> getClient() const;
 
+    SurfaceControl(const sp<SurfaceComposerClient>& client,
+                   const sp<IBinder>& handle,
+                   const sp<IGraphicBufferProducer>& gbp,
+                   bool owned);
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -84,12 +88,6 @@
     friend class SurfaceComposerClient;
     friend class Surface;
 
-    SurfaceControl(
-            const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& handle,
-            const sp<IGraphicBufferProducer>& gbp,
-            bool owned);
-
     ~SurfaceControl();
 
     sp<Surface> generateSurfaceLocked() const;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0b59147..09d87b2 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -118,7 +118,6 @@
     return lbc;
 }
 
-
 status_t Client::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -144,34 +143,19 @@
      return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
 }
 
-
 status_t Client::createSurface(
         const String8& name,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
         const sp<IBinder>& parentHandle, int32_t windowType, int32_t ownerUid,
         sp<IBinder>* handle,
-        sp<IGraphicBufferProducer>* gbp)
-{
-    sp<Layer> parent = nullptr;
-    if (parentHandle != nullptr) {
-        auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get());
-        parent = layerHandle->owner.promote();
-        if (parent == nullptr) {
-            return NAME_NOT_FOUND;
-        }
+        sp<IGraphicBufferProducer>* gbp) {
+    bool parentDied;
+    sp<Layer> parentLayer = getParentLayer(&parentDied);
+    if (parentHandle == nullptr && parentDied) {
+        return NAME_NOT_FOUND;
     }
-    if (parent == nullptr) {
-        bool parentDied;
-        parent = getParentLayer(&parentDied);
-        // If we had a parent, but it died, we've lost all
-        // our capabilities.
-        if (parentDied) {
-            return NAME_NOT_FOUND;
-        }
-    }
-
     return mFlinger->createLayer(name, this, w, h, format, flags, windowType,
-                                 ownerUid, handle, gbp, &parent);
+                                 ownerUid, handle, gbp, parentHandle, parentLayer);
 }
 
 status_t Client::destroySurface(const sp<IBinder>& handle) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 49437ed..36b685d 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -58,7 +58,7 @@
     virtual status_t createSurface(
             const String8& name,
             uint32_t w, uint32_t h,PixelFormat format, uint32_t flags,
-            const sp<IBinder>& parent, int32_t windowType, int32_t ownerUid,
+            const sp<IBinder>& parentHandle, int32_t windowType, int32_t ownerUid,
             sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp);
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a14bb98..13b12e2 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -178,9 +178,13 @@
 void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
 
 void Layer::onRemovedFromCurrentState() {
-    // the layer is removed from SF mCurrentState to mLayersPendingRemoval
+    if (!mPendingRemoval) {
+        // the layer is removed from SF mCurrentState to mLayersPendingRemoval
+        mPendingRemoval = true;
 
-    mPendingRemoval = true;
+        // remove from sf mapping
+        mFlinger->removeLayerFromMap(this);
+    }
 
     if (mCurrentState.zOrderRelativeOf != nullptr) {
         sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
@@ -221,6 +225,11 @@
 
 sp<IBinder> Layer::getHandle() {
     Mutex::Autolock _l(mLock);
+    if (mGetHandleCalled) {
+        ALOGE("Get handle called twice" );
+        return nullptr;
+    }
+    mGetHandleCalled = true;
     return new Handle(mFlinger, this);
 }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2239679..bd483e8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -704,6 +704,8 @@
         wp<Layer> owner;
     };
 
+    // Creates a new handle each time, so we only expect
+    // this to be called once.
     sp<IBinder> getHandle();
     const String8& getName() const;
     virtual void notifyAvailableFrames() {}
@@ -808,6 +810,7 @@
                                        const LayerVector::Visitor& visitor);
     LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
                                           const std::vector<Layer*>& layersInTree);
+    bool mGetHandleCalled = false;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 25cb589..6ce2cb8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3131,20 +3131,34 @@
     engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
 }
 
-status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
-        const sp<IBinder>& handle,
-        const sp<IGraphicBufferProducer>& gbc,
-        const sp<Layer>& lbc,
-        const sp<Layer>& parent)
-{
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
+                                        const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
+                                        const sp<IBinder>& parentHandle,
+                                        const sp<Layer>& parentLayer) {
     // add this layer to the current state list
     {
         Mutex::Autolock _l(mStateLock);
+        sp<Layer> parent;
+
+        if (parentHandle != nullptr) {
+            parent = fromHandle(parentHandle);
+            if (parent == nullptr) {
+                return NAME_NOT_FOUND;
+            }
+        } else {
+            parent = parentLayer;
+        }
+
         if (mNumLayers >= MAX_LAYERS) {
             ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
                   MAX_LAYERS);
             return NO_MEMORY;
         }
+
+        auto [itr, inserted] = mLayersByLocalBinderToken.emplace(handle->localBinder(), lbc);
+        if (!inserted) {
+          ALOGE("-----------ERROR REGISTERING HANDLE, layer pair: handle is already a key");
+        }
         if (parent == nullptr) {
             mCurrentState.layersSortedByZ.add(lbc);
         } else {
@@ -3178,6 +3192,24 @@
     return removeLayerLocked(mStateLock, layer, topLevelOnly);
 }
 
+status_t SurfaceFlinger::removeLayerFromMap(Layer* layer) {
+    auto it = mLayersByLocalBinderToken.begin();
+    while (it != mLayersByLocalBinderToken.end()) {
+        auto strongRef = it->second.promote();
+        if (strongRef != nullptr && strongRef.get() == layer) {
+            it = mLayersByLocalBinderToken.erase(it);
+            break;
+        } else {
+            it++;
+        }
+    }
+    if (it == mLayersByLocalBinderToken.end()) {
+        ALOGE("Failed to remove layer from mapping - could not find matching layer");
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::removeLayerLocked(const Mutex&, const sp<Layer>& layer,
                                            bool topLevelOnly) {
     if (layer->isPendingRemoval()) {
@@ -3614,13 +3646,12 @@
     }
 }
 
-status_t SurfaceFlinger::createLayer(
-        const String8& name,
-        const sp<Client>& client,
-        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-        int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
-        sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
-{
+status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
+                                     uint32_t h, PixelFormat format, uint32_t flags,
+                                     int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
+                                     sp<IGraphicBufferProducer>* gbp,
+                                     const sp<IBinder>& parentHandle,
+                                     const sp<Layer>& parentLayer) {
     if (int32_t(w|h) < 0) {
         ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
                 int(w), int(h));
@@ -3663,7 +3694,7 @@
 
     layer->setInfo(windowType, ownerUid);
 
-    result = addClientLayer(client, *handle, *gbp, layer, *parent);
+    result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer);
     if (result != NO_ERROR) {
         return result;
     }
@@ -4935,34 +4966,40 @@
         const bool mChildrenOnly;
     };
 
-    auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
-    auto parent = layerHandle->owner.promote();
-
-    if (parent == nullptr || parent->isPendingRemoval()) {
-        ALOGE("captureLayers called with a removed parent");
-        return NAME_NOT_FOUND;
-    }
-
-    const int uid = IPCThreadState::self()->getCallingUid();
-    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
-    if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
-        ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
-        return PERMISSION_DENIED;
-    }
-
+    int reqWidth = 0;
+    int reqHeight = 0;
+    sp<Layer> parent;
     Rect crop(sourceCrop);
-    if (sourceCrop.width() <= 0) {
-        crop.left = 0;
-        crop.right = parent->getCurrentState().active.w;
-    }
 
-    if (sourceCrop.height() <= 0) {
-        crop.top = 0;
-        crop.bottom = parent->getCurrentState().active.h;
-    }
+    {
+        Mutex::Autolock _l(mStateLock);
 
-    int32_t reqWidth = crop.width() * frameScale;
-    int32_t reqHeight = crop.height() * frameScale;
+        parent = fromHandle(layerHandleBinder);
+        if (parent == nullptr || parent->isPendingRemoval()) {
+            ALOGE("captureLayers called with an invalid or removed parent");
+            return NAME_NOT_FOUND;
+        }
+
+        const int uid = IPCThreadState::self()->getCallingUid();
+        const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+        if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+            ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
+            return PERMISSION_DENIED;
+        }
+
+        if (sourceCrop.width() <= 0) {
+            crop.left = 0;
+            crop.right = parent->getCurrentState().active.w;
+        }
+
+        if (sourceCrop.height() <= 0) {
+            crop.top = 0;
+            crop.bottom = parent->getCurrentState().active.h;
+        }
+
+        reqWidth = crop.width() * frameScale;
+        reqHeight = crop.height() * frameScale;
+    } // mStateLock
 
     LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
 
@@ -5287,8 +5324,20 @@
     }
 }
 
-}; // namespace android
+sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+    BBinder *b = handle->localBinder();
+    if (b == nullptr) {
+        return nullptr;
+    }
+    auto it = mLayersByLocalBinderToken.find(b);
+    if (it != mLayersByLocalBinderToken.end()) {
+        auto ret = it->second.promote();
+        return ret;
+    }
+    return nullptr;
+}
 
+} // namespace android
 
 #if defined(__gl_h_)
 #error "don't include gl/gl.h in this file"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 60bf94f..11cdad1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -347,6 +347,8 @@
 
     int getPrimaryDisplayOrientation() const { return mPrimaryDisplayOrientation; }
 
+    sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
@@ -528,10 +530,10 @@
     /* ------------------------------------------------------------------------
      * Layer management
      */
-    status_t createLayer(const String8& name, const sp<Client>& client,
-            uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-            int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
-            sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
+    status_t createLayer(const String8& name, const sp<Client>& client, uint32_t w, uint32_t h,
+                         PixelFormat format, uint32_t flags, int32_t windowType, int32_t ownerUid,
+                         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
+                         const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer = nullptr);
 
     status_t createBufferLayer(const sp<Client>& client, const String8& name,
             uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
@@ -557,12 +559,13 @@
     status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
     status_t removeLayerLocked(const Mutex&, const sp<Layer>& layer, bool topLevelOnly = false);
 
+    // remove layer from mapping
+    status_t removeLayerFromMap(Layer* layer);
+
     // add a layer to SurfaceFlinger
-    status_t addClientLayer(const sp<Client>& client,
-            const sp<IBinder>& handle,
-            const sp<IGraphicBufferProducer>& gbc,
-            const sp<Layer>& lbc,
-            const sp<Layer>& parent);
+    status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
+                            const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
+                            const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer);
 
     /* ------------------------------------------------------------------------
      * Boot animation, on/off animations and screen capture
@@ -832,6 +835,9 @@
     // it may be read from other threads with mStateLock held
     DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
 
+    // protected by mStateLock
+    std::unordered_map<BBinder*, wp<Layer>> mLayersByLocalBinderToken;
+
     // don't use a lock for these, we don't care
     int mDebugRegion;
     int mDebugDDMS;
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 322e8a0..2331dfd 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -18,7 +18,8 @@
     tags: ["test"],
     test_suites: ["device-tests"],
     srcs: [
-        "Stress_test.cpp",
+        "InvalidHandles_test.cpp",
+	"Stress_test.cpp",
         "SurfaceInterceptor_test.cpp",
         "Transaction_test.cpp",
     ],
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
new file mode 100644
index 0000000..42d1f5a
--- /dev/null
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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/Binder.h>
+
+#include <gtest/gtest.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/Rect.h>
+
+namespace android {
+namespace {
+
+class NotALayer : public BBinder {};
+
+/**
+ * For all of these tests we make a SurfaceControl with an invalid layer handle
+ * and verify we aren't able to trick SurfaceFlinger.
+ */
+class InvalidHandleTest : public ::testing::Test {
+protected:
+    sp<SurfaceComposerClient> mScc;
+    sp<SurfaceControl> mNotSc;
+    void SetUp() override {
+        mScc = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mScc->initCheck());
+        mNotSc = makeNotSurfaceControl();
+    }
+
+    sp<SurfaceControl> makeNotSurfaceControl() {
+        return new SurfaceControl(mScc, new NotALayer(), nullptr, true);
+    }
+};
+
+TEST_F(InvalidHandleTest, createSurfaceInvalidHandle) {
+    auto notSc = makeNotSurfaceControl();
+    ASSERT_EQ(nullptr,
+              mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
+                                  notSc.get())
+                      .get());
+}
+
+TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<GraphicBuffer> outBuffer;
+
+    ASSERT_EQ(NAME_NOT_FOUND,
+              sf->captureLayers(mNotSc->getHandle(), &outBuffer, Rect::EMPTY_RECT, 1.0f));
+}
+
+} // namespace
+} // namespace android