Merge "Store whether attribution tag is valid separate from bypass" into sc-dev

This commit is contained in:
Erik Wolsheimer
2021-06-13 03:19:41 +00:00
committed by Android (Google) Code Review
2 changed files with 81 additions and 58 deletions

View File

@@ -3105,24 +3105,11 @@ public class AppOpsManager {
*/
public boolean isRecordAudioRestrictionExcept;
/**
* Is attribution tag not null and not contained in the package attributions
*/
public boolean isAttributionTagNotFound = false;
public RestrictionBypass(boolean isPrivileged, boolean isRecordAudioRestrictionExcept) {
this.isPrivileged = isPrivileged;
this.isRecordAudioRestrictionExcept = isRecordAudioRestrictionExcept;
}
public void setIsAttributionTagNotFound(boolean isAttributionTagNotFound) {
this.isAttributionTagNotFound = isAttributionTagNotFound;
}
public boolean getIsAttributionTagNotFound() {
return this.isAttributionTagNotFound;
}
public static RestrictionBypass UNRESTRICTED = new RestrictionBypass(true, true);
}

View File

@@ -667,12 +667,30 @@ public class AppOpsService extends IAppOpsService.Stub {
/** Lazily populated cache of attributionTags of this package */
final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
/**
* Lazily populated cache of <b>valid</b> attributionTags of this package, a set smaller
* than or equal to {@link #knownAttributionTags}.
*/
final @NonNull ArraySet<String> validAttributionTags = new ArraySet<>();
Ops(String _packageName, UidState _uidState) {
packageName = _packageName;
uidState = _uidState;
}
}
/** Returned from {@link #verifyAndGetBypass(int, String, String, String, boolean)}. */
private static final class PackageVerificationResult {
final RestrictionBypass bypass;
final boolean isAttributionTagValid;
PackageVerificationResult(RestrictionBypass bypass, boolean isAttributionTagValid) {
this.bypass = bypass;
this.isAttributionTagValid = isAttributionTagValid;
}
}
/** A in progress startOp->finishOp event */
private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
/** Wall clock time of startOp event (not monotonic) */
@@ -2225,7 +2243,8 @@ public class AppOpsService extends IAppOpsService.Stub {
return Collections.emptyList();
}
synchronized (this) {
Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false /* edit */);
Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null,
/* edit */ false);
if (pkgOps == null) {
return null;
}
@@ -2387,7 +2406,7 @@ public class AppOpsService extends IAppOpsService.Stub {
op.removeAttributionsWithNoTime();
if (op.mAttributions.isEmpty()) {
Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */);
Ops ops = getOpsLocked(uid, packageName, null, false, null, /* edit */ false);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -2697,9 +2716,9 @@ public class AppOpsService extends IAppOpsService.Stub {
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
RestrictionBypass bypass;
PackageVerificationResult pvr;
try {
bypass = verifyAndGetBypass(uid, packageName, null);
pvr = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot setMode", e);
return;
@@ -2708,7 +2727,7 @@ public class AppOpsService extends IAppOpsService.Stub {
int previousMode = MODE_DEFAULT;
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
Op op = getOpLocked(code, uid, packageName, null, bypass, true);
Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ true);
if (op != null) {
if (op.mode != mode) {
previousMode = op.mode;
@@ -3148,9 +3167,9 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag, boolean raw) {
RestrictionBypass bypass;
PackageVerificationResult pvr;
try {
bypass = verifyAndGetBypass(uid, packageName, null);
pvr = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "checkOperation", e);
return AppOpsManager.opToDefaultMode(code);
@@ -3160,7 +3179,7 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
if (isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass)) {
if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -3170,7 +3189,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode);
}
Op op = getOpLocked(code, uid, packageName, null, bypass, false);
Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -3341,16 +3360,16 @@ public class AppOpsService extends IAppOpsService.Stub {
@Nullable String proxyAttributionTag, @OpFlags int flags,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
boolean shouldCollectMessage) {
RestrictionBypass bypass;
PackageVerificationResult pvr;
try {
boolean isLocOrActivity = code == AppOpsManager.OP_FINE_LOCATION
|| code == AppOpsManager.OP_FINE_LOCATION_SOURCE
|| code == AppOpsManager.OP_ACTIVITY_RECOGNITION
|| code == AppOpsManager.OP_ACTIVITY_RECOGNITION_SOURCE;
bypass = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName,
pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName,
isLocOrActivity);
boolean wasNull = attributionTag == null;
if (bypass != null && bypass.getIsAttributionTagNotFound()) {
if (!pvr.isAttributionTagValid) {
attributionTag = null;
}
if (attributionTag == null && isLocOrActivity
@@ -3365,8 +3384,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
synchronized (this) {
final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass,
true /* edit */);
final Ops ops = getOpsLocked(uid, packageName, attributionTag,
pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
@@ -3386,7 +3405,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final int switchCode = AppOpsManager.opToSwitch(code);
final UidState uidState = ops.uidState;
if (isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass)) {
if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
attributedOp.rejected(uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
@@ -3862,15 +3881,15 @@ public class AppOpsService extends IAppOpsService.Stub {
boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message,
boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
int attributionChainId, boolean dryRun) {
RestrictionBypass bypass;
PackageVerificationResult pvr;
try {
boolean isLocOrActivity = code == AppOpsManager.OP_FINE_LOCATION
|| code == AppOpsManager.OP_FINE_LOCATION_SOURCE
|| code == AppOpsManager.OP_ACTIVITY_RECOGNITION
|| code == AppOpsManager.OP_ACTIVITY_RECOGNITION_SOURCE;
bypass = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName,
pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName,
isLocOrActivity);
if (bypass != null && bypass.getIsAttributionTagNotFound()) {
if (!pvr.isAttributionTagValid) {
attributionTag = null;
}
if (attributionTag == null && isLocOrActivity
@@ -3886,7 +3905,8 @@ public class AppOpsService extends IAppOpsService.Stub {
boolean isRestricted = false;
synchronized (this) {
final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, true /* edit */);
final Ops ops = getOpsLocked(uid, packageName, attributionTag,
pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
if (ops == null) {
if (!dryRun) {
scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
@@ -3901,7 +3921,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
final UidState uidState = ops.uidState;
isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass);
isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass);
final int switchCode = AppOpsManager.opToSwitch(code);
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
@@ -4033,10 +4053,10 @@ public class AppOpsService extends IAppOpsService.Stub {
private void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
String attributionTag) {
RestrictionBypass bypass;
PackageVerificationResult pvr;
try {
bypass = verifyAndGetBypass(uid, packageName, attributionTag);
if (bypass != null && bypass.getIsAttributionTagNotFound()) {
pvr = verifyAndGetBypass(uid, packageName, attributionTag);
if (!pvr.isAttributionTagValid) {
attributionTag = null;
}
} catch (SecurityException e) {
@@ -4045,7 +4065,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
synchronized (this) {
Op op = getOpLocked(code, uid, packageName, attributionTag, bypass, true);
Op op = getOpLocked(code, uid, packageName, attributionTag, pvr.isAttributionTagValid,
pvr.bypass, /* edit */ true);
if (op == null) {
Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
+ attributionTag + ") op=" + AppOpsManager.opToName(code));
@@ -4427,32 +4448,35 @@ public class AppOpsService extends IAppOpsService.Stub {
}
/**
* @see verifyAndGetBypass(int, String, String, String)
* @see #verifyAndGetBypass(int, String, String, String, boolean)
*/
private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
@Nullable String attributionTag) {
return verifyAndGetBypass(uid, packageName, attributionTag, null, false);
}
/**
* Verify that package belongs to uid and return the {@link RestrictionBypass bypass
* description} for the package.
* description} for the package, along with a boolean indicating whether the attribution tag is
* valid.
*
* @param uid The uid the package belongs to
* @param packageName The package the might belong to the uid
* @param attributionTag attribution tag or {@code null} if no need to verify
* @param proxyPackageName The proxy package, from which the attribution tag is to be pulled
*
* @return {@code true} iff the package is privileged
* @return PackageVerificationResult containing {@link RestrictionBypass} and whether the
* attribution tag is valid
*/
private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
@Nullable String attributionTag, @Nullable String proxyPackageName, boolean extraLog) {
if (uid == Process.ROOT_UID) {
// For backwards compatibility, don't check package name for root UID.
return null;
return new PackageVerificationResult(null,
/* isAttributionTagValid */ true);
}
// Do not check if uid/packageName/attributionTag is already known
// Do not check if uid/packageName/attributionTag is already known.
synchronized (this) {
UidState uidState = mUidStates.get(uid);
if (uidState != null && uidState.pkgOps != null) {
@@ -4460,14 +4484,13 @@ public class AppOpsService extends IAppOpsService.Stub {
if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
attributionTag)) && ops.bypass != null) {
return ops.bypass;
return new PackageVerificationResult(ops.bypass,
ops.validAttributionTags.contains(attributionTag));
}
}
}
int callingUid = Binder.getCallingUid();
int userId = UserHandle.getUserId(uid);
RestrictionBypass bypass = null;
// Allow any attribution tag for resolvable uids
int pkgUid = resolveUid(packageName);
@@ -4479,12 +4502,16 @@ public class AppOpsService extends IAppOpsService.Stub {
throw new SecurityException("Specified package " + packageName + " under uid "
+ UserHandle.getAppId(uid) + otherUidMessage);
}
return RestrictionBypass.UNRESTRICTED;
return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED,
/* isAttributionTagValid */ true);
}
int userId = UserHandle.getUserId(uid);
RestrictionBypass bypass = null;
boolean isAttributionTagValid = false;
final long ident = Binder.clearCallingIdentity();
try {
boolean isAttributionTagValid = false;
PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
AndroidPackage pkg = pmInt.getPackage(packageName);
if (pkg != null) {
@@ -4509,15 +4536,15 @@ public class AppOpsService extends IAppOpsService.Stub {
if (!isAttributionTagValid) {
AndroidPackage proxyPkg = proxyPackageName != null
? pmInt.getPackage(proxyPackageName) : null;
boolean foundInProxy = isAttributionInPackage(proxyPkg, attributionTag);
// Re-check in proxy.
isAttributionTagValid = isAttributionInPackage(proxyPkg, attributionTag);
String msg;
if (pkg != null && foundInProxy) {
if (pkg != null && isAttributionTagValid) {
msg = "attributionTag " + attributionTag + " declared in manifest of the proxy"
+ " package " + proxyPackageName + ", this is not advised";
} else if (pkg != null) {
msg = "attributionTag " + attributionTag + " not declared in manifest of "
+ packageName;
bypass.setIsAttributionTagNotFound(true);
} else {
msg = "package " + packageName + " not found, can't check for "
+ "attributionTag " + attributionTag;
@@ -4528,7 +4555,7 @@ public class AppOpsService extends IAppOpsService.Stub {
SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, packageName,
userId) && mPlatformCompat.isChangeEnabledByUid(
SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE,
callingUid) && !foundInProxy) {
callingUid) && !isAttributionTagValid) {
Slog.e(TAG, msg);
} else {
Slog.e(TAG, msg);
@@ -4546,7 +4573,7 @@ public class AppOpsService extends IAppOpsService.Stub {
+ otherUidMessage);
}
return bypass;
return new PackageVerificationResult(bypass, isAttributionTagValid);
}
private boolean isAttributionInPackage(@Nullable AndroidPackage pkg,
@@ -4574,13 +4601,14 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param uid The uid the package belongs to
* @param packageName The name of the package
* @param attributionTag attribution tag
* @param isAttributionTagValid whether the given attribution tag is valid
* @param bypass When to bypass certain op restrictions (can be null if edit == false)
* @param edit If an ops does not exist, create the ops?
* @return The ops
*/
private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
@Nullable RestrictionBypass bypass, boolean edit) {
boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -4609,6 +4637,11 @@ public class AppOpsService extends IAppOpsService.Stub {
if (attributionTag != null) {
ops.knownAttributionTags.add(attributionTag);
if (isAttributionTagValid) {
ops.validAttributionTags.add(attributionTag);
} else {
ops.validAttributionTags.remove(attributionTag);
}
}
}
@@ -4638,14 +4671,17 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
* @param attributionTag The attribution tag
* @param isAttributionTagValid Whether the given attribution tag is valid
* @param bypass When to bypass certain op restrictions (can be null if edit == false)
* @param edit Iff {@code true} create the {@link Op} object if not yet created
*
* @return The {@link Op state} of the op
*/
private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) {
Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit);
@Nullable String attributionTag, boolean isAttributionTagValid,
@Nullable RestrictionBypass bypass, boolean edit) {
Ops ops = getOpsLocked(uid, packageName, attributionTag, isAttributionTagValid, bypass,
edit);
if (ops == null) {
return null;
}
@@ -6510,7 +6546,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
// TODO moltmann: Allow to check for attribution op activeness
synchronized (AppOpsService.this) {
Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false);
Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null, false);
if (pkgOps == null) {
return false;
}