1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 
21 #include <gtest/gtest.h>
22 #include <gui/ISurfaceComposer.h>
23 #include <gui/LayerDebugInfo.h>
24 #include <gui/Surface.h>
25 #include <gui/SurfaceComposerClient.h>
26 #include <private/android_filesystem_config.h>
27 #include <private/gui/ComposerService.h>
28 #include <ui/DisplayMode.h>
29 #include <ui/DynamicDisplayInfo.h>
30 #include <utils/String8.h>
31 #include <functional>
32 #include "utils/ScreenshotUtils.h"
33 
34 namespace android {
35 
36 using Transaction = SurfaceComposerClient::Transaction;
37 using ui::ColorMode;
38 
39 namespace {
40 const String8 DISPLAY_NAME("Credentials Display Test");
41 const String8 SURFACE_NAME("Test Surface Name");
42 } // namespace
43 
44 /**
45  * This class tests the CheckCredentials method in SurfaceFlinger.
46  * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
47  * return anything meaningful.
48  */
49 
50 // TODO(b/129481165): remove the #pragma below and fix conversion issues
51 #pragma clang diagnostic push
52 #pragma clang diagnostic ignored "-Wconversion"
53 class CredentialsTest : public ::testing::Test {
54 protected:
SetUp()55     void SetUp() override {
56         // Start the tests as root.
57         seteuid(AID_ROOT);
58 
59         ASSERT_NO_FATAL_FAILURE(initClient());
60     }
61 
TearDown()62     void TearDown() override {
63         mComposerClient->dispose();
64         mBGSurfaceControl.clear();
65         mComposerClient.clear();
66         // Finish the tests as root.
67         seteuid(AID_ROOT);
68     }
69 
70     sp<IBinder> mDisplay;
71     sp<IBinder> mVirtualDisplay;
72     sp<SurfaceComposerClient> mComposerClient;
73     sp<SurfaceControl> mBGSurfaceControl;
74     sp<SurfaceControl> mVirtualSurfaceControl;
75 
initClient()76     void initClient() {
77         mComposerClient = new SurfaceComposerClient;
78         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
79     }
80 
setupBackgroundSurface()81     void setupBackgroundSurface() {
82         mDisplay = SurfaceComposerClient::getInternalDisplayToken();
83         ASSERT_FALSE(mDisplay == nullptr);
84 
85         ui::DisplayMode mode;
86         ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplay, &mode));
87 
88         // Background surface
89         mBGSurfaceControl = mComposerClient->createSurface(SURFACE_NAME, mode.resolution.getWidth(),
90                                                            mode.resolution.getHeight(),
91                                                            PIXEL_FORMAT_RGBA_8888, 0);
92         ASSERT_TRUE(mBGSurfaceControl != nullptr);
93         ASSERT_TRUE(mBGSurfaceControl->isValid());
94 
95         Transaction t;
96         t.setDisplayLayerStack(mDisplay, 0);
97         ASSERT_EQ(NO_ERROR,
98                   t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply());
99     }
100 
101     /**
102      * Sets UID to imitate Graphic's process.
103      */
setGraphicsUID()104     void setGraphicsUID() {
105         seteuid(AID_ROOT);
106         seteuid(AID_GRAPHICS);
107     }
108 
109     /**
110      * Sets UID to imitate System's process.
111      */
setSystemUID()112     void setSystemUID() {
113         seteuid(AID_ROOT);
114         seteuid(AID_SYSTEM);
115     }
116 
117     /**
118      * Sets UID to imitate a process that doesn't have any special privileges in
119      * our code.
120      */
setBinUID()121     void setBinUID() {
122         seteuid(AID_ROOT);
123         seteuid(AID_BIN);
124     }
125 
126     /**
127      * Template function the check a condition for different types of users: root
128      * graphics, system, and non-supported user. Root, graphics, and system should
129      * always equal privilegedValue, and non-supported user should equal unprivilegedValue.
130      */
131     template <typename T>
checkWithPrivileges(std::function<T ()> condition,T privilegedValue,T unprivilegedValue)132     void checkWithPrivileges(std::function<T()> condition, T privilegedValue, T unprivilegedValue) {
133         // Check with root.
134         seteuid(AID_ROOT);
135         ASSERT_EQ(privilegedValue, condition());
136 
137         // Check as a Graphics user.
138         setGraphicsUID();
139         ASSERT_EQ(privilegedValue, condition());
140 
141         // Check as a system user.
142         setSystemUID();
143         ASSERT_EQ(privilegedValue, condition());
144 
145         // Check as a non-supported user.
146         setBinUID();
147         ASSERT_EQ(unprivilegedValue, condition());
148 
149         // Check as shell since shell has some additional permissions
150         seteuid(AID_SHELL);
151         ASSERT_EQ(unprivilegedValue, condition());
152     }
153 };
154 
TEST_F(CredentialsTest,ClientInitTest)155 TEST_F(CredentialsTest, ClientInitTest) {
156     // Root can init can init the client.
157     ASSERT_NO_FATAL_FAILURE(initClient());
158 
159     // Graphics can init the client.
160     setGraphicsUID();
161     ASSERT_NO_FATAL_FAILURE(initClient());
162 
163     // System can init the client.
164     setSystemUID();
165     ASSERT_NO_FATAL_FAILURE(initClient());
166 
167     // Anyone else can init the client.
168     setBinUID();
169     mComposerClient = new SurfaceComposerClient;
170     ASSERT_NO_FATAL_FAILURE(initClient());
171 }
172 
TEST_F(CredentialsTest,GetBuiltInDisplayAccessTest)173 TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
174     std::function<bool()> condition = [] {
175         return SurfaceComposerClient::getInternalDisplayToken() != nullptr;
176     };
177     // Anyone can access display information.
178     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
179 }
180 
TEST_F(CredentialsTest,AllowedGetterMethodsTest)181 TEST_F(CredentialsTest, AllowedGetterMethodsTest) {
182     // The following methods are tested with a UID that is not root, graphics,
183     // or system, to show that anyone can access them.
184     setBinUID();
185     const auto display = SurfaceComposerClient::getInternalDisplayToken();
186     ASSERT_TRUE(display != nullptr);
187 
188     ui::DisplayMode mode;
189     ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
190 
191     Vector<ui::DisplayMode> modes;
192     ui::DynamicDisplayInfo info;
193     ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
194 }
195 
TEST_F(CredentialsTest,GetDynamicDisplayInfoTest)196 TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) {
197     const auto display = SurfaceComposerClient::getInternalDisplayToken();
198     std::function<status_t()> condition = [=]() {
199         ui::DynamicDisplayInfo info;
200         return SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
201     };
202     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
203 }
204 
TEST_F(CredentialsTest,GetDisplayNativePrimariesTest)205 TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
206     const auto display = SurfaceComposerClient::getInternalDisplayToken();
207     std::function<status_t()> condition = [=]() {
208         ui::DisplayPrimaries primaries;
209         return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries);
210     };
211     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
212 }
213 
TEST_F(CredentialsTest,SetDesiredDisplayConfigsTest)214 TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
215     const auto display = SurfaceComposerClient::getInternalDisplayToken();
216     ui::DisplayModeId defaultMode;
217     bool allowGroupSwitching;
218     float primaryFpsMin;
219     float primaryFpsMax;
220     float appRequestFpsMin;
221     float appRequestFpsMax;
222     status_t res =
223             SurfaceComposerClient::getDesiredDisplayModeSpecs(display, &defaultMode,
224                                                               &allowGroupSwitching, &primaryFpsMin,
225                                                               &primaryFpsMax, &appRequestFpsMin,
226                                                               &appRequestFpsMax);
227     ASSERT_EQ(res, NO_ERROR);
228     std::function<status_t()> condition = [=]() {
229         return SurfaceComposerClient::setDesiredDisplayModeSpecs(display, defaultMode,
230                                                                  allowGroupSwitching, primaryFpsMin,
231                                                                  primaryFpsMax, appRequestFpsMin,
232                                                                  appRequestFpsMax);
233     };
234     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
235 }
236 
TEST_F(CredentialsTest,SetActiveColorModeTest)237 TEST_F(CredentialsTest, SetActiveColorModeTest) {
238     const auto display = SurfaceComposerClient::getInternalDisplayToken();
239     std::function<status_t()> condition = [=]() {
240         return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
241     };
242     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
243 }
244 
TEST_F(CredentialsTest,CreateDisplayTest)245 TEST_F(CredentialsTest, CreateDisplayTest) {
246     // Only graphics and system processes can create a secure display.
247     std::function<bool()> condition = [=]() {
248         sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
249         return testDisplay.get() != nullptr;
250     };
251 
252     // Check with root.
253     seteuid(AID_ROOT);
254     ASSERT_FALSE(condition());
255 
256     // Check as a Graphics user.
257     setGraphicsUID();
258     ASSERT_TRUE(condition());
259 
260     // Check as a system user.
261     setSystemUID();
262     ASSERT_TRUE(condition());
263 
264     // Check as a non-supported user.
265     setBinUID();
266     ASSERT_FALSE(condition());
267 
268     // Check as shell since shell has some additional permissions
269     seteuid(AID_SHELL);
270     ASSERT_FALSE(condition());
271 
272     condition = [=]() {
273         sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
274         return testDisplay.get() != nullptr;
275     };
276     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
277 }
278 
TEST_F(CredentialsTest,CaptureTest)279 TEST_F(CredentialsTest, CaptureTest) {
280     const auto display = SurfaceComposerClient::getInternalDisplayToken();
281     std::function<status_t()> condition = [=]() {
282         sp<GraphicBuffer> outBuffer;
283         DisplayCaptureArgs captureArgs;
284         captureArgs.displayToken = display;
285         ScreenCaptureResults captureResults;
286         return ScreenCapture::captureDisplay(captureArgs, captureResults);
287     };
288     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
289 }
290 
TEST_F(CredentialsTest,CaptureLayersTest)291 TEST_F(CredentialsTest, CaptureLayersTest) {
292     setupBackgroundSurface();
293     sp<GraphicBuffer> outBuffer;
294     std::function<status_t()> condition = [=]() {
295         LayerCaptureArgs captureArgs;
296         captureArgs.layerHandle = mBGSurfaceControl->getHandle();
297         captureArgs.sourceCrop = {0, 0, 1, 1};
298 
299         ScreenCaptureResults captureResults;
300         return ScreenCapture::captureLayers(captureArgs, captureResults);
301     };
302     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
303 }
304 
305 /**
306  * The following tests are for methods accessible directly through SurfaceFlinger.
307  */
TEST_F(CredentialsTest,GetLayerDebugInfo)308 TEST_F(CredentialsTest, GetLayerDebugInfo) {
309     setupBackgroundSurface();
310     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
311 
312     // Historically, only root and shell can access the getLayerDebugInfo which
313     // is called when we call dumpsys. I don't see a reason why we should change this.
314     std::vector<LayerDebugInfo> outLayers;
315     // Check with root.
316     seteuid(AID_ROOT);
317     ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
318 
319     // Check as a shell.
320     seteuid(AID_SHELL);
321     ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
322 
323     // Check as anyone else.
324     seteuid(AID_ROOT);
325     seteuid(AID_BIN);
326     ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers));
327 }
328 
TEST_F(CredentialsTest,IsWideColorDisplayBasicCorrectness)329 TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
330     const auto display = SurfaceComposerClient::getInternalDisplayToken();
331     ASSERT_FALSE(display == nullptr);
332     bool result = false;
333     status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
334     ASSERT_EQ(NO_ERROR, error);
335     bool hasWideColorMode = false;
336     ui::DynamicDisplayInfo info;
337     SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
338     const auto& colorModes = info.supportedColorModes;
339     for (ColorMode colorMode : colorModes) {
340         switch (colorMode) {
341             case ColorMode::DISPLAY_P3:
342             case ColorMode::ADOBE_RGB:
343             case ColorMode::DCI_P3:
344                 hasWideColorMode = true;
345                 break;
346             default:
347                 break;
348         }
349     }
350     ASSERT_EQ(hasWideColorMode, result);
351 }
352 
TEST_F(CredentialsTest,IsWideColorDisplayWithPrivileges)353 TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
354     const auto display = SurfaceComposerClient::getInternalDisplayToken();
355     ASSERT_FALSE(display == nullptr);
356     std::function<status_t()> condition = [=]() {
357         bool result = false;
358         return SurfaceComposerClient::isWideColorDisplay(display, &result);
359     };
360     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
361 }
362 
TEST_F(CredentialsTest,GetActiveColorModeBasicCorrectness)363 TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) {
364     const auto display = SurfaceComposerClient::getInternalDisplayToken();
365     ASSERT_FALSE(display == nullptr);
366     ui::DynamicDisplayInfo info;
367     SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
368     ColorMode colorMode = info.activeColorMode;
369     ASSERT_NE(static_cast<ColorMode>(BAD_VALUE), colorMode);
370 }
371 
372 } // namespace android
373 
374 // TODO(b/129481165): remove the #pragma below and fix conversion issues
375 #pragma clang diagnostic pop // ignored "-Wconversion"
376