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

Commit 4a960316 authored by Eran Messeri's avatar Eran Messeri
Browse files

Device Identifiers access: only on organization-owned devices

Deprecate access to device identifiers on non organization-owned
devices.

This is in line with changes to device identifiers access made in
Android Q. Profile owner access to device identifiers on personal
devices was deprecated in Q and is now removed.

However, on an organization-owned device, for asset management
purposes, the profile owner maintains access to device identifiers as
well as the ability to perform device ID attestation.

This is done by adjusting the checkDeviceIdentifierAccess method in the
DevicePolicyManagerService to take into account whether the profile
owner is on organization-owned device.

Bug: 145336515
Test: atest com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCanGetDeviceIdentifiers
Test: atest com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCanGetDeviceIdentifiers
Change-Id: I13486509b5af7acb4713adf8cb17fa301e647268
parent ee7d195f
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -5001,14 +5001,15 @@ public class DevicePolicyManager {
     * <p>Device owner, profile owner and their delegated certificate installer can use
     * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
     * including manufacturer, model, brand, device and product in the attestation record.
     * Only device owner and their delegated certificate installer can use
     * {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID} to request
     * unique device identifiers to be attested (the serial number, IMEI and MEID correspondingly),
     * if supported by the device (see {@link #isDeviceIdAttestationSupported()}).
     * Additionally, device owner and their delegated certificate installer can also request the
     * attestation record to be signed using an individual attestation certificate by specifying
     * the {@link #ID_TYPE_INDIVIDUAL_ATTESTATION} flag (if supported by the device, see
     * {@link #isUniqueDeviceAttestationSupported()}).
     * Only device owner, profile owner on an organization-owned device and their delegated
     * certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and
     * {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial number,
     * IMEI and MEID correspondingly), if supported by the device
     * (see {@link #isDeviceIdAttestationSupported()}).
     * Additionally, device owner, profile owner on an organization-owned device and their delegated
     * certificate installers can also request the attestation record to be signed using an
     * individual attestation certificate by specifying the {@link #ID_TYPE_INDIVIDUAL_ATTESTATION}
     * flag (if supported by the device, see {@link #isUniqueDeviceAttestationSupported()}).
     * <p>
     * If any of {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID}
     * is set, it is implicitly assumed that {@link #ID_TYPE_BASE_INFO} is also set.
+49 −34
Original line number Diff line number Diff line
@@ -8599,39 +8599,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @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);
        }
        ensureCallerIdentityMatchesIfNotSystem(packageName, pid, uid);
        // 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);
        if (!doesPackageMatchUid(packageName, uid)) {
            return false;
        }
        // A device or profile owner must also have the READ_PHONE_STATE permission to access device
@@ -8647,9 +8618,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                    || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
            return true;
        }
        final int userId = UserHandle.getUserId(uid);
        // Allow access to the profile owner for the specified user, or delegate cert installer
        // But only if this is an organization-owned device.
        ComponentName profileOwner = getProfileOwnerAsUser(userId);
        if (profileOwner != null && (profileOwner.getPackageName().equals(packageName)
        if (profileOwner != null && canProfileOwnerAccessDeviceIds(userId)
                && (profileOwner.getPackageName().equals(packageName)
                || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
            return true;
        }
@@ -8659,6 +8633,47 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        return false;
    }
    private boolean doesPackageMatchUid(String packageName, int uid) {
        final 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;
        }
        return true;
    }
    private void ensureCallerIdentityMatchesIfNotSystem(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);
        }
    }
    /**
     * Canonical name for a given package.
     */