Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5bb97ba authored by chaviw's avatar chaviw
Browse files

Add CAPTURE_BLACKOUT_CONTENT permission check for screenshots

Previously, only graphics and system were allowed to take screenshots of
layers that are normally blacked out. This change adds an additional check so
processes that have the permission CAPTURE_BLACKOUT_CONTENT can also take
screenshots of that content. Only system applications can have that
permission

Test: Builds, screenshots still work as before
Bug: 173746627
Change-Id: I53a1738be8e4787507a76f8b0ac703f3e413b30c
parent 6e2e0eff
Loading
Loading
Loading
Loading
+24 −10
Original line number Original line Diff line number Diff line
@@ -287,6 +287,8 @@ const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER"
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS");
const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS");
const String16 sDump("android.permission.DUMP");
const String16 sDump("android.permission.DUMP");
const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONTENT");

const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
@@ -5681,6 +5683,14 @@ static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) {
    }
    }
}
}


static bool hasCaptureBlackoutContentPermission() {
    IPCThreadState* ipc = IPCThreadState::self();
    const int pid = ipc->getCallingPid();
    const int uid = ipc->getCallingUid();
    return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
            PermissionCache::checkPermission(sCaptureBlackoutContent, pid, uid);
}

static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) {
static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) {
    IPCThreadState* ipc = IPCThreadState::self();
    IPCThreadState* ipc = IPCThreadState::self();
    const int pid = ipc->getCallingPid();
    const int pid = ipc->getCallingPid();
@@ -5851,6 +5861,10 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
    Rect layerStackSpaceRect;
    Rect layerStackSpaceRect;
    ui::Dataspace dataspace;
    ui::Dataspace dataspace;
    bool captureSecureLayers;
    bool captureSecureLayers;

    // Call this before holding mStateLock to avoid any deadlocking.
    bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();

    {
    {
        Mutex::Autolock lock(mStateLock);
        Mutex::Autolock lock(mStateLock);


@@ -5860,9 +5874,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
            return NAME_NOT_FOUND;
            return NAME_NOT_FOUND;
        }
        }


        const int uid = IPCThreadState::self()->getCallingUid();
        if (!canCaptureBlackoutContent &&
        const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
            parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
        if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
            ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
            ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
            return PERMISSION_DENIED;
            return PERMISSION_DENIED;
        }
        }
@@ -6012,8 +6025,7 @@ status_t SurfaceFlinger::captureScreenCommon(
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }


    const int uid = IPCThreadState::self()->getCallingUid();
    bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;


    static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
    static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
        if (mRefreshPending) {
        if (mRefreshPending) {
@@ -6033,8 +6045,9 @@ status_t SurfaceFlinger::captureScreenCommon(


        status_t result = NO_ERROR;
        status_t result = NO_ERROR;
        renderArea->render([&] {
        renderArea->render([&] {
            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem,
            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer,
                                            regionSampling, grayscale, captureResults);
                                            canCaptureBlackoutContent, regionSampling, grayscale,
                                            captureResults);
        });
        });


        captureResults.result = result;
        captureResults.result = result;
@@ -6046,8 +6059,9 @@ status_t SurfaceFlinger::captureScreenCommon(


status_t SurfaceFlinger::renderScreenImplLocked(
status_t SurfaceFlinger::renderScreenImplLocked(
        const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
        const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
        const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool forSystem,
        const std::shared_ptr<renderengine::ExternalTexture>& buffer,
        bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) {
        bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
        ScreenCaptureResults& captureResults) {
    ATRACE_CALL();
    ATRACE_CALL();


    traverseLayers([&](Layer* layer) {
    traverseLayers([&](Layer* layer) {
@@ -6060,7 +6074,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(
    // We allow the system server to take screenshots of secure layers for
    // We allow the system server to take screenshots of secure layers for
    // use in situations like the Screen-rotation animation and place
    // use in situations like the Screen-rotation animation and place
    // the impetus on WindowManager to not persist them.
    // the impetus on WindowManager to not persist them.
    if (captureResults.capturedSecureLayers && !forSystem) {
    if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
        ALOGW("FB is protected: PERMISSION_DENIED");
        ALOGW("FB is protected: PERMISSION_DENIED");
        return PERMISSION_DENIED;
        return PERMISSION_DENIED;
    }
    }
+2 −2
Original line number Original line Diff line number Diff line
@@ -911,8 +911,8 @@ private:
                                 const sp<IScreenCaptureListener>&);
                                 const sp<IScreenCaptureListener>&);
    status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
    status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
                                    const std::shared_ptr<renderengine::ExternalTexture>&,
                                    const std::shared_ptr<renderengine::ExternalTexture>&,
                                    bool forSystem, bool regionSampling, bool grayscale,
                                    bool canCaptureBlackoutContent, bool regionSampling,
                                    ScreenCaptureResults&);
                                    bool grayscale, ScreenCaptureResults&);


    sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
    sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
    sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock);
    sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock);
+6 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wconversion"


#include <gui/BufferItemConsumer.h>
#include <gui/BufferItemConsumer.h>
#include <private/android_filesystem_config.h>
#include "TransactionTestHarnesses.h"
#include "TransactionTestHarnesses.h"


namespace android {
namespace android {
@@ -170,7 +171,11 @@ TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
    args.displayToken = mDisplay;
    args.displayToken = mDisplay;


    ScreenCaptureResults captureResults;
    ScreenCaptureResults captureResults;
    {
        // Ensure the UID is not root because root has all permissions
        UIDFaker f(AID_APP_START);
        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
    }


    Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
    Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
    ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults));
    ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults));
+12 −4
Original line number Original line Diff line number Diff line
@@ -84,7 +84,11 @@ TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) {


    Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);
    Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);


    {
        // Ensure the UID is not root because root has all permissions
        UIDFaker f(AID_APP_START);
        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
    }


    UIDFaker f(AID_SYSTEM);
    UIDFaker f(AID_SYSTEM);


@@ -528,7 +532,7 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
    ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
    ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
}
}


TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
TEST_F(ScreenCaptureTest, CaptureSecureLayer) {
    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
                                              ISurfaceComposerClient::eFXSurfaceBufferState);
                                              ISurfaceComposerClient::eFXSurfaceBufferState);
    sp<SurfaceControl> secureLayer =
    sp<SurfaceControl> secureLayer =
@@ -552,8 +556,12 @@ TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
    args.childrenOnly = false;
    args.childrenOnly = false;
    ScreenCaptureResults captureResults;
    ScreenCaptureResults captureResults;


    {
        // Ensure the UID is not root because root has all permissions
        UIDFaker f(AID_APP_START);
        // Call from outside system with secure layers will result in permission denied
        // Call from outside system with secure layers will result in permission denied
        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
    }


    UIDFaker f(AID_SYSTEM);
    UIDFaker f(AID_SYSTEM);