FRP bypass defense in the settings app

Over the last few years, there have been a number of
Factory Reset Protection bypass bugs in the SUW flow.
It's unlikely to defense all points from individual apps.

Therefore, we decide to block some critical pages when
user doesn't complete the SUW flow.

Test: Can't open the certain pages in the suw flow.
Fix: 200746457
Bug: 202975040
Fix: 213091525
Fix: 213090835
Fix: 201561699
Fix: 213090827
Fix: 213090875
Change-Id: Ia18f367109df5af7da0a5acad7702898a459d32e
This commit is contained in:
Tsung-Mao Fang
2022-01-03 18:25:04 +08:00
parent 1ee60270df
commit 07dd833a6a
10 changed files with 170 additions and 1 deletions

View File

@@ -23,11 +23,13 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.FrameLayout;
@@ -41,6 +43,7 @@ import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settings.widget.WorkOnlyCategory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -64,7 +67,9 @@ public class SettingsPreferenceFragmentTest {
private PreferenceScreen mPreferenceScreen;
private Context mContext;
private TestFragment mFragment;
private TestFragment2 mFragment2;
private View mEmptyView;
private int mInitDeviceProvisionedValue;
@Before
public void setUp() {
@@ -72,13 +77,24 @@ public class SettingsPreferenceFragmentTest {
FakeFeatureFactory.setupForTest();
mContext = RuntimeEnvironment.application;
mFragment = spy(new TestFragment());
mFragment2 = spy(new TestFragment2());
doReturn(mActivity).when(mFragment).getActivity();
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment2.getContext()).thenReturn(mContext);
mEmptyView = new View(mContext);
ReflectionHelpers.setField(mFragment, "mEmptyView", mEmptyView);
doReturn(ITEM_COUNT).when(mPreferenceScreen).getPreferenceCount();
mInitDeviceProvisionedValue = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0);
}
@After
public void tearDown() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, mInitDeviceProvisionedValue);
}
@Test
@@ -210,8 +226,66 @@ public class SettingsPreferenceFragmentTest {
assertThat(mFragment.mPinnedHeaderFrameLayout.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void onAttach_shouldNotSkipForSUWAndDeviceIsProvisioned_notCallFinish() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
mFragment.onAttach(mContext);
verify(mFragment, never()).finish();
}
@Test
public void onAttach_shouldNotSkipForSUWAndDeviceIsNotProvisioned_notCallFinish() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0);
mFragment.onAttach(mContext);
verify(mFragment, never()).finish();
}
@Test
public void onAttach_shouldSkipForSUWAndDeviceIsDeviceProvisioned_notCallFinish() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
mFragment2.onAttach(mContext);
verify(mFragment2, never()).finish();
}
@Test
public void onAttach_shouldSkipForSUWAndDeviceProvisioned_notCallFinish() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0);
mFragment2.onAttach(mContext);
verify(mFragment2, times(1)).finish();
}
public static class TestFragment extends SettingsPreferenceFragment {
@Override
protected boolean shouldSkipForInitialSUW() {
return false;
}
@Override
public int getMetricsCategory() {
return 0;
}
}
public static class TestFragment2 extends SettingsPreferenceFragment {
@Override
protected boolean shouldSkipForInitialSUW() {
return true;
}
@Override
public int getMetricsCategory() {
return 0;