Fix vulnerability that allowed attackers to start arbitary

activities

Test: atest DreamServiceTest
Test: flashed device and verified dream settings works as expected
Fixes: 242845514
Change-Id: I6e90e3a0d513dceb7d7f5c59d6807ebe164c5716
This commit is contained in:
Lucas Silva
2022-08-30 15:29:11 -04:00
parent b2f2546b5b
commit 2ce1b7fd37
7 changed files with 114 additions and 16 deletions

View File

@@ -2412,6 +2412,16 @@ package android.service.dreams {
method public final boolean shouldShowComplications();
}
public class DreamService extends android.app.Service implements android.view.Window.Callback {
method @Nullable public static android.service.dreams.DreamService.DreamMetadata getDreamMetadata(@NonNull android.content.Context, @Nullable android.content.pm.ServiceInfo);
}
public static final class DreamService.DreamMetadata {
field @Nullable public final android.graphics.drawable.Drawable previewImage;
field @Nullable public final android.content.ComponentName settingsActivity;
field @NonNull public final boolean showComplications;
}
}
package android.service.notification {

View File

@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
@@ -1124,7 +1125,8 @@ public class DreamService extends Service implements Window.Callback {
* @hide
*/
@Nullable
public static DreamMetadata getDreamMetadata(Context context,
@TestApi
public static DreamMetadata getDreamMetadata(@NonNull Context context,
@Nullable ServiceInfo serviceInfo) {
if (serviceInfo == null) return null;
@@ -1183,7 +1185,8 @@ public class DreamService extends Service implements Window.Callback {
}
}
private static ComponentName convertToComponentName(String flattenedString,
@Nullable
private static ComponentName convertToComponentName(@Nullable String flattenedString,
ServiceInfo serviceInfo) {
if (flattenedString == null) {
return null;
@@ -1193,7 +1196,17 @@ public class DreamService extends Service implements Window.Callback {
return new ComponentName(serviceInfo.packageName, flattenedString);
}
return ComponentName.unflattenFromString(flattenedString);
// Ensure that the component is from the same package as the dream service. If not,
// treat the component as invalid and return null instead.
final ComponentName cn = ComponentName.unflattenFromString(flattenedString);
if (cn == null) return null;
if (!cn.getPackageName().equals(serviceInfo.packageName)) {
Log.w(TAG,
"Inconsistent package name in component: " + cn.getPackageName()
+ ", should be: " + serviceInfo.packageName);
return null;
}
return cn;
}
/**
@@ -1489,6 +1502,7 @@ public class DreamService extends Service implements Window.Callback {
*
* @hide
*/
@TestApi
public static final class DreamMetadata {
@Nullable
public final ComponentName settingsActivity;

View File

@@ -147,6 +147,19 @@
android:resource="@xml/test_dream_metadata" />
</service>
<service
android:name="com.android.server.dreams.TestDreamServiceWithInvalidSettings"
android:exported="false"
android:label="Test Dream" >
<intent-filter>
<action android:name="android.service.dreams.DreamService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.service.dream"
android:resource="@xml/test_dream_metadata_invalid" />
</service>
<receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">

View File

@@ -15,5 +15,5 @@
-->
<dream xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
android:settingsActivity="com.android.frameworks.servicestests/.TestDreamSettingsActivity"
android:showClockAndComplications="false" />

View File

@@ -0,0 +1,20 @@
<!--
~ Copyright (C) 2022 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.
-->
<!-- The settings activity is in a different package, which is invalid -->
<dream xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
android:showClockAndComplications="false"/>

View File

@@ -16,7 +16,8 @@
package com.android.server.dreams;
import static org.junit.Assert.assertEquals;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import android.content.ComponentName;
@@ -35,21 +36,36 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DreamServiceTest {
private static final String TEST_PACKAGE_NAME = "com.android.frameworks.servicestests";
@Test
public void testMetadataParsing() throws PackageManager.NameNotFoundException {
final String testPackageName = "com.android.frameworks.servicestests";
final String testDreamClassName = "com.android.server.dreams.TestDreamService";
final String testSettingsActivity = "com.android.server.dreams/.TestDreamSettingsActivity";
final String testSettingsActivity =
"com.android.frameworks.servicestests/.TestDreamSettingsActivity";
final DreamService.DreamMetadata metadata = getDreamMetadata(testDreamClassName);
final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
final ServiceInfo si = context.getPackageManager().getServiceInfo(
new ComponentName(testPackageName, testDreamClassName),
PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
final DreamService.DreamMetadata metadata = DreamService.getDreamMetadata(context, si);
assertEquals(0, metadata.settingsActivity.compareTo(
ComponentName.unflattenFromString(testSettingsActivity)));
assertThat(metadata.settingsActivity).isEqualTo(
ComponentName.unflattenFromString(testSettingsActivity));
assertFalse(metadata.showComplications);
}
@Test
public void testMetadataParsing_invalidSettingsActivity()
throws PackageManager.NameNotFoundException {
final String testDreamClassName =
"com.android.server.dreams.TestDreamServiceWithInvalidSettings";
final DreamService.DreamMetadata metadata = getDreamMetadata(testDreamClassName);
assertThat(metadata.settingsActivity).isNull();
}
private DreamService.DreamMetadata getDreamMetadata(String dreamClassName)
throws PackageManager.NameNotFoundException {
final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
final ServiceInfo si = context.getPackageManager().getServiceInfo(
new ComponentName(TEST_PACKAGE_NAME, dreamClassName),
PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
return DreamService.getDreamMetadata(context, si);
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 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.
*/
package com.android.server.dreams;
import android.service.dreams.DreamService;
/**
* Dream service implementation for unit testing, where the settings activity is invalid.
*/
public class TestDreamServiceWithInvalidSettings extends DreamService {
}