Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eec34e27 authored by yutingfang's avatar yutingfang Committed by Yuting Fang
Browse files

Impose a threshold on the number of attributed op entries returned in a binder call

In the binder call IAppOpsService#getPackagesForOpsForDevice, we return
attributed op entries encapsulated in PackageOps. When there are too
many attribution tags used for a lot of ops, the size of PackageOps can
be bloated and exceeds the binder transaction limit. However, this is
usually caused by DoS attack from malicious apps. A normal app wouldn't
run into this problem.

This CL adds a threshold on the number of attributed op entries that can
be returned in a binder call. The threshold is calculated assuming each
attribution tag is 50 bytes long.

Bug: 372678095
Test: manual. Using provided POC app from the reporter.
Verified the exception is gone after the fix.
Flag: EXEMPT bugfix
Change-Id: I43cd4b9774dbe554edcec296c4b8a3d7fc60c85c
parent 60f66360
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -236,6 +236,13 @@ public class AppOpsService extends IAppOpsService.Stub {
     */
    private static final int CURRENT_VERSION = 1;

    /**
     * The upper limit of total number of attributed op entries that can be returned in a binder
     * transaction to avoid TransactionTooLargeException
     */
    private static final int NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD = 2000;


    private SensorPrivacyManager mSensorPrivacyManager;

    // Write at most every 30 minutes.
@@ -1701,6 +1708,8 @@ public class AppOpsService extends IAppOpsService.Stub {
                Manifest.permission.GET_APP_OPS_STATS,
                Binder.getCallingPid(), Binder.getCallingUid())
                == PackageManager.PERMISSION_GRANTED;
        int totalAttributedOpEntryCount = 0;

        if (ops == null) {
            resOps = new ArrayList<>();
            for (int j = 0; j < pkgOps.size(); j++) {
@@ -1708,7 +1717,12 @@ public class AppOpsService extends IAppOpsService.Stub {
                if (opRestrictsRead(curOp.op) && !shouldReturnRestrictedAppOps) {
                    continue;
                }
                resOps.add(getOpEntryForResult(curOp, persistentDeviceId));
                if (totalAttributedOpEntryCount > NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD) {
                    break;
                }
                OpEntry opEntry = getOpEntryForResult(curOp, persistentDeviceId);
                resOps.add(opEntry);
                totalAttributedOpEntryCount += opEntry.getAttributedOpEntries().size();
            }
        } else {
            for (int j = 0; j < ops.length; j++) {
@@ -1720,10 +1734,21 @@ public class AppOpsService extends IAppOpsService.Stub {
                    if (opRestrictsRead(curOp.op) && !shouldReturnRestrictedAppOps) {
                        continue;
                    }
                    resOps.add(getOpEntryForResult(curOp, persistentDeviceId));
                    if (totalAttributedOpEntryCount > NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD) {
                        break;
                    }
                    OpEntry opEntry = getOpEntryForResult(curOp, persistentDeviceId);
                    resOps.add(opEntry);
                    totalAttributedOpEntryCount += opEntry.getAttributedOpEntries().size();
                }
            }
        }

        if (totalAttributedOpEntryCount > NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD) {
            Slog.w(TAG, "The number of attributed op entries has exceeded the threshold. This "
                    + "could be due to DoS attack from malicious apps. The result is throttled.");
        }

        return resOps;
    }