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

Commit 94672cea authored by Michael Groover's avatar Michael Groover
Browse files

Add device identifier permission checks to TelephonyPermissions

Bug: 131916175
Fixes: 136305129
Test: atest PhoneSubInfoControllerTest
Change-Id: Icca98347ab76b7c3468b95756a33a758a3abde37
Merged-In: I3c82c53ec89cd17b34a61166ccc9e9747388efac
parent f2aa4ce4
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -166,6 +166,7 @@ message Atom {
        BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
        ProcessStartTime process_start_time = 169;
        BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
        DeviceIdentifierAccessDenied device_identifier_access_denied = 172;
        NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"];
    }

@@ -3054,3 +3055,22 @@ message NetworkStackReported {
    optional android.stats.connectivity.NetworkStackEventData network_stack_event = 2 [(log_mode) = MODE_BYTES];
}

/**
 * Logs when a package is denied access to a device identifier based on the new access requirements.
 *
 * Logged from:
 *     frameworks/base/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
 */
message DeviceIdentifierAccessDenied {
    // The name of the package denied access to the requested device identifier.
    optional string package_name = 1;

    // The name of the device identifier method the package attempted to invoke.
    optional string method_name = 2;

    // True if the package is preinstalled.
    optional bool is_preinstalled = 3;

    // True if the package is privileged.
    optional bool is_priv_app = 4;
}
 No newline at end of file
+25 −0
Original line number Diff line number Diff line
@@ -5653,6 +5653,31 @@ public class DevicePolicyManager {
        return null;
    }

    /**
     * Returns whether the specified package can read the device identifiers.
     *
     * @param packageName The package name of the app to check for device identifier access.
     * @param pid The process id of the package to be checked.
     * @param uid The uid of the package to be checked.
     * @return whether the package can read the device identifiers.
     *
     * @hide
     */
    public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
        throwIfParentInstance("checkDeviceIdentifierAccess");
        if (packageName == null) {
            return false;
        }
        if (mService != null) {
            try {
                return mService.checkDeviceIdentifierAccess(packageName, pid, uid);
            } catch (RemoteException re) {
                throw re.rethrowFromSystemServer();
            }
        }
        return false;
    }

    /**
     * @hide
     * @return the human readable name of the organisation associated with this DPM or {@code null}
+3 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ interface IDevicePolicyManager {
    int getDeviceOwnerUserId();

    boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
    ComponentName getProfileOwnerAsUser(int userHandle);
    ComponentName getProfileOwner(int userHandle);
    String getProfileOwnerName(int userHandle);
    void setProfileEnabled(in ComponentName who);
@@ -153,6 +154,8 @@ interface IDevicePolicyManager {
    void clearProfileOwner(in ComponentName who);
    boolean hasUserSetupCompleted();

    boolean checkDeviceIdentifierAccess(in String packageName, int pid, int uid);

    void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
    CharSequence getDeviceOwnerLockScreenInfo();

+5 −1
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */
package com.android.server.devicepolicy;

import android.annotation.UserIdInt;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.os.PersistableBundle;
@@ -159,4 +158,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
    @Override
    public void setDefaultSmsApplication(ComponentName admin, String packageName) {
    }

    @Override
    public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
        return false;
    }
}
+84 −15
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
@@ -69,11 +68,10 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
        .PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
        .STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager
        .ADMIN_TYPE_DEVICE_OWNER;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager
        .ADMIN_TYPE_PROFILE_OWNER;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -219,11 +217,11 @@ import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.internal.util.StatLogger;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
@@ -5188,7 +5186,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    public void enforceCanManageCaCerts(ComponentName who, String callerPackage) {
        if (who == null) {
            if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
            if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
                    DELEGATION_CERT_INSTALL)) {
                mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
            }
        } else {
@@ -5364,7 +5363,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            if (UserHandle.getUserId(callerUid) != mOwners.getDeviceOwnerUserId()) {
                throw new SecurityException("Caller not from device owner user");
            }
            if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
            if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
                    DELEGATION_CERT_INSTALL)) {
                throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid() +
                        "has no permission to generate keys.");
            }
@@ -5766,15 +5766,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
     * @param scope the delegation scope to be checked.
     * @return {@code true} if the calling process is a delegate of {@code scope}.
     */
    private boolean isCallerDelegate(String callerPackage, String scope) {
    private boolean isCallerDelegate(String callerPackage, int callerUid, String scope) {
        Preconditions.checkNotNull(callerPackage, "callerPackage is null");
        if (!Arrays.asList(DELEGATIONS).contains(scope)) {
            throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
        }
        // Retrieve the UID and user ID of the calling process.
        final int callingUid = mInjector.binderGetCallingUid();
        final int userId = UserHandle.getUserId(callingUid);
        final int userId = UserHandle.getUserId(callerUid);
        synchronized (getLockObject()) {
            // Retrieve user policy data.
            final DevicePolicyData policy = getUserData(userId);
@@ -5787,7 +5786,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                    final int uid = mInjector.getPackageManager()
                            .getPackageUidAsUser(callerPackage, userId);
                    // Return true if the caller is actually callerPackage.
                    return uid == callingUid;
                    return uid == callerUid;
                } catch (NameNotFoundException e) {
                    // Ignore.
                }
@@ -5818,7 +5817,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                getActiveAdminForCallerLocked(who, reqPolicy);
            }
        // If no ComponentName is given ensure calling process has scope delegation.
        } else if (!isCallerDelegate(callerPackage, scope)) {
        } else if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(), scope)) {
            throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid()
                    + " is not a delegate of scope " + scope + ".");
        }
@@ -7782,6 +7781,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    @Override
    public ComponentName getProfileOwnerAsUser(int userHandle) {
        enforceCrossUsersPermission(userHandle);
        return getProfileOwner(userHandle);
    }
    @Override
    public ComponentName getProfileOwner(int userHandle) {
        if (!mHasFeature) {
@@ -7825,6 +7831,68 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        return getApplicationLabel(profileOwner.getPackageName(), userHandle);
    }
    @Override
    public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
        // If the caller is not a system app then it should only be able to check its own device
        // identifier access.
        int callingUid = mInjector.binderGetCallingUid();
        int callingPid = mInjector.binderGetCallingPid();
        if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID
                && (callingUid != uid || callingPid != pid)) {
            String message = String.format(
                    "Calling uid %d, pid %d cannot check device identifier access for package %s "
                            + "(uid=%d, pid=%d)", callingUid, callingPid, packageName, uid, pid);
            Log.w(LOG_TAG, message);
            throw new SecurityException(message);
        }
        // Verify that the specified packages matches the provided uid.
        int userId = UserHandle.getUserId(uid);
        try {
            ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0, userId);
            // Since this call goes directly to PackageManagerService a NameNotFoundException is not
            // thrown but null data can be returned; if the appInfo for the specified package cannot
            // be found then return false to prevent crashing the app.
            if (appInfo == null) {
                Log.w(LOG_TAG,
                        String.format("appInfo could not be found for package %s", packageName));
                return false;
            } else if (uid != appInfo.uid) {
                String message = String.format("Package %s (uid=%d) does not match provided uid %d",
                        packageName, appInfo.uid, uid);
                Log.w(LOG_TAG, message);
                throw new SecurityException(message);
            }
        } catch (RemoteException e) {
            // If an exception is caught obtaining the appInfo just return false to prevent crashing
            // apps due to an internal error.
            Log.e(LOG_TAG, "Exception caught obtaining appInfo for package " + packageName, e);
            return false;
        }
        // A device or profile owner must also have the READ_PHONE_STATE permission to access device
        // identifiers. If the package being checked does not have this permission then deny access.
        if (mContext.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid, uid)
                != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
        // Allow access to the device owner or delegate cert installer.
        ComponentName deviceOwner = getDeviceOwnerComponent(true);
        if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
                || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
            return true;
        }
        // Allow access to the profile owner for the specified user, or delegate cert installer
        ComponentName profileOwner = getProfileOwnerAsUser(userId);
        if (profileOwner != null && (profileOwner.getPackageName().equals(packageName)
                || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
            return true;
        }
        Log.w(LOG_TAG, String.format("Package %s (uid=%d, pid=%d) cannot access Device IDs",
                packageName, uid, pid));
        return false;
    }
    /**
     * Canonical name for a given package.
     */
@@ -8266,7 +8334,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @Override
    public boolean isCallerApplicationRestrictionsManagingPackage(String callerPackage) {
        return isCallerDelegate(callerPackage, DELEGATION_APP_RESTRICTIONS);
        return isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
                DELEGATION_APP_RESTRICTIONS);
    }
    @Override
Loading