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