Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6 months worth of security patches! #8

Open
wants to merge 9 commits into
base: 12.1
Choose a base branch
from
3 changes: 2 additions & 1 deletion src/com/android/settings/accounts/AddAccountSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public void run(AccountManagerFuture<Bundle> future) {
intent.putExtras(addAccountOptions)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivityForResultAsUser(intent, ADD_ACCOUNT_REQUEST, mUserHandle);
startActivityForResultAsUser(
new Intent(intent), ADD_ACCOUNT_REQUEST, mUserHandle);
} else {
setResult(RESULT_OK);
if (mPendingIntent != null) {
Expand Down
8 changes: 7 additions & 1 deletion src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,13 @@ public void onPrepareOptionsMenu(Menu menu) {
return;
}
super.onPrepareOptionsMenu(menu);
menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry));
final MenuItem uninstallAllUsersItem = menu.findItem(UNINSTALL_ALL_USERS_MENU);
uninstallAllUsersItem.setVisible(
shouldShowUninstallForAll(mAppEntry) && !mAppsControlDisallowedBySystem);
if (uninstallAllUsersItem.isVisible()) {
RestrictedLockUtilsInternal.setMenuItemAsDisabledByAdmin(getActivity(),
uninstallAllUsersItem, mAppsControlDisallowedAdmin);
}
mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
final boolean uninstallUpdateDisabled = getContext().getResources().getBoolean(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

package com.android.settings.applications.specialaccess.notificationaccess;

import static android.content.pm.PackageManager.PERMISSION_GRANTED;

import static com.android.settings.applications.AppInfoBase.ARG_PACKAGE_NAME;

import android.Manifest;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
Expand All @@ -39,6 +42,7 @@
import android.provider.Settings;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;

Expand All @@ -53,6 +57,7 @@
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.password.PasswordUtils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;

Expand Down Expand Up @@ -208,8 +213,12 @@ protected void retrieveAppEntry() {
}
}
if (intent != null && intent.hasExtra(Intent.EXTRA_USER_HANDLE)) {
mUserId = ((UserHandle) intent.getParcelableExtra(
Intent.EXTRA_USER_HANDLE)).getIdentifier();
if (hasInteractAcrossUsersPermission()) {
mUserId = ((UserHandle) intent.getParcelableExtra(
Intent.EXTRA_USER_HANDLE)).getIdentifier();
} else {
finish();
}
} else {
mUserId = UserHandle.myUserId();
}
Expand All @@ -224,6 +233,26 @@ protected void retrieveAppEntry() {
}
}

private boolean hasInteractAcrossUsersPermission() {
final String callingPackageName = PasswordUtils.getCallingAppPackageName(
getActivity().getActivityToken());

if (TextUtils.isEmpty(callingPackageName)) {
Log.w(TAG, "Not able to get calling package name for permission check");
return false;
}

if (getContext().getPackageManager().checkPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPackageName)
!= PERMISSION_GRANTED) {
Log.w(TAG, "Package " + callingPackageName + " does not have required permission "
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
return false;
}

return true;
}

// Dialogs only have access to the parent fragment, not the controller, so pass the information
// along to keep business logic out of this file
public void disable(final ComponentName cn) {
Expand Down
92 changes: 92 additions & 0 deletions src/com/android/settings/homepage/SettingsHomepageActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.FeatureFlagUtils;
Expand All @@ -38,6 +43,7 @@
import android.widget.ImageView;
import android.widget.Toolbar;

import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
Expand All @@ -55,6 +61,7 @@
import com.android.settings.core.FeatureFlags;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.PasswordUtils;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;

Expand Down Expand Up @@ -351,6 +358,40 @@ private void launchDeepLinkIntentToRight() {
finish();
return;
}

ActivityInfo targetActivityInfo = null;
try {
targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
/* flags= */ 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Failed to get target ActivityInfo: " + e);
finish();
return;
}

int callingUid = -1;
try {
callingUid = ActivityManager.getService().getLaunchedFromUid(getActivityToken());
} catch (RemoteException re) {
Log.e(TAG, "Not able to get callingUid: " + re);
finish();
return;
}

if (!hasPrivilegedAccess(callingUid, targetActivityInfo)) {
if (!targetActivityInfo.exported) {
Log.e(TAG, "Target Activity is not exported");
finish();
return;
}

if (!isCallingAppPermitted(targetActivityInfo.permission)) {
Log.e(TAG, "Calling app must have the permission of deep link Activity");
finish();
return;
}
}

targetIntent.setComponent(targetComponentName);

// To prevent launchDeepLinkIntentToRight again for configuration change.
Expand All @@ -368,6 +409,19 @@ private void launchDeepLinkIntentToRight() {
targetIntent.setData(intent.getParcelableExtra(
SettingsHomepageActivity.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA));

// Only allow FLAG_GRANT_READ/WRITE_URI_PERMISSION if calling app has the permission to
// access specified Uri.
int uriPermissionFlags = targetIntent.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (targetIntent.getData() != null
&& uriPermissionFlags != 0
&& checkUriPermission(targetIntent.getData(), /* pid= */ -1, callingUid,
uriPermissionFlags) == PackageManager.PERMISSION_DENIED) {
Log.e(TAG, "Calling app must have the permission to access Uri and grant permission");
finish();
return;
}

// Set 2-pane pair rule for the deep link page.
ActivityEmbeddingRulesController.registerTwoPanePairRule(this,
new ComponentName(getApplicationContext(), getClass()),
Expand All @@ -386,6 +440,44 @@ private void launchDeepLinkIntentToRight() {
startActivity(targetIntent);
}

// Check if calling app has privileged access to launch Activity of activityInfo.
private boolean hasPrivilegedAccess(int callingUid, ActivityInfo activityInfo) {
if (TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
getPackageName())) {
return true;
}

int targetUid = -1;
try {
targetUid = getPackageManager().getApplicationInfo(activityInfo.packageName,
/* flags= */ 0).uid;
} catch (PackageManager.NameNotFoundException nnfe) {
Log.e(TAG, "Not able to get targetUid: " + nnfe);
return false;
}

// When activityInfo.exported is false, Activity still can be launched if applications have
// the same user ID.
if (UserHandle.isSameApp(callingUid, targetUid)) {
return true;
}

// When activityInfo.exported is false, Activity still can be launched if calling app has
// root or system privilege.
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID) {
return true;
}

return false;
}

@VisibleForTesting
boolean isCallingAppPermitted(String permission) {
return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
this, getActivityToken(), permission);
}

private String getHighlightMenuKey() {
final Intent intent = getIntent();
if (intent != null && TextUtils.equals(intent.getAction(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.content.Context;
import android.provider.Settings;
import android.widget.Switch;
import android.os.UserManager;

import androidx.preference.PreferenceScreen;

Expand All @@ -33,9 +34,11 @@ public class BluetoothScanningMainSwitchPreferenceController extends TogglePrefe
implements OnMainSwitchChangeListener {

private static final String KEY_BLUETOOTH_SCANNING_SWITCH = "bluetooth_always_scanning_switch";
private final UserManager mUserManager;

public BluetoothScanningMainSwitchPreferenceController(Context context) {
super(context, KEY_BLUETOOTH_SCANNING_SWITCH);
mUserManager = UserManager.get(context);
}

@Override
Expand All @@ -49,7 +52,9 @@ public void displayPreference(PreferenceScreen screen) {
@Override
public int getAvailabilityStatus() {
return mContext.getResources().getBoolean(R.bool.config_show_location_scanning)
? AVAILABLE
? (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_LOCATION)
? DISABLED_DEPENDENT_SETTING
: AVAILABLE)
: UNSUPPORTED_ON_DEVICE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.content.Context;
import android.net.wifi.WifiManager;
import android.widget.Switch;
import android.os.UserManager;

import androidx.preference.PreferenceScreen;

Expand All @@ -34,10 +35,12 @@ public class WifiScanningMainSwitchPreferenceController extends TogglePreference

private static final String KEY_WIFI_SCANNING_SWITCH = "wifi_always_scanning_switch";
private final WifiManager mWifiManager;
private final UserManager mUserManager;

public WifiScanningMainSwitchPreferenceController(Context context) {
super(context, KEY_WIFI_SCANNING_SWITCH);
mWifiManager = context.getSystemService(WifiManager.class);
mUserManager = UserManager.get(context);
}

@Override
Expand All @@ -52,7 +55,9 @@ public void displayPreference(PreferenceScreen screen) {
@Override
public int getAvailabilityStatus() {
return mContext.getResources().getBoolean(R.bool.config_show_location_scanning)
? AVAILABLE
? (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_LOCATION)
? DISABLED_DEPENDENT_SETTING
: AVAILABLE)
: UNSUPPORTED_ON_DEVICE;
}

Expand Down
2 changes: 1 addition & 1 deletion src/com/android/settings/nfc/SecureNfcEnabler.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ protected void handleNfcStateChanged(int newState) {
}

private boolean isToggleable() {
if (mUserManager.isGuestUser()) {
if (!mUserManager.isPrimaryUser()) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void onPause() {
}

private boolean isToggleable() {
if (mUserManager.isGuestUser()) {
if (!mUserManager.isPrimaryUser()) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class NotificationAccessSettings extends EmptyTextSettings {
private static final String TAG = "NotifAccessSettings";
private static final String ALLOWED_KEY = "allowed";
private static final String NOT_ALLOWED_KEY = "not_allowed";
private static final int MAX_CN_LENGTH = 500;

private static final ManagedServiceSettings.Config CONFIG =
new ManagedServiceSettings.Config.Builder()
Expand Down Expand Up @@ -98,6 +99,12 @@ public void onCreate(Bundle icicle) {
.setNoun(CONFIG.noun)
.setSetting(CONFIG.setting)
.setTag(CONFIG.tag)
.setValidator(info -> {
if (info.getComponentName().flattenToString().length() > MAX_CN_LENGTH) {
return false;
}
return true;
})
.build();
mServiceListing.addCallback(this::updateList);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
Expand All @@ -37,9 +39,11 @@
import com.android.settings.R;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;
import com.android.settings.testutils.shadow.ShadowPasswordUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -66,6 +70,11 @@ public void setUp() {
MockitoAnnotations.initMocks(this);
}

@After
public void tearDown() {
ShadowPasswordUtils.reset();
}

@Test
public void launch_shouldHaveAnimationForIaFragment() {
final SettingsHomepageActivity activity = Robolectric.buildActivity(
Expand Down Expand Up @@ -195,6 +204,32 @@ public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
& SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
}

@Test
@Config(shadows = {ShadowPasswordUtils.class})
public void isCallingAppPermitted_emptyPermission_returnTrue() {
SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());

assertTrue(homepageActivity.isCallingAppPermitted(""));
}

@Test
@Config(shadows = {ShadowPasswordUtils.class})
public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());

assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
}

@Test
@Config(shadows = {ShadowPasswordUtils.class})
public void isCallingAppPermitted_grantedPermission_returnTrue() {
SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
String permission = "android.permission.TEST";
ShadowPasswordUtils.addGrantedPermission(permission);

assertTrue(homepageActivity.isCallingAppPermitted(permission));
}

@Implements(SuggestionFeatureProviderImpl.class)
public static class ShadowSuggestionFeatureProviderImpl {

Expand Down