diff options
Diffstat (limited to 'apex/blobstore/service/java')
4 files changed, 133 insertions, 20 deletions
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java index 4a527adf9abc..ca588c509594 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java @@ -15,18 +15,29 @@ */ package com.android.server.blob; +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.app.blob.XmlTags.ATTR_CERTIFICATE; import static android.app.blob.XmlTags.ATTR_PACKAGE; import static android.app.blob.XmlTags.ATTR_TYPE; +import static android.app.blob.XmlTags.ATTR_VALUE; import static android.app.blob.XmlTags.TAG_ALLOWED_PACKAGE; +import static android.app.blob.XmlTags.TAG_ALLOWED_PERMISSION; + +import static com.android.server.blob.BlobStoreConfig.TAG; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.permission.PermissionManager; import android.util.ArraySet; import android.util.Base64; import android.util.DebugUtils; +import android.util.Slog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; @@ -53,21 +64,27 @@ class BlobAccessMode { ACCESS_TYPE_PUBLIC, ACCESS_TYPE_SAME_SIGNATURE, ACCESS_TYPE_ALLOWLIST, + ACCESS_TYPE_LOCATION_PERMISSION, }) @interface AccessType {} public static final int ACCESS_TYPE_PRIVATE = 1 << 0; public static final int ACCESS_TYPE_PUBLIC = 1 << 1; public static final int ACCESS_TYPE_SAME_SIGNATURE = 1 << 2; public static final int ACCESS_TYPE_ALLOWLIST = 1 << 3; + public static final int ACCESS_TYPE_LOCATION_PERMISSION = 1 << 4; private int mAccessType = ACCESS_TYPE_PRIVATE; private final ArraySet<PackageIdentifier> mAllowedPackages = new ArraySet<>(); + private final ArraySet<String> mAllowedPermissions = new ArraySet<>(); void allow(BlobAccessMode other) { if ((other.mAccessType & ACCESS_TYPE_ALLOWLIST) != 0) { mAllowedPackages.addAll(other.mAllowedPackages); } + if ((other.mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) != 0) { + mAllowedPermissions.addAll(other.mAllowedPermissions); + } mAccessType |= other.mAccessType; } @@ -84,6 +101,11 @@ class BlobAccessMode { mAllowedPackages.add(PackageIdentifier.create(packageName, certificate)); } + void allowPackagesWithLocationPermission(@NonNull String permissionName) { + mAccessType |= ACCESS_TYPE_LOCATION_PERMISSION; + mAllowedPermissions.add(permissionName); + } + boolean isPublicAccessAllowed() { return (mAccessType & ACCESS_TYPE_PUBLIC) != 0; } @@ -99,8 +121,15 @@ class BlobAccessMode { return mAllowedPackages.contains(PackageIdentifier.create(packageName, certificate)); } - boolean isAccessAllowedForCaller(Context context, - @NonNull String callingPackage, @NonNull String committerPackage) { + boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName) { + if ((mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) == 0) { + return false; + } + return mAllowedPermissions.contains(permissionName); + } + + boolean isAccessAllowedForCaller(Context context, @NonNull String callingPackage, + @NonNull String committerPackage, int callingUid, @Nullable String attributionTag) { if ((mAccessType & ACCESS_TYPE_PUBLIC) != 0) { return true; } @@ -124,9 +153,37 @@ class BlobAccessMode { } } + if ((mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) != 0) { + final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + for (int i = 0; i < mAllowedPermissions.size(); ++i) { + final String permission = mAllowedPermissions.valueAt(i); + if (PermissionManager.checkPackageNamePermission(permission, callingPackage, + UserHandle.getUserId(callingUid)) != PackageManager.PERMISSION_GRANTED) { + continue; + } + // TODO: Add appropriate message + if (appOpsManager.noteOpNoThrow(getAppOp(permission), callingUid, callingPackage, + attributionTag, null /* message */) == AppOpsManager.MODE_ALLOWED) { + return true; + } + } + } + return false; } + private static String getAppOp(String permission) { + switch (permission) { + case ACCESS_FINE_LOCATION: + return AppOpsManager.OPSTR_FINE_LOCATION; + case ACCESS_COARSE_LOCATION: + return AppOpsManager.OPSTR_COARSE_LOCATION; + default: + Slog.w(TAG, "Unknown permission found: " + permission); + return null; + } + } + int getAccessType() { return mAccessType; } @@ -148,6 +205,16 @@ class BlobAccessMode { } fout.decreaseIndent(); } + fout.print("Allowed permissions:"); + if (mAllowedPermissions.isEmpty()) { + fout.println(" (Empty)"); + } else { + fout.increaseIndent(); + for (int i = 0, count = mAllowedPermissions.size(); i < count; ++i) { + fout.println(mAllowedPermissions.valueAt(i).toString()); + } + fout.decreaseIndent(); + } } void writeToXml(@NonNull XmlSerializer out) throws IOException { @@ -159,6 +226,12 @@ class BlobAccessMode { XmlUtils.writeByteArrayAttribute(out, ATTR_CERTIFICATE, packageIdentifier.certificate); out.endTag(null, TAG_ALLOWED_PACKAGE); } + for (int i = 0, count = mAllowedPermissions.size(); i < count; ++i) { + out.startTag(null, TAG_ALLOWED_PERMISSION); + final String permission = mAllowedPermissions.valueAt(i); + XmlUtils.writeStringAttribute(out, ATTR_VALUE, permission); + out.endTag(null, TAG_ALLOWED_PERMISSION); + } } @NonNull @@ -176,6 +249,10 @@ class BlobAccessMode { final byte[] certificate = XmlUtils.readByteArrayAttribute(in, ATTR_CERTIFICATE); blobAccessMode.allowPackageAccess(packageName, certificate); } + if (TAG_ALLOWED_PERMISSION.equals(in.getName())) { + final String permission = XmlUtils.readStringAttribute(in, ATTR_VALUE); + blobAccessMode.allowPackagesWithLocationPermission(permission); + } } return blobAccessMode; } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java index fb02e960f91a..8b12beb57195 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -229,7 +229,8 @@ class BlobMetadata { return getBlobFile().length(); } - boolean isAccessAllowedForCaller(@NonNull String callingPackage, int callingUid) { + boolean isAccessAllowedForCaller(@NonNull String callingPackage, int callingUid, + @Nullable String attributionTag) { // Don't allow the blob to be accessed after it's expiry time has passed. if (getBlobHandle().isExpired()) { return false; @@ -254,7 +255,7 @@ class BlobMetadata { // Check if the caller is allowed access as per the access mode specified // by the committer. if (committer.blobAccessMode.isAccessAllowedForCaller(mContext, - callingPackage, committer.packageName)) { + callingPackage, committer.packageName, callingUid, attributionTag)) { return true; } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index f77f6c642f6a..0e7354726123 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -402,12 +402,12 @@ public class BlobStoreManagerService extends SystemService { } private ParcelFileDescriptor openBlobInternal(BlobHandle blobHandle, int callingUid, - String callingPackage) throws IOException { + String callingPackage, String attributionTag) throws IOException { synchronized (mBlobsLock) { final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid)) .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( - callingPackage, callingUid)) { + callingPackage, callingUid, attributionTag)) { if (blobMetadata == null) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, INVALID_BLOB_ID, INVALID_BLOB_SIZE, @@ -455,7 +455,7 @@ public class BlobStoreManagerService extends SystemService { private void acquireLeaseInternal(BlobHandle blobHandle, int descriptionResId, CharSequence description, long leaseExpiryTimeMillis, - int callingUid, String callingPackage) { + int callingUid, String callingPackage, String attributionTag) { synchronized (mBlobsLock) { final int leasesCount = getLeasedBlobsCountLocked(callingUid, callingPackage); if (leasesCount >= getMaxLeasedBlobs()) { @@ -468,7 +468,7 @@ public class BlobStoreManagerService extends SystemService { final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid)) .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( - callingPackage, callingUid)) { + callingPackage, callingUid, attributionTag)) { if (blobMetadata == null) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, INVALID_BLOB_ID, INVALID_BLOB_SIZE, @@ -527,13 +527,13 @@ public class BlobStoreManagerService extends SystemService { } private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid, - String callingPackage) { + String callingPackage, String attributionTag) { synchronized (mBlobsLock) { final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(UserHandle.getUserId(callingUid)); final BlobMetadata blobMetadata = userBlobs.get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( - callingPackage, callingUid)) { + callingPackage, callingUid, attributionTag)) { throw new SecurityException("Caller not allowed to access " + blobHandle + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } @@ -634,12 +634,12 @@ public class BlobStoreManagerService extends SystemService { } private LeaseInfo getLeaseInfoInternal(BlobHandle blobHandle, - int callingUid, @NonNull String callingPackage) { + int callingUid, @NonNull String callingPackage, String attributionTag) { synchronized (mBlobsLock) { final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid)) .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( - callingPackage, callingUid)) { + callingPackage, callingUid, attributionTag)) { throw new SecurityException("Caller not allowed to access " + blobHandle + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } @@ -1465,7 +1465,7 @@ public class BlobStoreManagerService extends SystemService { @Override public ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle, - @NonNull String packageName) { + @NonNull String packageName, @Nullable String attributionTag) { Objects.requireNonNull(blobHandle, "blobHandle must not be null"); blobHandle.assertIsValid(); Objects.requireNonNull(packageName, "packageName must not be null"); @@ -1480,7 +1480,7 @@ public class BlobStoreManagerService extends SystemService { } try { - return openBlobInternal(blobHandle, callingUid, packageName); + return openBlobInternal(blobHandle, callingUid, packageName, attributionTag); } catch (IOException e) { throw ExceptionUtils.wrap(e); } @@ -1489,7 +1489,8 @@ public class BlobStoreManagerService extends SystemService { @Override public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId, @Nullable CharSequence description, - @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName) { + @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName, + @Nullable String attributionTag) { Objects.requireNonNull(blobHandle, "blobHandle must not be null"); blobHandle.assertIsValid(); Preconditions.checkArgument( @@ -1513,7 +1514,7 @@ public class BlobStoreManagerService extends SystemService { try { acquireLeaseInternal(blobHandle, descriptionResId, description, - leaseExpiryTimeMillis, callingUid, packageName); + leaseExpiryTimeMillis, callingUid, packageName, attributionTag); } catch (Resources.NotFoundException e) { throw new IllegalArgumentException(e); } catch (LimitExceededException e) { @@ -1522,7 +1523,8 @@ public class BlobStoreManagerService extends SystemService { } @Override - public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName) { + public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName, + @Nullable String attributionTag) { Objects.requireNonNull(blobHandle, "blobHandle must not be null"); blobHandle.assertIsValid(); Objects.requireNonNull(packageName, "packageName must not be null"); @@ -1536,7 +1538,7 @@ public class BlobStoreManagerService extends SystemService { + "callingUid=" + callingUid + ", callingPackage=" + packageName); } - releaseLeaseInternal(blobHandle, callingUid, packageName); + releaseLeaseInternal(blobHandle, callingUid, packageName, attributionTag); } @Override @@ -1606,7 +1608,8 @@ public class BlobStoreManagerService extends SystemService { @Override @Nullable - public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle, @NonNull String packageName) { + public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle, @NonNull String packageName, + @Nullable String attributionTag) { Objects.requireNonNull(blobHandle, "blobHandle must not be null"); blobHandle.assertIsValid(); Objects.requireNonNull(packageName, "packageName must not be null"); @@ -1620,7 +1623,7 @@ public class BlobStoreManagerService extends SystemService { + "callingUid=" + callingUid + ", callingPackage=" + packageName); } - return getLeaseInfoInternal(blobHandle, callingUid, packageName); + return getLeaseInfoInternal(blobHandle, callingUid, packageName, attributionTag); } @Override diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java index fe688828997e..2c3f682a46e0 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java @@ -15,6 +15,8 @@ */ package com.android.server.blob; +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR; import static android.app.blob.XmlTags.ATTR_CREATION_TIME_MS; import static android.app.blob.XmlTags.ATTR_ID; @@ -366,6 +368,21 @@ class BlobStoreSession extends IBlobStoreSession.Stub { } @Override + public void allowPackagesWithLocationPermission(@NonNull String permissionName) { + assertCallerIsOwner(); + Preconditions.checkArgument(ACCESS_FINE_LOCATION.equals(permissionName) + || ACCESS_COARSE_LOCATION.equals(permissionName), + "permissionName is unknown: " + permissionName); + synchronized (mSessionLock) { + if (mState != STATE_OPENED) { + throw new IllegalStateException("Not allowed to change access type in state: " + + stateToString(mState)); + } + mBlobAccessMode.allowPackagesWithLocationPermission(permissionName); + } + } + + @Override public boolean isPackageAccessAllowed(@NonNull String packageName, @NonNull byte[] certificate) { assertCallerIsOwner(); @@ -406,6 +423,21 @@ class BlobStoreSession extends IBlobStoreSession.Stub { } @Override + public boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName) { + assertCallerIsOwner(); + Preconditions.checkArgument(ACCESS_FINE_LOCATION.equals(permissionName) + || ACCESS_COARSE_LOCATION.equals(permissionName), + "permissionName is unknown: " + permissionName); + synchronized (mSessionLock) { + if (mState != STATE_OPENED) { + throw new IllegalStateException("Not allowed to change access type in state: " + + stateToString(mState)); + } + return mBlobAccessMode.arePackagesWithLocationPermissionAllowed(permissionName); + } + } + + @Override public void close() { closeSession(STATE_CLOSED, false /* sendCallback */); } |