blob: 4d3bb91f0ffdb0626caffd0c9736d10677d8a7e2 [file] [log] [blame]
/*
* Copyright (C) 2016 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 android.security.cts;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.platform.test.annotations.SecurityTest;
import android.support.test.InstrumentationRegistry;
import android.util.Log;
import android.view.WindowManager;
import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@SecurityTest
public class ActivityManagerTest extends TestCase {
private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
private static CountDownLatch sLatch;
private static volatile int sNormalActivityUserId;
private static volatile boolean sCannotReflect;
private static volatile boolean sIsAppForeground;
private static final String TAG = "ActivityManagerTest";
@Override
protected void setUp() throws Exception {
super.setUp();
sLatch = new CountDownLatch(2);
sNormalActivityUserId = -1;
sCannotReflect = false;
sIsAppForeground = false;
}
@SecurityTest(minPatchLevel = "2015-03")
public void testActivityManager_injectInputEvents() throws ClassNotFoundException {
try {
/*
* Should throw NoSuchMethodException. getEnclosingActivityContainer() has been
* removed/renamed.
* Patch: https://android.googlesource.com/platform/frameworks/base/+/aa7e3ed%5E!/
*/
Class.forName("android.app.ActivityManagerNative").getMethod(
"getEnclosingActivityContainer", IBinder.class);
fail("ActivityManagerNative.getEnclosingActivityContainer() API should not be" +
"available in patched devices: Device is vulnerable to CVE-2015-1533");
} catch (NoSuchMethodException e) {
// Patched devices should throw this exception
}
}
// b/144285917
@SecurityTest(minPatchLevel = "2020-05")
public void testActivityManager_attachNullApplication() {
SecurityException securityException = null;
Exception unexpectedException = null;
try {
final Object iam = ActivityManager.class.getDeclaredMethod("getService").invoke(null);
Class.forName("android.app.IActivityManager").getDeclaredMethod("attachApplication",
Class.forName("android.app.IApplicationThread"))
.invoke(iam, new Object[] { null /* thread */ });
} catch (SecurityException e) {
securityException = e;
} catch (InvocationTargetException e) {
if (e.getCause() instanceof SecurityException) {
securityException = (SecurityException) e.getCause();
} else {
unexpectedException = e;
}
} catch (Exception e) {
unexpectedException = e;
}
if (unexpectedException != null) {
Log.w("ActivityManagerTest", "Unexpected exception", unexpectedException);
}
assertNotNull("Expect SecurityException by attaching null application", securityException);
}
public void testIsAppInForegroundNormal() throws Exception {
/* Verify that isAppForeground can be called by the caller on itself. */
launchActivity(NormalActivity.class);
sNormalActivityUserId = InstrumentationRegistry.getTargetContext().getPackageManager()
.getPackageUid(SECURITY_CTS_PACKAGE_NAME, 0);
sLatch.await(5, TimeUnit.SECONDS); // Ensure the service has ran at least twice.
if (sCannotReflect) return; // If reflection is not possible, pass the test.
assertTrue("isAppForeground failed to query for uid on itself.", sIsAppForeground);
}
public void testIsAppInForegroundMalicious() throws Exception {
/* Verify that isAppForeground cannot be called by another app on a known uid. */
launchActivity(MaliciousActivity.class);
launchSettingsActivity();
sLatch.await(5, TimeUnit.SECONDS); // Ensure the service has ran at least twice.
if (sCannotReflect) return; // If reflection is not possible, pass the test.
assertFalse("isAppForeground successfully queried for a uid other than itself.",
sIsAppForeground);
}
private void launchActivity(Class<? extends Activity> clazz) {
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(SECURITY_CTS_PACKAGE_NAME, clazz.getName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
private void launchSettingsActivity() {
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
final Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
public static class NormalActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Intent intent = new Intent(this, AppMonitoringService.class);
intent.putExtra(AppMonitoringService.EXTRA_UID, sNormalActivityUserId);
startService(intent);
}
}
public static class MaliciousActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Intent intent = new Intent(this, AppMonitoringService.class);
intent.putExtra(AppMonitoringService.EXTRA_UID, Process.SYSTEM_UID);
startService(intent);
finish();
}
}
public static class AppMonitoringService extends Service {
private static final String EXTRA_UID = "android.security.cts.extra.UID";
private int uid;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
uid = intent.getIntExtra(EXTRA_UID, -1);
return super.onStartCommand(intent, flags, startId);
}
public AppMonitoringService() {
super.onCreate();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
ActivityManager activityManager = (ActivityManager) getSystemService(
ACTIVITY_SERVICE);
Field field = activityManager.getClass().getDeclaredField(
"IActivityManagerSingleton");
field.setAccessible(true);
Object fieldValue = field.get(activityManager);
Method method = fieldValue.getClass().getDeclaredMethod("create");
method.setAccessible(true);
Object IActivityInstance = method.invoke(fieldValue);
Method isAppForeground = IActivityInstance.getClass().getDeclaredMethod(
"isAppForeground", int.class);
isAppForeground.setAccessible(true);
boolean res = (boolean) isAppForeground.invoke(IActivityInstance, uid);
if (res) {
sIsAppForeground = true;
}
} catch (Exception e) {
Log.e(TAG, "Failed to fetch/invoke field/method via reflection.", e);
sCannotReflect = true;
}
sLatch.countDown();
handler.postDelayed(this, 200);
}
}, 0);
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
}