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

Commit bf73792c authored by Nate Myren's avatar Nate Myren
Browse files

Register AttributionSource binders in system server

This ensures the system server has a strong
reference to the binder, and won't let it get
garbage collected prematurely

Bug: 303614372
Test: atest CtsPermissionTestCases, manual
Change-Id: If5902b38f7b83de099cf04d6d066cef8fdcc3cf1
parent 922a3212
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ public final class AttributionSource implements Parcelable {
    }

    /** @hide */
    public AttributionSource withToken(@NonNull Binder token) {
    public AttributionSource withToken(@NonNull IBinder token) {
        return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
                token, mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
    }
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ interface IPermissionManager {

    boolean isAutoRevokeExempted(String packageName, int userId);

    void registerAttributionSource(in AttributionSourceState source);
    IBinder registerAttributionSource(in AttributionSourceState source);

    boolean isRegisteredAttributionSource(in AttributionSourceState source);

+11 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.os.Build.VERSION_CODES.S;
import static android.permission.flags.Flags.serverSideAttributionRegistration;

import android.Manifest;
import android.annotation.CheckResult;
@@ -59,6 +60,7 @@ import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
@@ -1464,13 +1466,19 @@ public final class PermissionManager {
        // We use a shared static token for sources that are not registered since the token's
        // only used for process death detection. If we are about to use the source for security
        // enforcement we need to replace the binder with a unique one.
        final AttributionSource registeredSource = source.withToken(new Binder());
        try {
            if (serverSideAttributionRegistration()) {
                IBinder newToken = mPermissionManager.registerAttributionSource(source.asState());
                return source.withToken(newToken);
            } else {
                AttributionSource registeredSource = source.withToken(new Binder());
                mPermissionManager.registerAttributionSource(registeredSource.asState());
                return registeredSource;
            }
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
        return registeredSource;
        return source;
    }

    /**
+7 −0
Original line number Diff line number Diff line
@@ -72,6 +72,13 @@ flag {
    bug: "274132354"
}

flag {
    name: "server_side_attribution_registration"
    namespace: "permissions"
    description: "controls whether the binder representing an AttributionSource is created in the system server, or client process"
    bug: "310953959"
}

flag {
    name: "wallet_role_enabled"
    namespace: "wallet_integration"
+23 −6
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_BLUETOOTH_CONNECT;
import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.permission.flags.Flags.serverSideAttributionRegistration;

import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;

@@ -439,10 +440,27 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        }
    }

    /**
     * Reference propagation over binder is affected by the ownership of the object. So if 
     * the token is owned by client, references to the token on client side won't be 
     * propagated to the server and the token may still be garbage collected on server side. 
     * But if the token is owned by server, references to the token on client side will now 
     * be propagated to the server since it's a foreign object to the client, and that will 
     * keep the token referenced on the server side as long as the client is alive and 
     * holding it.
     */
    @Override
    public void registerAttributionSource(@NonNull AttributionSourceState source) {
    public IBinder registerAttributionSource(@NonNull AttributionSourceState source) {
        if (serverSideAttributionRegistration()) {
            Binder token = new Binder();
            mAttributionSourceRegistry
                    .registerAttributionSource(new AttributionSource(source).withToken(token));
            return token;
        } else {
            mAttributionSourceRegistry
                    .registerAttributionSource(new AttributionSource(source));
            return source.token;
        }
    }

    @Override
@@ -1218,7 +1236,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                @Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
                boolean fromDatasource, int attributedOp) {
            PermissionInfo permissionInfo = sPlatformPermissions.get(permission);

            if (permissionInfo == null) {
                try {
                    permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0);
@@ -1346,8 +1363,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {

                // If the call is from a datasource we need to vet only the chain before it. This
                // way we can avoid the datasource creating an attribution context for every call.
                if (!(fromDatasource && current.equals(attributionSource))
                        && next != null && !current.isTrusted(context)) {
                boolean isDatasource = fromDatasource && current.equals(attributionSource);
                if (!isDatasource && next != null && !current.isTrusted(context)) {
                    return PermissionChecker.PERMISSION_HARD_DENIED;
                }