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

Commit 8d2ed506 authored by Svet Ganov's avatar Svet Ganov
Browse files

Runtime permission attribution improvements

When an app is proxying access to runtime permission protected
data it needs to check whether the calling app has a permission
to the data it is about to proxy which leaves a trace in app ops
that the requesting app perofmed a data access. However, then the
app doing the work needs to get the protected data itself from the
OS which access gets attributed only to itself. As a result there
are two data accesses in app ops where only the first one is a
proxy one that app A got access to Foo through app B - that is the
one we want to show in the permission tracking UIs - and one
for the data access - that is the one we would want to blame on
the calling app, and in fact, these two accesses should be one -
that app A accessed Foo though B. This limitation requires fragile
one off workarounds where both accesses use the same attribution
tag and sys UI has hardcoded rules to dedupe. Since this is not
documented we cannot expect that the ecosystem would reliably
do this...
parent e3585e10
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.commands.content;
import android.app.ActivityManager;
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.content.AttributionSource;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.IContentProvider;
@@ -562,7 +563,8 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            provider.insert(resolveCallingPackage(), null, mUri, mContentValues, mExtras);
            provider.insert(new AttributionSource(Binder.getCallingUid(),
                    resolveCallingPackage(), null), mUri, mContentValues, mExtras);
        }
    }

@@ -576,7 +578,8 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            provider.delete(resolveCallingPackage(), null, mUri, mExtras);
            provider.delete(new AttributionSource(Binder.getCallingUid(),
                    resolveCallingPackage(), null), mUri, mExtras);
        }
    }

@@ -593,7 +596,8 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            Bundle result = provider.call(null, null, mUri.getAuthority(), mMethod, mArg, mExtras);
            Bundle result = provider.call(new AttributionSource(Binder.getCallingUid(),
                    resolveCallingPackage(), null), mUri.getAuthority(), mMethod, mArg, mExtras);
            if (result != null) {
                result.size(); // unpack
            }
@@ -620,7 +624,9 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            try (ParcelFileDescriptor fd = provider.openFile(null, null, mUri, "r", null, null)) {
            try (ParcelFileDescriptor fd = provider.openFile(
                    new AttributionSource(Binder.getCallingUid(),
                    resolveCallingPackage(), null), mUri, "r", null)) {
                FileUtils.copy(fd.getFileDescriptor(), FileDescriptor.out);
            }
        }
@@ -633,7 +639,8 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            try (ParcelFileDescriptor fd = provider.openFile(null, null, mUri, "w", null, null)) {
            try (ParcelFileDescriptor fd = provider.openFile(new AttributionSource(
                    Binder.getCallingUid(), resolveCallingPackage(), null), mUri, "w", null)) {
                FileUtils.copy(FileDescriptor.in, fd.getFileDescriptor());
            }
        }
@@ -651,8 +658,8 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
                    mExtras, null);
            Cursor cursor = provider.query(new AttributionSource(Binder.getCallingUid(),
                    resolveCallingPackage(), null), mUri, mProjection, mExtras, null);
            if (cursor == null) {
                System.out.println("No result found.");
                return;
@@ -716,7 +723,8 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            provider.update(resolveCallingPackage(), null, mUri, mValues, mExtras);
            provider.update(new AttributionSource(Binder.getCallingUid(),
                    resolveCallingPackage(), null), mUri, mValues, mExtras);
        }
    }

+18 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.app.UiAutomation;
import android.content.AttributionSource;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentProvider;
@@ -28,6 +29,7 @@ import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -67,7 +69,8 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge {
                    throw new IllegalStateException("Could not find provider: " + providerName);
                }
                provider = holder.provider;
                cursor = provider.query(null, null, Settings.Secure.CONTENT_URI,
                cursor = provider.query(new AttributionSource(Binder.getCallingUid(),
                        resolveCallingPackage(), null), Settings.Secure.CONTENT_URI,
                        new String[] {
                            Settings.Secure.VALUE
                        },
@@ -123,4 +126,18 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge {
        }
        return ret;
    }

    private static String resolveCallingPackage() {
        switch (Binder.getCallingUid()) {
            case Process.ROOT_UID: {
                return "root";
            }
            case Process.SHELL_UID: {
                return "com.android.shell";
            }
            default: {
                return null;
            }
        }
    }
}
+26 −3
Original line number Diff line number Diff line
@@ -9907,6 +9907,27 @@ package android.content {
    method @Deprecated public void setUpdateThrottle(long);
  }
  public final class AttributionSource implements android.os.Parcelable {
    method public boolean checkCallingUid();
    method public int describeContents();
    method public void enforceCallingUid();
    method @Nullable public String getAttributionTag();
    method @Nullable public android.content.AttributionSource getNext();
    method @Nullable public String getPackageName();
    method public int getUid();
    method public boolean isTrusted(@NonNull android.content.Context);
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.content.AttributionSource> CREATOR;
  }
  public static final class AttributionSource.Builder {
    ctor public AttributionSource.Builder(int);
    method @NonNull public android.content.AttributionSource build();
    method @NonNull public android.content.AttributionSource.Builder setAttributionTag(@NonNull String);
    method @NonNull public android.content.AttributionSource.Builder setNext(@NonNull android.content.AttributionSource);
    method @NonNull public android.content.AttributionSource.Builder setPackageName(@NonNull String);
  }
  public abstract class BroadcastReceiver {
    ctor public BroadcastReceiver();
    method public final void abortBroadcast();
@@ -10076,6 +10097,7 @@ package android.content {
    method public abstract int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]);
    method public int delete(@NonNull android.net.Uri, @Nullable android.os.Bundle);
    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
    method @Nullable public final android.content.AttributionSource getCallingAttributionSource();
    method @Nullable public final String getCallingAttributionTag();
    method @Nullable public final String getCallingPackage();
    method @Nullable public final String getCallingPackageUnchecked();
@@ -10438,6 +10460,7 @@ package android.content {
    method public abstract android.content.Context getApplicationContext();
    method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
    method public abstract android.content.res.AssetManager getAssets();
    method @NonNull public android.content.AttributionSource getAttributionSource();
    method @Nullable public String getAttributionTag();
    method public abstract java.io.File getCacheDir();
    method public abstract ClassLoader getClassLoader();
@@ -10643,8 +10666,7 @@ package android.content {
  public final class ContextParams {
    method @Nullable public String getAttributionTag();
    method @Nullable public String getReceiverAttributionTag();
    method @Nullable public String getReceiverPackage();
    method @Nullable public android.content.AttributionSource getNextAttributionSource();
  }
  public static final class ContextParams.Builder {
@@ -10652,7 +10674,7 @@ package android.content {
    ctor public ContextParams.Builder(@NonNull android.content.ContextParams);
    method @NonNull public android.content.ContextParams build();
    method @NonNull public android.content.ContextParams.Builder setAttributionTag(@Nullable String);
    method @NonNull public android.content.ContextParams.Builder setReceiverPackage(@Nullable String, @Nullable String);
    method @NonNull public android.content.ContextParams.Builder setNextAttributionSource(@NonNull android.content.AttributionSource);
  }
  public class ContextWrapper extends android.content.Context {
@@ -39082,6 +39104,7 @@ package android.speech {
    method public void bufferReceived(byte[]) throws android.os.RemoteException;
    method public void endOfSpeech() throws android.os.RemoteException;
    method public void error(int) throws android.os.RemoteException;
    method @NonNull public android.content.AttributionSource getCallingAttributionSource();
    method public int getCallingUid();
    method public void partialResults(android.os.Bundle) throws android.os.RemoteException;
    method public void readyForSpeech(android.os.Bundle) throws android.os.RemoteException;
+11 −3
Original line number Diff line number Diff line
@@ -596,7 +596,7 @@ package android.app {
  public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
    method public int describeContents();
    method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@NonNull String);
    method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@Nullable String);
    method @NonNull public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOpsAt(@IntRange(from=0) int);
    method @IntRange(from=0) public int getAttributedOpsCount();
    method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
@@ -2217,6 +2217,14 @@ package android.content {
    method @NonNull public java.io.File getDeviceProtectedDataDirForUser(@NonNull android.os.UserHandle);
  }
  public final class AttributionSource implements android.os.Parcelable {
    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public java.util.Set<java.lang.String> getRenouncedPermissions();
  }
  public static final class AttributionSource.Builder {
    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.AttributionSource.Builder setRenouncedPermissions(@NonNull java.util.Set<java.lang.String>);
  }
  public abstract class BroadcastReceiver {
    method @NonNull public final android.os.UserHandle getSendingUser();
  }
@@ -2291,11 +2299,11 @@ package android.content {
  }
  public final class ContextParams {
    method @Nullable @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public java.util.Set<java.lang.String> getRenouncedPermissions();
    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public java.util.Set<java.lang.String> getRenouncedPermissions();
  }
  public static final class ContextParams.Builder {
    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.ContextParams.Builder setRenouncedPermissions(@Nullable java.util.Set<java.lang.String>);
    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.ContextParams.Builder setRenouncedPermissions(@NonNull java.util.Set<java.lang.String>);
  }
  public class ContextWrapper extends android.content.Context {
+6 −0
Original line number Diff line number Diff line
@@ -220,6 +220,7 @@ package android.app {
    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void rebootHistory(long);
    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void reloadNonHistoricalState();
    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetHistoryParameters();
    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetPackageOpsNoHistory(@NonNull String);
    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int);
    method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(int, int, String, int);
    method public static int strOpToOp(@NonNull String);
@@ -654,6 +655,11 @@ package android.bluetooth {

package android.content {

  public final class AttributionSource implements android.os.Parcelable {
    ctor public AttributionSource(int, @Nullable String, @Nullable String);
    ctor public AttributionSource(int, @Nullable String, @Nullable String, @Nullable android.content.AttributionSource);
  }

  public final class AutofillOptions implements android.os.Parcelable {
    ctor public AutofillOptions(int, boolean);
    method public int describeContents();
Loading