MuntashirAkon / MuntashirAkon/AppManager

Feature/Bug: Warn users before batch modifying AppOps for shared system UIDs (< 10000) to prevent silent collateral permission loss

Open
#2,030 1 comment 2 reactions 0 assignees View on GitHub
Bug Status: Pending
Dominant language
Java
Stars
9k
Forks
518
PR merge metrics
No merged PRs in 30d

Description

### Please check before submitting an issue

- [x] I know what my device, OS and App Manager versions are
- [x] I know how to take logs
- [x] I know that generating a report, in whole part or in part, using AI/LLM is prohibited
- [x] I know how to reproduce the issue which may not be specific to my device

### Describe the bug

In `AppOpsManagerCompat.setMode()`, for Android M (API 23)+ and non-MIUI ops, the method correctly uses `setUidMode` to ensure permissions are consistent at the UID level.

While I agree that using `setUidMode` is the correct Android standard (as apps sharing the same UID run in the same security domain), this introduces a severe side effect: **stripping permissions from a shared-UID system app silently affects all other system apps sharing that UID.**

When a user manually modifies a single AppOp, this side effect is somewhat expected.

However, when users perform **batch operations** on a specific system app, the blast radius is massive and silent. If a user clicks "Delete All Rules" on a system-level app (Android M (API 23) and above, and not a MIUI-specific Appops), and this system-level app happens to share the same UID as the system framework (System), (`ComponentUtils.java`):

```java
appOpsManager.resetAllModes(userHandle, packageName);
for (AppOpRule entry : cb.getAll(AppOpRule.class)) {
appOpsManager.setMode(entry.getOp(), uid, packageName, MODE_DEFAULT);
// Under the hood, this calls setUidMode(entry.getOp(), uid, MODE_DEFAULT)
}
```

This means that `resetAllModes` inadvertently resets all AppOps associated with a specific UID to their default values. Many essential permissions—such as `GET_USAGE_STATS`—default to `MODE_DEFAULT` (meaning "not explicitly granted," which is effectively a denial), immediately causing a host of issues.

If a user taps "Delete all rules" within a specific system-level app( share the same UID as the system framework ), they might immediately find that System Settings crashes with a security exception when calling `StorageStatsManager.getFreeBytes()` (e.g., when accessing Storage settings); Furthermore, the user may not easily realize the cause or be able to revert the change in time.

And if a user inadvertently taps "Ignore all dangerous permissions" for a specific system app, then within `ignoreDangerousAppOps()` in (`AppDetailsViewModel.java`):

```java
for (AppDetailsAppOpItem mAppOpItem : mAppOpItems) {
permName = AppOpsManagerCompat.opToPermission(mAppOpItem.getOp());
if (basePermissionType == PermissionInfo.PROTECTION_DANGEROUS) {
PermUtils.setAppOpMode(mAppOpsManager, mAppOpItem.getOp(), mPackageName,
packageInfo.applicationInfo.uid,
AppOpsManager.MODE_IGNORED);
}
}
```

This method iterates through all AppOps entries for packages sharing the same UID and sets all "dangerous" ones to IGNORED.

There are three additional locations:
- Resetting all AppOps (`resetAppOps()`) in `AppDetailsViewModel.java` (lines 812–836);
- Batch AppOps modification in `ExternalComponentsImporter.java` (line 50);
- Backup/restore operations in `RestoreOp.java` (line 661).

Although these actions also trigger `setUidMode`, the user is at least aware of them and can revert the changes promptly.

### To Reproduce

- 1. Go to a specific system app that shares a UID with the Android framework (e.g., UID 1000).
- 2. Click "Delete all rules" or "Ignore all dangerous permissions".
- 3. Observe that all apps sharing that specific system UID (e.g., android.uid.system / UID 1000) have their AppOps reset or ignored. Some system functions break unexpectedly. For example, opening Storage in system settings causes a security exception crash (StorageStatsManager.getFreeBytes()), and the user is unaware of the root cause.

### Expected behavior

I am **not** suggesting reverting to package-level `setMode(op, uid, packageName, mode)` for system apps, as privacy and access control must maintain UID-level consistency.
Instead, the expected behavior is to implement a **Safety Warning Dialog**:

* Before executing actions like "Delete all rules" or "Ignore all dangerous permissions", check if **`uid < Process.FIRST_APPLICATION_UID (10000)`** AND if the UID is shared by multiple packages.
* If true, pop up a warning alerting the user: *"This app shares a core system UID. Modifying these rules will affect the entire Android framework and other system apps. Do you want to proceed?"*

### Screenshots

_No response_

### Logs

Caused by: java.lang.SecurityException: android from uid 1000 not allowed to perform GET_USAGE_STATS

### Device info

- OS Version: Pixel OS, Android 14
- App Manager Version: 4.1.0
- Mode: Root

### Additional context

_No response_

Contributor guide

Open the contributing guide

Research direction

Read AppOpsManagerCompat.setMode() and trace the batch actions in ComponentUtils.java, AppDetailsViewModel.java, ExternalComponentsImporter.java, and RestoreOp.java. Start by reproducing the shared-UID behavior with a UID below 10000, then inspect how the affected actions open their confirmation flows. Done means the specified batch operations warn when the UID is shared and allow the user to proceed or cancel.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java
Domain
mobile-dev, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.