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