/* * Copyright (C) 2020 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. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #include #include #include #include #include #include #include #include #include #include #include #include #include "utils/ScreenshotUtils.h" #include "utils/WindowInfosListenerUtils.h" namespace android { using Transaction = SurfaceComposerClient::Transaction; using gui::aidl_utils::statusTFromBinderStatus; using ui::ColorMode; namespace { const std::string kDisplayName("Credentials Display Test"); const String8 kSurfaceName("Test Surface Name"); } // namespace /** * This class tests the CheckCredentials method in SurfaceFlinger. * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not * return anything meaningful. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" class CredentialsTest : public ::testing::Test { protected: void SetUp() override { ASSERT_NO_FATAL_FAILURE(initClient()); } void TearDown() override { mComposerClient->dispose(); mBGSurfaceControl.clear(); mComposerClient.clear(); } sp mDisplay; sp mVirtualDisplay; sp mComposerClient; sp mBGSurfaceControl; sp mVirtualSurfaceControl; void initClient() { mComposerClient = sp::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); } static sp getFirstDisplayToken() { const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); if (ids.empty()) { return nullptr; } return SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); } static std::optional getFirstDisplayId() { const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); if (ids.empty()) { return std::nullopt; } return ids.front().value; } void setupBackgroundSurface() { mDisplay = getFirstDisplayToken(); ASSERT_FALSE(mDisplay == nullptr); ui::DisplayMode mode; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplay, &mode)); // Background surface mBGSurfaceControl = mComposerClient->createSurface(kSurfaceName, mode.resolution.getWidth(), mode.resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mBGSurfaceControl != nullptr); ASSERT_TRUE(mBGSurfaceControl->isValid()); Transaction t; t.setDisplayLayerStack(mDisplay, ui::DEFAULT_LAYER_STACK); ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply()); } /** * Template function the check a condition for different types of users: root * graphics, system, and non-supported user. Root, graphics, and system should * always equal privilegedValue, and non-supported user should equal unprivilegedValue. */ template void checkWithPrivileges(std::function condition, T privilegedValue, T unprivilegedValue) { // Check with root. { UIDFaker f(AID_SYSTEM); ASSERT_EQ(privilegedValue, condition()); } // Check as a Graphics user. { UIDFaker f(AID_GRAPHICS); ASSERT_EQ(privilegedValue, condition()); } // Check as a system user. { UIDFaker f(AID_SYSTEM); ASSERT_EQ(privilegedValue, condition()); } // Check as a non-supported user. { UIDFaker f(AID_BIN); ASSERT_EQ(unprivilegedValue, condition()); } // Check as shell since shell has some additional permissions { UIDFaker f(AID_SHELL); ASSERT_EQ(privilegedValue, condition()); } } }; TEST_F(CredentialsTest, ClientInitTest) { // Root can init can init the client. ASSERT_NO_FATAL_FAILURE(initClient()); // Graphics can init the client. { UIDFaker f(AID_GRAPHICS); ASSERT_NO_FATAL_FAILURE(initClient()); } // System can init the client. { UIDFaker f(AID_SYSTEM); ASSERT_NO_FATAL_FAILURE(initClient()); } // Anyone else can init the client. { UIDFaker f(AID_BIN); mComposerClient = sp::make(); ASSERT_NO_FATAL_FAILURE(initClient()); } } TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { std::function condition = [] { return getFirstDisplayToken() != nullptr; }; // Anyone can access display information. ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); } TEST_F(CredentialsTest, AllowedGetterMethodsTest) { // The following methods are tested with a UID that is not root, graphics, // or system, to show that anyone can access them. UIDFaker f(AID_BIN); const auto id = getFirstDisplayId(); ASSERT_TRUE(id); ui::DynamicDisplayInfo info; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info)); } TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) { const auto id = getFirstDisplayId(); ASSERT_TRUE(id); std::function condition = [=]() { ui::DynamicDisplayInfo info; return SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { const auto display = getFirstDisplayToken(); std::function condition = [=]() { ui::DisplayPrimaries primaries; return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) { const auto display = getFirstDisplayToken(); gui::DisplayModeSpecs specs; status_t res = SurfaceComposerClient::getDesiredDisplayModeSpecs(display, &specs); ASSERT_EQ(res, NO_ERROR); gui::DisplayModeSpecs setSpecs; std::function condition = [=]() { return SurfaceComposerClient::setDesiredDisplayModeSpecs(display, specs); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } TEST_F(CredentialsTest, SetActiveColorModeTest) { const auto display = getFirstDisplayToken(); std::function condition = [=]() { return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } TEST_F(CredentialsTest, CreateDisplayTest) { // Only graphics and system processes can create a secure display. std::function condition = [=]() { sp testDisplay = SurfaceComposerClient::createVirtualDisplay(kDisplayName, true); return testDisplay.get() != nullptr; }; // Check with root. { UIDFaker f(AID_ROOT); ASSERT_TRUE(condition()); } // Check as a Graphics user. { UIDFaker f(AID_GRAPHICS); ASSERT_TRUE(condition()); } // Check as a system user. { UIDFaker f(AID_SYSTEM); ASSERT_TRUE(condition()); } // Check as a non-supported user. { UIDFaker f(AID_BIN); ASSERT_FALSE(condition()); } // Check as shell since shell has some additional permissions { UIDFaker f(AID_SHELL); ASSERT_FALSE(condition()); } condition = [=]() { sp testDisplay = SurfaceComposerClient::createVirtualDisplay(kDisplayName, false); return testDisplay.get() != nullptr; }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); } TEST_F(CredentialsTest, CaptureLayersTest) { setupBackgroundSurface(); sp outBuffer; std::function condition = [=, this]() { LayerCaptureArgs captureArgs; captureArgs.layerHandle = mBGSurfaceControl->getHandle(); captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(0, 0, 1, 1); ScreenCaptureResults captureResults; return ScreenCapture::captureLayers(captureArgs, captureResults); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } /** * The following tests are for methods accessible directly through SurfaceFlinger. */ TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { const auto display = getFirstDisplayToken(); ASSERT_FALSE(display == nullptr); bool result = false; status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result); ASSERT_EQ(NO_ERROR, error); bool hasWideColorMode = false; const auto id = getFirstDisplayId(); ASSERT_TRUE(id); ui::DynamicDisplayInfo info; SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info); const auto& colorModes = info.supportedColorModes; for (ColorMode colorMode : colorModes) { switch (colorMode) { case ColorMode::DISPLAY_P3: case ColorMode::ADOBE_RGB: case ColorMode::DCI_P3: hasWideColorMode = true; break; default: break; } } ASSERT_EQ(hasWideColorMode, result); } TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) { const auto display = getFirstDisplayToken(); ASSERT_FALSE(display == nullptr); std::function condition = [=]() { bool result = false; return SurfaceComposerClient::isWideColorDisplay(display, &result); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) { const auto id = getFirstDisplayId(); ASSERT_TRUE(id); ui::DynamicDisplayInfo info; SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info); ColorMode colorMode = info.activeColorMode; ASSERT_NE(static_cast(BAD_VALUE), colorMode); } TEST_F(CredentialsTest, TransactionPermissionTest) { WindowInfosListenerUtils windowInfosListenerUtils; std::string name = "Test Layer"; sp token = sp::make(); auto windowInfo = sp::make(); windowInfo->editInfo()->name = name; windowInfo->editInfo()->token = token; sp surfaceControl = mComposerClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); const Rect crop(0, 0, 100, 100); { UIDFaker f(AID_SYSTEM); Transaction() .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK) .show(surfaceControl) .setLayer(surfaceControl, INT32_MAX - 1) .setCrop(surfaceControl, crop) .setInputWindowInfo(surfaceControl, windowInfo) .apply(); } // Attempt to set a trusted overlay from a non-privileged process. This should fail silently. { UIDFaker f{AID_BIN}; Transaction().setTrustedOverlay(surfaceControl, true).apply(/*synchronous=*/true); } // Verify that the layer was not made a trusted overlay. { UIDFaker f(AID_SYSTEM); auto windowIsPresentAndNotTrusted = [&](const std::vector& windowInfos) { auto foundWindowInfo = WindowInfosListenerUtils::findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); if (!foundWindowInfo) { return false; } return !foundWindowInfo->inputConfig.test(WindowInfo::InputConfig::TRUSTED_OVERLAY); }; ASSERT_TRUE( windowInfosListenerUtils.waitForWindowInfosPredicate(windowIsPresentAndNotTrusted)); } // Verify that privileged processes are able to set trusted overlays. { UIDFaker f(AID_SYSTEM); Transaction().setTrustedOverlay(surfaceControl, true).apply(/*synchronous=*/true); auto windowIsPresentAndTrusted = [&](const std::vector& windowInfos) { auto foundWindowInfo = WindowInfosListenerUtils::findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); if (!foundWindowInfo) { return false; } return foundWindowInfo->inputConfig.test(WindowInfo::InputConfig::TRUSTED_OVERLAY); }; ASSERT_TRUE( windowInfosListenerUtils.waitForWindowInfosPredicate(windowIsPresentAndTrusted)); } } TEST_F(CredentialsTest, DisplayTransactionPermissionTest) { const auto display = getFirstDisplayToken(); ui::DisplayState displayState; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState)); const ui::Rotation initialOrientation = displayState.orientation; // Set display orientation from an untrusted process. This should fail silently. { UIDFaker f{AID_BIN}; Transaction transaction; Rect layerStackRect; Rect displayRect; transaction.setDisplayProjection(display, initialOrientation + ui::ROTATION_90, layerStackRect, displayRect); transaction.apply(/*synchronous=*/true); } // Verify that the display orientation did not change. ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState)); ASSERT_EQ(initialOrientation, displayState.orientation); // Set display orientation from a trusted process. { UIDFaker f{AID_SYSTEM}; Transaction transaction; Rect layerStackRect; Rect displayRect; transaction.setDisplayProjection(display, initialOrientation + ui::ROTATION_90, layerStackRect, displayRect); transaction.apply(/*synchronous=*/true); } // Verify that the display orientation did change. ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState)); ASSERT_EQ(initialOrientation + ui::ROTATION_90, displayState.orientation); // Reset orientation { UIDFaker f{AID_SYSTEM}; Transaction transaction; Rect layerStackRect; Rect displayRect; transaction.setDisplayProjection(display, initialOrientation, layerStackRect, displayRect); transaction.apply(/*synchronous=*/true); } ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState)); ASSERT_EQ(initialOrientation, displayState.orientation); } } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion"