Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.am;
     18 
     19 import android.app.GrantedUriPermission;
     20 import android.content.Intent;
     21 import android.os.Binder;
     22 import android.os.UserHandle;
     23 import android.util.ArraySet;
     24 import android.util.Log;
     25 import android.util.Slog;
     26 
     27 import com.android.server.am.ActivityManagerService.GrantUri;
     28 import com.google.android.collect.Sets;
     29 
     30 import java.io.PrintWriter;
     31 import java.util.Comparator;
     32 
     33 /**
     34  * Description of a permission granted to an app to access a particular URI.
     35  *
     36  * CTS tests for this functionality can be run with "runtest cts-appsecurity".
     37  *
     38  * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
     39  *      src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
     40  */
     41 final class UriPermission {
     42     private static final String TAG = "UriPermission";
     43 
     44     public static final int STRENGTH_NONE = 0;
     45     public static final int STRENGTH_OWNED = 1;
     46     public static final int STRENGTH_GLOBAL = 2;
     47     public static final int STRENGTH_PERSISTABLE = 3;
     48 
     49     final int targetUserId;
     50     final String sourcePkg;
     51     final String targetPkg;
     52 
     53     /** Cached UID of {@link #targetPkg}; should not be persisted */
     54     final int targetUid;
     55 
     56     final GrantUri uri;
     57 
     58     /**
     59      * Allowed modes. All permission enforcement should use this field. Must
     60      * always be a combination of {@link #ownedModeFlags},
     61      * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
     62      * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
     63      * the owning class.
     64      */
     65     int modeFlags = 0;
     66 
     67     /** Allowed modes with active owner. */
     68     int ownedModeFlags = 0;
     69     /** Allowed modes without explicit owner. */
     70     int globalModeFlags = 0;
     71     /** Allowed modes that have been offered for possible persisting. */
     72     int persistableModeFlags = 0;
     73 
     74     /** Allowed modes that should be persisted across device boots. */
     75     int persistedModeFlags = 0;
     76 
     77     /**
     78      * Timestamp when {@link #persistedModeFlags} was first defined in
     79      * {@link System#currentTimeMillis()} time base.
     80      */
     81     long persistedCreateTime = INVALID_TIME;
     82 
     83     private static final long INVALID_TIME = Long.MIN_VALUE;
     84 
     85     private ArraySet<UriPermissionOwner> mReadOwners;
     86     private ArraySet<UriPermissionOwner> mWriteOwners;
     87 
     88     private String stringName;
     89 
     90     UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
     91         this.targetUserId = UserHandle.getUserId(targetUid);
     92         this.sourcePkg = sourcePkg;
     93         this.targetPkg = targetPkg;
     94         this.targetUid = targetUid;
     95         this.uri = uri;
     96     }
     97 
     98     private void updateModeFlags() {
     99         final int oldModeFlags = modeFlags;
    100         modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
    101 
    102         if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
    103             Slog.d(TAG,
    104                     "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
    105                             + Integer.toHexString(oldModeFlags) + " to 0x"
    106                             + Integer.toHexString(modeFlags) + " via calling UID "
    107                             + Binder.getCallingUid() + " PID " + Binder.getCallingPid(),
    108                     new Throwable());
    109         }
    110     }
    111 
    112     /**
    113      * Initialize persisted modes as read from file. This doesn't issue any
    114      * global or owner grants.
    115      */
    116     void initPersistedModes(int modeFlags, long createdTime) {
    117         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    118                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    119 
    120         persistableModeFlags = modeFlags;
    121         persistedModeFlags = modeFlags;
    122         persistedCreateTime = createdTime;
    123 
    124         updateModeFlags();
    125     }
    126 
    127     void grantModes(int modeFlags, UriPermissionOwner owner) {
    128         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
    129         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    130                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    131 
    132         if (persistable) {
    133             persistableModeFlags |= modeFlags;
    134         }
    135 
    136         if (owner == null) {
    137             globalModeFlags |= modeFlags;
    138         } else {
    139             if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
    140                 addReadOwner(owner);
    141             }
    142             if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
    143                 addWriteOwner(owner);
    144             }
    145         }
    146 
    147         updateModeFlags();
    148     }
    149 
    150     /**
    151      * @return if mode changes should trigger persisting.
    152      */
    153     boolean takePersistableModes(int modeFlags) {
    154         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    155                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    156 
    157         if ((modeFlags & persistableModeFlags) != modeFlags) {
    158             Slog.w(TAG, "Requested flags 0x"
    159                     + Integer.toHexString(modeFlags) + ", but only 0x"
    160                     + Integer.toHexString(persistableModeFlags) + " are allowed");
    161             return false;
    162         }
    163 
    164         final int before = persistedModeFlags;
    165         persistedModeFlags |= (persistableModeFlags & modeFlags);
    166 
    167         if (persistedModeFlags != 0) {
    168             persistedCreateTime = System.currentTimeMillis();
    169         }
    170 
    171         updateModeFlags();
    172         return persistedModeFlags != before;
    173     }
    174 
    175     boolean releasePersistableModes(int modeFlags) {
    176         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    177                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    178 
    179         final int before = persistedModeFlags;
    180 
    181         persistableModeFlags &= ~modeFlags;
    182         persistedModeFlags &= ~modeFlags;
    183 
    184         if (persistedModeFlags == 0) {
    185             persistedCreateTime = INVALID_TIME;
    186         }
    187 
    188         updateModeFlags();
    189         return persistedModeFlags != before;
    190     }
    191 
    192     /**
    193      * @return if mode changes should trigger persisting.
    194      */
    195     boolean revokeModes(int modeFlags, boolean includingOwners) {
    196         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
    197         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    198                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    199 
    200         final int before = persistedModeFlags;
    201 
    202         if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
    203             if (persistable) {
    204                 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    205                 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    206             }
    207             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    208             if (mReadOwners != null && includingOwners) {
    209                 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    210                 for (UriPermissionOwner r : mReadOwners) {
    211                     r.removeReadPermission(this);
    212                 }
    213                 mReadOwners = null;
    214             }
    215         }
    216         if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
    217             if (persistable) {
    218                 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    219                 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    220             }
    221             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    222             if (mWriteOwners != null && includingOwners) {
    223                 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    224                 for (UriPermissionOwner r : mWriteOwners) {
    225                     r.removeWritePermission(this);
    226                 }
    227                 mWriteOwners = null;
    228             }
    229         }
    230 
    231         if (persistedModeFlags == 0) {
    232             persistedCreateTime = INVALID_TIME;
    233         }
    234 
    235         updateModeFlags();
    236         return persistedModeFlags != before;
    237     }
    238 
    239     /**
    240      * Return strength of this permission grant for the given flags.
    241      */
    242     public int getStrength(int modeFlags) {
    243         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    244                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    245         if ((persistableModeFlags & modeFlags) == modeFlags) {
    246             return STRENGTH_PERSISTABLE;
    247         } else if ((globalModeFlags & modeFlags) == modeFlags) {
    248             return STRENGTH_GLOBAL;
    249         } else if ((ownedModeFlags & modeFlags) == modeFlags) {
    250             return STRENGTH_OWNED;
    251         } else {
    252             return STRENGTH_NONE;
    253         }
    254     }
    255 
    256     private void addReadOwner(UriPermissionOwner owner) {
    257         if (mReadOwners == null) {
    258             mReadOwners = Sets.newArraySet();
    259             ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
    260             updateModeFlags();
    261         }
    262         if (mReadOwners.add(owner)) {
    263             owner.addReadPermission(this);
    264         }
    265     }
    266 
    267     /**
    268      * Remove given read owner, updating {@Link #modeFlags} as needed.
    269      */
    270     void removeReadOwner(UriPermissionOwner owner) {
    271         if (!mReadOwners.remove(owner)) {
    272             Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
    273         }
    274         if (mReadOwners.size() == 0) {
    275             mReadOwners = null;
    276             ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    277             updateModeFlags();
    278         }
    279     }
    280 
    281     private void addWriteOwner(UriPermissionOwner owner) {
    282         if (mWriteOwners == null) {
    283             mWriteOwners = Sets.newArraySet();
    284             ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    285             updateModeFlags();
    286         }
    287         if (mWriteOwners.add(owner)) {
    288             owner.addWritePermission(this);
    289         }
    290     }
    291 
    292     /**
    293      * Remove given write owner, updating {@Link #modeFlags} as needed.
    294      */
    295     void removeWriteOwner(UriPermissionOwner owner) {
    296         if (!mWriteOwners.remove(owner)) {
    297             Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
    298         }
    299         if (mWriteOwners.size() == 0) {
    300             mWriteOwners = null;
    301             ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    302             updateModeFlags();
    303         }
    304     }
    305 
    306     @Override
    307     public String toString() {
    308         if (stringName != null) {
    309             return stringName;
    310         }
    311         StringBuilder sb = new StringBuilder(128);
    312         sb.append("UriPermission{");
    313         sb.append(Integer.toHexString(System.identityHashCode(this)));
    314         sb.append(' ');
    315         sb.append(uri);
    316         sb.append('}');
    317         return stringName = sb.toString();
    318     }
    319 
    320     void dump(PrintWriter pw, String prefix) {
    321         pw.print(prefix);
    322         pw.print("targetUserId=" + targetUserId);
    323         pw.print(" sourcePkg=" + sourcePkg);
    324         pw.println(" targetPkg=" + targetPkg);
    325 
    326         pw.print(prefix);
    327         pw.print("mode=0x" + Integer.toHexString(modeFlags));
    328         pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
    329         pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
    330         pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
    331         pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
    332         if (persistedCreateTime != INVALID_TIME) {
    333             pw.print(" persistedCreate=" + persistedCreateTime);
    334         }
    335         pw.println();
    336 
    337         if (mReadOwners != null) {
    338             pw.print(prefix);
    339             pw.println("readOwners:");
    340             for (UriPermissionOwner owner : mReadOwners) {
    341                 pw.print(prefix);
    342                 pw.println("  * " + owner);
    343             }
    344         }
    345         if (mWriteOwners != null) {
    346             pw.print(prefix);
    347             pw.println("writeOwners:");
    348             for (UriPermissionOwner owner : mReadOwners) {
    349                 pw.print(prefix);
    350                 pw.println("  * " + owner);
    351             }
    352         }
    353     }
    354 
    355     public static class PersistedTimeComparator implements Comparator<UriPermission> {
    356         @Override
    357         public int compare(UriPermission lhs, UriPermission rhs) {
    358             return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
    359         }
    360     }
    361 
    362     /**
    363      * Snapshot of {@link UriPermission} with frozen
    364      * {@link UriPermission#persistedModeFlags} state.
    365      */
    366     public static class Snapshot {
    367         final int targetUserId;
    368         final String sourcePkg;
    369         final String targetPkg;
    370         final GrantUri uri;
    371         final int persistedModeFlags;
    372         final long persistedCreateTime;
    373 
    374         private Snapshot(UriPermission perm) {
    375             this.targetUserId = perm.targetUserId;
    376             this.sourcePkg = perm.sourcePkg;
    377             this.targetPkg = perm.targetPkg;
    378             this.uri = perm.uri;
    379             this.persistedModeFlags = perm.persistedModeFlags;
    380             this.persistedCreateTime = perm.persistedCreateTime;
    381         }
    382     }
    383 
    384     public Snapshot snapshot() {
    385         return new Snapshot(this);
    386     }
    387 
    388     public android.content.UriPermission buildPersistedPublicApiObject() {
    389         return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
    390     }
    391 
    392     public GrantedUriPermission buildGrantedUriPermission() {
    393         return new GrantedUriPermission(uri.uri, targetPkg);
    394     }
    395 }
    396