RESTRICT AUTOMERGE Fix READ/WRITE operation access issues on Restricted appOps.
Problems were identified around read and write access to the restricted appOps, this change includes:
- Filter out restricted appOps status for unprivileged readers.
- Allow additional privileged appOps permission holder reading restricted appOps status.
Bug: 336273802
Bug: 336323279
Test: Local test see b/336273802#comment3
Test: atest AppOpsTest#testRestrictedSettingsOpsRead
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e2471e03e471ed701dd1ac0c6c483f82b0dd22d0)
Merged-In: I09008b365e36b2c20c9a1fe5a1d52699ddb17d35
Change-Id: I09008b365e36b2c20c9a1fe5a1d52699ddb17d35
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9344d96..353bb15 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3290,7 +3290,7 @@
}
/**
- * Retrieve whether the op can be read by apps with manage appops permission.
+ * Retrieve whether the op can be read by apps with privileged appops permission.
* @hide
*/
public static boolean opRestrictsRead(int op) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 1bde4e2..b891aee 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2186,16 +2186,26 @@
private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
ArrayList<AppOpsManager.OpEntry> resOps = null;
final long elapsedNow = SystemClock.elapsedRealtime();
+ boolean shouldReturnRestrictedAppOps = mContext.checkPermission(
+ Manifest.permission.GET_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid())
+ == PackageManager.PERMISSION_GRANTED;
if (ops == null) {
resOps = new ArrayList<>();
- for (int j=0; j<pkgOps.size(); j++) {
+ for (int j = 0; j < pkgOps.size(); j++) {
Op curOp = pkgOps.valueAt(j);
+ if (opRestrictsRead(curOp.op) && !shouldReturnRestrictedAppOps) {
+ continue;
+ }
resOps.add(getOpEntryForResult(curOp, elapsedNow));
}
} else {
- for (int j=0; j<ops.length; j++) {
+ for (int j = 0; j < ops.length; j++) {
Op curOp = pkgOps.get(ops[j]);
if (curOp != null) {
+ if (opRestrictsRead(curOp.op) && !shouldReturnRestrictedAppOps) {
+ continue;
+ }
if (resOps == null) {
resOps = new ArrayList<>();
}
@@ -4400,10 +4410,21 @@
private void verifyIncomingOp(int op) {
if (op >= 0 && op < AppOpsManager._NUM_OP) {
- // Enforce manage appops permission if it's a restricted read op.
+ // Enforce privileged appops permission if it's a restricted read op.
if (opRestrictsRead(op)) {
- mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
- Binder.getCallingPid(), Binder.getCallingUid(), "verifyIncomingOp");
+ if (!(mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
+ Binder.getCallingPid(), Binder.getCallingUid())
+ == PackageManager.PERMISSION_GRANTED || mContext.checkPermission(
+ Manifest.permission.GET_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid())
+ == PackageManager.PERMISSION_GRANTED || mContext.checkPermission(
+ Manifest.permission.MANAGE_APP_OPS_MODES,
+ Binder.getCallingPid(), Binder.getCallingUid())
+ == PackageManager.PERMISSION_GRANTED)) {
+ throw new SecurityException("verifyIncomingOp: uid " + Binder.getCallingUid()
+ + " does not have any of {MANAGE_APPOPS, GET_APP_OPS_STATS, "
+ + "MANAGE_APP_OPS_MODES}");
+ }
}
return;
}