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

Commit b83a568f authored by Tommy Webb's avatar Tommy Webb Committed by Michael Bestas
Browse files

Use POLICY_REJECT_ALL instead of allowlist

This allows us to keep track of a user's explicit intention to deny
network access to a UID while still allowing newly-added system apps
to have network access by default. It also allows us to retain an
app's network access allowed state when it is hidden and unhidden.

Issue: calyxos#1273
Issue: calyxos#1568
Change-Id: I74407c21cd4ed2cdd932d634577ae07d0bad67b1
parent c05f2daa
Loading
Loading
Loading
Loading
+114 −70
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_REPLACING;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_HIDDEN;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -367,6 +369,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final int VERSION_REMOVED_SUBSCRIPTION_PLANS = 14;
    private static final int VERSION_LATEST = VERSION_REMOVED_SUBSCRIPTION_PLANS;

    private static final int LINEAGE_VERSION_INIT = 1;
    private static final int LINEAGE_VERSION_REINSTATED_POLICY_REJECT_ALL = 2;
    private static final int LINEAGE_VERSION_LATEST = LINEAGE_VERSION_REINSTATED_POLICY_REJECT_ALL;

    @VisibleForTesting
    public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING;
    @VisibleForTesting
@@ -386,6 +392,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final String TAG_XML_UTILS_INT_ARRAY = "int-array";

    private static final String ATTR_VERSION = "version";
    private static final String ATTR_LINEAGE_VERSION = "lineageVersion";
    private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
@@ -1277,14 +1284,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                // global background data policy
                // Clear the cache for the app
                synchronized (mUidRulesFirstLock) {
                    if (hasInternetPermissionUL(uid)) {
                        Slog.i(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
                        Set<Integer> uids =
                                ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(
                                        context);
                        uids.add(uid);
                        ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(context,
                                uids);
                    if (!hasInternetPermissionUL(uid) && !isSystemApp(uid)) {
                        Slog.i(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid + ", no INTERNET");
                        addUidPolicy(uid, POLICY_REJECT_ALL);
                    }
                    mInternetPermissionMap.delete(uid);
                    updateRestrictionRulesForUidUL(uid);
@@ -1332,28 +1334,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        // Removing outside removeUserStateUL since that can also be called when
                        // user resets app preferences.
                        mMeteredRestrictedUids.remove(userId);
                        Set<Integer> uids =
                                ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(
                                        mContext);
                        if (action == ACTION_USER_ADDED) {
                            // Add apps that are allowed by default.
                            addDefaultRestrictBackgroundAllowlistUidsUL(userId);
                            try {
                                List<PackageInfo> packages = mIPm.getPackagesHoldingPermissions(
                                        new String[]{Manifest.permission.INTERNET},
                                        0, userId).getList();
                                uids.addAll(packages.stream().map(packageInfo ->
                                        packageInfo.applicationInfo.uid)
                                                .collect(Collectors.toSet()));
                            } catch (RemoteException ignored) {
                            }
                        } else {
                            uids.removeAll(uids.stream().filter(uid ->
                                    UserHandle.getUserId(uid) == userId)
                                    .collect(Collectors.toSet()));
                            synchronized (mUidRulesFirstLock) {
                                for (int i = 0; i < mUidPolicy.size(); i++) {
                                    final int uid = mUidPolicy.keyAt(i);
                                    if (UserHandle.getUserId(uid) == userId) {
                                        mUidPolicy.delete(uid);
                                    }
                                }
                            }
                        }
                        ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(mContext,
                                uids);
                        // Update global restrict for that user
                        synchronized (mNetworkPoliciesSecondLock) {
                            updateRulesForGlobalChangeAL(true);
@@ -2597,22 +2590,86 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private void migrateNetworkIsolation() {
        // Get pre-12 network-isolation uids
        final int[] uidsWithPolicy = getUidsWithPolicy(POLICY_REJECT_ALL);
        final Set<Integer> uidsToDeny =
                Arrays.stream(uidsWithPolicy).boxed().collect(Collectors.toSet());

        // Remove the POLICY_REJECT_ALL uids from the allowlist
        Set<Integer> uidsAllowedOnRestrictedNetworks =
    private void migrateToPolicyRejectAll() {
        final Set<Integer> uidsAllowedOnRestrictedNetworks =
                ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext);
        uidsAllowedOnRestrictedNetworks.removeAll(uidsToDeny);
        ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(mContext,
                uidsAllowedOnRestrictedNetworks);
        final Set<Integer> uidsToDeny = new ArraySet<>();

        // Clear policy to avoid future conflicts
        for (int uid : uidsToDeny) {
            removeUidPolicy(uid, POLICY_REJECT_ALL);
        for (final UserInfo userInfo : UserManager.get(mContext).getUsers()) {
            final List<ApplicationInfo> appsForUser;
            try {
                appsForUser = mIPm.getInstalledApplications(
                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userInfo.id).getList();
            } catch (RemoteException e) {
                Slog.e(TAG, "migrateToPolicyRejectAll: Failed to retrieve package UIDs for user "
                        + userInfo.id, e);
                continue;
            }
            for (final ApplicationInfo appInfo : appsForUser) {
                final int uid = appInfo.uid;
                // Allow apps that are already allowlisted, or that have restricted networking
                // permission, or that are system apps without the INTERNET permission.
                final boolean shouldAllow = uidsAllowedOnRestrictedNetworks.contains(uid)
                        || hasRestrictedModeAccess(uid);
                if (!shouldAllow) {
                    synchronized (mUidRulesFirstLock) {
                        if (appInfo.isSystemApp() && !hasInternetPermissionUL(uid)) {
                            // Allow system-bundled apps to add the INTERNET permission later
                            // without the user needing to turn on their network access manually;
                            // don't add system apps lacking that permission to the denylist now.
                            continue;
                        }
                        if (((appInfo.privateFlags & PRIVATE_FLAG_HIDDEN) != PRIVATE_FLAG_HIDDEN)
                                && ((appInfo.flags & FLAG_INSTALLED) != FLAG_INSTALLED)) {
                            // If the app is not hidden *and* not "installed," then it's truly not
                            // installed for the user or profile, so don't add it to the denylist.
                            continue;
                        }
                        uidsToDeny.add(uid);
                    }
                }
            }
        }

        // Add POLICY_REJECT_ALL to UIDs that are not allowed to use networks.
        setPolicyForUids(uidsToDeny, POLICY_REJECT_ALL, true /* enabled */);

        // Unset the restricted mode allowlist setting, which will no longer be utilized.
        ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(mContext, Set.of());
    }

    private boolean isSystemApp(int uid) {
        final String packageName = getPackageForUid(uid);
        if (packageName == null) return false;
        final ApplicationInfo appInfo;
        try {
            appInfo = mContext.getPackageManager().getApplicationInfo(packageName,
                    PackageManager.MATCH_UNINSTALLED_PACKAGES);
        } catch (PackageManager.NameNotFoundException ignored) {
            return false;
        }
        return appInfo.isSystemApp();
    }

    private void setPolicyForUids(final Set<Integer> uids, int policy, boolean enabled) {
        synchronized (mUidRulesFirstLock) {
            for (final int uid : uids) {
                // Update the policy in memory before writing it to disk.
                int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
                final boolean wasEnabled = (uidPolicy & policy) == policy;
                if (enabled != wasEnabled) {
                    if (enabled) {
                        uidPolicy = uidPolicy | policy;
                    } else {
                        uidPolicy = uidPolicy & ~policy;
                    }
                    setUidPolicyUncheckedUL(uid, uidPolicy, false /* persist */);
                }
            }
            synchronized (mNetworkPoliciesSecondLock) {
                // Persist the policy now that we are done updating it.
                writePolicyAL();
            }
        }
    }

@@ -2638,9 +2695,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        } finally {
            IoUtils.closeQuietly(fis);
        }

        // Migrate from pre-12 network-isolation to restricted-networking-mode
        migrateNetworkIsolation();
    }

    private void readPolicyXml(InputStream inputStream, boolean forRestore, int userId)
@@ -2653,6 +2707,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

        int type;
        int version = VERSION_INIT;
        int lineageVersion = LINEAGE_VERSION_INIT;
        boolean insideAllowlist = false;
        while ((type = in.next()) != END_DOCUMENT) {
            final String tag = in.getName();
@@ -2660,6 +2715,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                if (TAG_POLICY_LIST.equals(tag)) {
                    final boolean oldValue = mRestrictBackground;
                    version = readIntAttribute(in, ATTR_VERSION);
                    lineageVersion = readIntAttribute(in, ATTR_LINEAGE_VERSION, lineageVersion);
                    mLoadedRestrictBackground = (version >= VERSION_ADDED_RESTRICT_BACKGROUND)
                            && readBooleanAttribute(in, ATTR_RESTRICT_BACKGROUND);
                } else if (TAG_NETWORK_POLICY.equals(tag)) {
@@ -2818,6 +2874,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                Slog.w(TAG, "unable to update policy on UID " + uid);
            }
        }

        // There is nothing to migrate if coming from pre-12 or from nothing.
        final boolean isMigratingFromAtLeastAndroid12 = version >= VERSION_SUPPORTED_CARRIER_USAGE;
        if (lineageVersion < LINEAGE_VERSION_REINSTATED_POLICY_REJECT_ALL
                && isMigratingFromAtLeastAndroid12) {
            migrateToPolicyRejectAll();
        }
    }

    /**
@@ -2938,26 +3001,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            out.endTag(null, TAG_UID_POLICY);
        }

        if (forBackup) {
            try {
                List<PackageInfo> packages = mIPm.getPackagesHoldingPermissions(
                        new String[]{android.Manifest.permission.INTERNET}, 0, userId
                ).getList();
                List<Integer> uids = packages.stream().map(packageInfo ->
                        packageInfo.applicationInfo.uid).collect(Collectors.toList());
                uids.removeAll(
                        ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext));
                for (int uid : uids) {
                    out.startTag(null, TAG_UID_POLICY);
                    writeStringAttribute(out, ATTR_XML_UTILS_NAME, getPackageForUid(uid));
                    writeIntAttribute(out, ATTR_POLICY, POLICY_REJECT_ALL);
                    out.endTag(null, TAG_UID_POLICY);
                }
            } catch (RemoteException ignored) {

            }
        }

        // write all allowlists
        out.startTag(null, TAG_WHITELIST);

@@ -2986,6 +3029,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private void writeUidIndependentAttributes(TypedXmlSerializer out) throws IOException {
        out.startTag(null, TAG_POLICY_LIST);
        writeIntAttribute(out, ATTR_VERSION, VERSION_LATEST);
        writeIntAttribute(out, ATTR_LINEAGE_VERSION, LINEAGE_VERSION_LATEST);
        writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);

        // write all known network policies
@@ -3058,9 +3102,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        } catch (IOException | XmlPullParserException e) {
            Slog.w(TAG, "applyRestore: error reading payload for user " + user, e);
        }

        // Migrate from pre-12 network-isolation to restricted-networking-mode
        migrateNetworkIsolation();
    }

    @Override
@@ -4481,7 +4522,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    @GuardedBy("mUidRulesFirstLock")
    private int updateBlockedReasonsForRestrictedModeUL(int uid) {
        final boolean hasRestrictedModeAccess = hasRestrictedModeAccess(uid);
        final boolean hasRestrictedModeAccess = hasRestrictedModeAccess(uid)
                || !isUidBlockedOnAllNetworks(uid);
        final int oldEffectiveBlockedReasons;
        final int newEffectiveBlockedReasons;
        final int uidRules;
@@ -4524,14 +4566,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private boolean isUidBlockedOnAllNetworks(int uid) {
        // Check for restricted-networking-mode status
        return (getUidPolicy(uid) & POLICY_REJECT_ALL) == POLICY_REJECT_ALL;
    }

    private boolean hasRestrictedModeAccess(int uid) {
        try {
            // TODO: this needs to be kept in sync with
            // PermissionMonitor#hasRestrictedNetworkPermission
            // Check for restricted-networking-mode status
            return ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext)
                    .contains(uid)
                    || mIPm.checkUidPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
            return mIPm.checkUidPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
                    == PERMISSION_GRANTED
                    || mIPm.checkUidPermission(NETWORK_STACK, uid) == PERMISSION_GRANTED
                    || mIPm.checkUidPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)