From 0ee3b96e59f3e5699c919af3642130fb33cd263b Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 1/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 126 ++++++++++-------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 113922e2303..59ec178ecb0 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -50,6 +50,8 @@ import android.text.method.ScrollingMovementMethod; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -138,7 +140,7 @@ public class DeviceAdminAdd extends Activity { mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -148,7 +150,7 @@ public class DeviceAdminAdd extends Activity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -206,7 +208,7 @@ public class DeviceAdminAdd extends Activity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From cb2b75309466a624e75be6967657f312be91ed30 Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 2/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 131 +++++++++--------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 7b2f4ba15af..2a4250a4fcb 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -52,6 +52,7 @@ import android.text.TextUtils.TruncateAt; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -142,12 +143,12 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mHandler = new Handler(getMainLooper()); - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); - mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mDPM = getSystemService(DevicePolicyManager.class); + mAppOps = getSystemService(AppOpsManager.class); + mLayoutInflaternflater = getSystemService(LayoutInflater.class); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -157,7 +158,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -215,7 +216,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From f753a3c8df9e0fd15a445681532492ef5385d8f4 Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 3/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 133 +++++++++--------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index fa76a948c06..fee05277a60 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -66,6 +66,7 @@ import android.text.TextUtils.TruncateAt; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -156,12 +157,12 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mHandler = new Handler(getMainLooper()); - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); + mDPM = getSystemService(DevicePolicyManager.class); + mAppOps = getSystemService(AppOpsManager.class); mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -171,7 +172,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -229,7 +230,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i - getString(R.string.device_admin_warning_simplified, - mProfileOwnerName), mProfileOwnerName)); + getString(R.string.device_admin_warning_simplified, + mProfileOwnerName), mProfileOwnerName)); return; } setContentView(R.layout.device_admin_add); - mAdminIcon = (ImageView)findViewById(R.id.admin_icon); - mAdminName = (TextView)findViewById(R.id.admin_name); - mAdminDescription = (TextView)findViewById(R.id.admin_description); + mAdminIcon = (ImageView) findViewById(R.id.admin_icon); + mAdminName = (TextView) findViewById(R.id.admin_name); + mAdminDescription = (TextView) findViewById(R.id.admin_description); mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning); mProfileOwnerWarning.setText( mDPM.getResources().getString(SET_PROFILE_OWNER_POSTSETUP_WARNING, () -> getString(R.string.adding_profile_owner_warning))); - mAddMsg = (TextView)findViewById(R.id.add_msg); + mAddMsg = (TextView) findViewById(R.id.add_msg); mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander); final View.OnClickListener onClickListener = new View.OnClickListener() { @Override @@ -381,7 +382,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines; mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE); if (hideMsgExpander) { - ((View)mAddMsgExpander.getParent()).invalidate(); + ((View) mAddMsgExpander.getParent()).invalidate(); } mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this); } @@ -399,7 +400,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mCancelButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER, - mDeviceAdmin.getActivityInfo().applicationInfo.uid); + mDeviceAdmin.getActivityInfo().applicationInfo.uid); finish(); } }); @@ -421,58 +422,64 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { final View restrictedAction = findViewById(R.id.restricted_action); restrictedAction.setFilterTouchesWhenObscured(true); - restrictedAction.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - if (!mActionButton.isEnabled()) { - showPolicyTransparencyDialogIfRequired(); - return; - } - if (mAdding) { - addAndFinish(); - } else if (isManagedProfile(mDeviceAdmin) - && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { - final int userId = UserHandle.myUserId(); - UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - UserManager um = UserManager.get(DeviceAdminAdd.this); - um.removeUser(userId); - finish(); - } - } - ).show(); - } else if (mUninstalling) { - mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); - finish(); - } else if (!mWaitingForRemoveMsg) { - try { - // Don't allow the admin to put a dialog up in front - // of us while we interact with the user. - ActivityManager.getService().stopAppSwitches(); - } catch (RemoteException e) { - } - mWaitingForRemoveMsg = true; - mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), - new RemoteCallback(new RemoteCallback.OnResultListener() { - @Override - public void onResult(Bundle result) { - CharSequence msg = result != null - ? result.getCharSequence( - DeviceAdminReceiver.EXTRA_DISABLE_WARNING) - : null; - continueRemoveAction(msg); - } - }, mHandler)); - // Don't want to wait too long. - getWindow().getDecorView().getHandler().postDelayed(new Runnable() { - @Override public void run() { - continueRemoveAction(null); - } - }, 2*1000); - } + + final View.OnClickListener restrictedActionClickListener = v -> { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From 0976cd789d3bfb593e73237b5b0adc39933a1c1c Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 4/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 135 +++++++++--------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index fa76a948c06..5746d13666a 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -66,6 +66,7 @@ import android.text.TextUtils.TruncateAt; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -156,12 +157,12 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mHandler = new Handler(getMainLooper()); - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); - mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mDPM = getSystemService(DevicePolicyManager.class); + mAppOps = getSystemService(AppOpsManager.class); + mLayoutInflaternflater = getSystemService(LayoutInflater.class); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -171,7 +172,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -229,7 +230,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i - getString(R.string.device_admin_warning_simplified, - mProfileOwnerName), mProfileOwnerName)); + getString(R.string.device_admin_warning_simplified, + mProfileOwnerName), mProfileOwnerName)); return; } setContentView(R.layout.device_admin_add); - mAdminIcon = (ImageView)findViewById(R.id.admin_icon); - mAdminName = (TextView)findViewById(R.id.admin_name); - mAdminDescription = (TextView)findViewById(R.id.admin_description); + mAdminIcon = (ImageView) findViewById(R.id.admin_icon); + mAdminName = (TextView) findViewById(R.id.admin_name); + mAdminDescription = (TextView) findViewById(R.id.admin_description); mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning); mProfileOwnerWarning.setText( mDPM.getResources().getString(SET_PROFILE_OWNER_POSTSETUP_WARNING, () -> getString(R.string.adding_profile_owner_warning))); - mAddMsg = (TextView)findViewById(R.id.add_msg); + mAddMsg = (TextView) findViewById(R.id.add_msg); mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander); final View.OnClickListener onClickListener = new View.OnClickListener() { @Override @@ -381,7 +382,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines; mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE); if (hideMsgExpander) { - ((View)mAddMsgExpander.getParent()).invalidate(); + ((View) mAddMsgExpander.getParent()).invalidate(); } mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this); } @@ -399,7 +400,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mCancelButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER, - mDeviceAdmin.getActivityInfo().applicationInfo.uid); + mDeviceAdmin.getActivityInfo().applicationInfo.uid); finish(); } }); @@ -421,58 +422,64 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { final View restrictedAction = findViewById(R.id.restricted_action); restrictedAction.setFilterTouchesWhenObscured(true); - restrictedAction.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - if (!mActionButton.isEnabled()) { - showPolicyTransparencyDialogIfRequired(); - return; - } - if (mAdding) { - addAndFinish(); - } else if (isManagedProfile(mDeviceAdmin) - && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { - final int userId = UserHandle.myUserId(); - UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - UserManager um = UserManager.get(DeviceAdminAdd.this); - um.removeUser(userId); - finish(); - } - } - ).show(); - } else if (mUninstalling) { - mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); - finish(); - } else if (!mWaitingForRemoveMsg) { - try { - // Don't allow the admin to put a dialog up in front - // of us while we interact with the user. - ActivityManager.getService().stopAppSwitches(); - } catch (RemoteException e) { - } - mWaitingForRemoveMsg = true; - mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), - new RemoteCallback(new RemoteCallback.OnResultListener() { - @Override - public void onResult(Bundle result) { - CharSequence msg = result != null - ? result.getCharSequence( - DeviceAdminReceiver.EXTRA_DISABLE_WARNING) - : null; - continueRemoveAction(msg); - } - }, mHandler)); - // Don't want to wait too long. - getWindow().getDecorView().getHandler().postDelayed(new Runnable() { - @Override public void run() { - continueRemoveAction(null); - } - }, 2*1000); - } + + final View.OnClickListener restrictedActionClickListener = v -> { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From 0564ec25bb4706257038f202687cc9172880a82e Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 5/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 126 ++++++++++-------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 113922e2303..59ec178ecb0 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -50,6 +50,8 @@ import android.text.method.ScrollingMovementMethod; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -138,7 +140,7 @@ public class DeviceAdminAdd extends Activity { mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -148,7 +150,7 @@ public class DeviceAdminAdd extends Activity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -206,7 +208,7 @@ public class DeviceAdminAdd extends Activity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From 27a97f458391c4323f031ededcb7c3b5d7b8c6bf Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 6/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 131 +++++++++--------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 7b2f4ba15af..2a4250a4fcb 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -52,6 +52,7 @@ import android.text.TextUtils.TruncateAt; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -142,12 +143,12 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mHandler = new Handler(getMainLooper()); - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); - mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mDPM = getSystemService(DevicePolicyManager.class); + mAppOps = getSystemService(AppOpsManager.class); + mLayoutInflaternflater = getSystemService(LayoutInflater.class); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -157,7 +158,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -215,7 +216,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From 76b536abc8ee503846da6b3060f74b69e1a20f15 Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 19 May 2023 23:17:47 +0000 Subject: [PATCH 7/8] DO NOT MERGE: Prevent non-system IME from becoming device admin Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to activate itself as device admin and cause various DoS attacks. This CL ensures KeyEvent on "Activate" button can only come from system apps. Bug: 280793427 Test: atest DeviceAdminActivationTest Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188 (cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373) --- .../deviceadmin/DeviceAdminAdd.java | 131 +++++++++--------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 7b2f4ba15af..2a4250a4fcb 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -52,6 +52,7 @@ import android.text.TextUtils.TruncateAt; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -142,12 +143,12 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mHandler = new Handler(getMainLooper()); - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); - mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mDPM = getSystemService(DevicePolicyManager.class); + mAppOps = getSystemService(AppOpsManager.class); + mLayoutInflaternflater = getSystemService(LayoutInflater.class); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -157,7 +158,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -215,7 +216,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** From 627a584f39ce1d5bac4a5e41d682a4db848e5789 Mon Sep 17 00:00:00 2001 From: Patty Huang Date: Tue, 4 Jul 2023 17:54:00 +0800 Subject: [PATCH 8/8] Do not show LE audio toggle in Device Detail by default Bug: 289884263 Bug: 289957406 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothLeAudioDeviceDetailsPreferenceControllerTest Test: Checks the LE Audio toggle is not shown in Device Detail by default Change-Id: I2c6430c791dd852d238d7122a72f218f395c4a0b --- .../bluetooth/BluetoothDetailsProfilesController.java | 4 +++- .../BluetoothLeAudioDeviceDetailsPreferenceController.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java index 701967bfb5e..3472e3940ce 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java @@ -69,6 +69,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private static final String ENABLE_DUAL_MODE_AUDIO = "persist.bluetooth.enable_dual_mode_audio"; private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default"; + private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = false; private LocalBluetoothManager mManager; private LocalBluetoothProfileManager mProfileManager; @@ -444,7 +445,8 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true); boolean isLeDeviceDetailEnabled = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SETTINGS_UI, - SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, true); + SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, + LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE); boolean isLeEnabledByDefault = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false); mIsLeAudioToggleEnabled = isLeDeviceDetailEnabled || isLeEnabledByDefault; diff --git a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java index 298ced091a9..9545728d87e 100644 --- a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java +++ b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java @@ -40,7 +40,7 @@ public class BluetoothLeAudioDeviceDetailsPreferenceController private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details"; private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default"; - private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true; + private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = false; static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN; @VisibleForTesting