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         final int oldModeFlags = modeFlags;
     98         modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
     99 
    100         if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
    101             Slog.d(TAG,
    102                     "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
    103                             + Integer.toHexString(oldModeFlags) + " to 0x"
    104                             + Integer.toHexString(modeFlags),
    105                     new Throwable());
    106         }
    107     }
    108 
    109     /**
    110      * Initialize persisted modes as read from file. This doesn't issue any
    111      * global or owner grants.
    112      */
    113     void initPersistedModes(int modeFlags, long createdTime) {
    114         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    115                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    116 
    117         persistableModeFlags = modeFlags;
    118         persistedModeFlags = modeFlags;
    119         persistedCreateTime = createdTime;
    120 
    121         updateModeFlags();
    122     }
    123 
    124     void grantModes(int modeFlags, UriPermissionOwner owner) {
    125         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
    126         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    127                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    128 
    129         if (persistable) {
    130             persistableModeFlags |= modeFlags;
    131         }
    132 
    133         if (owner == null) {
    134             globalModeFlags |= modeFlags;
    135         } else {
    136             if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
    137                 addReadOwner(owner);
    138             }
    139             if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
    140                 addWriteOwner(owner);
    141             }
    142         }
    143 
    144         updateModeFlags();
    145     }
    146 
    147     /**
    148      * @return if mode changes should trigger persisting.
    149      */
    150     boolean takePersistableModes(int modeFlags) {
    151         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    152                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    153 
    154         if ((modeFlags & persistableModeFlags) != modeFlags) {
    155             Slog.w(TAG, "Requested flags 0x"
    156                     + Integer.toHexString(modeFlags) + ", but only 0x"
    157                     + Integer.toHexString(persistableModeFlags) + " are allowed");
    158             return false;
    159         }
    160 
    161         final int before = persistedModeFlags;
    162         persistedModeFlags |= (persistableModeFlags & modeFlags);
    163 
    164         if (persistedModeFlags != 0) {
    165             persistedCreateTime = System.currentTimeMillis();
    166         }
    167 
    168         updateModeFlags();
    169         return persistedModeFlags != before;
    170     }
    171 
    172     boolean releasePersistableModes(int modeFlags) {
    173         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    174                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    175 
    176         final int before = persistedModeFlags;
    177 
    178         persistableModeFlags &= ~modeFlags;
    179         persistedModeFlags &= ~modeFlags;
    180 
    181         if (persistedModeFlags == 0) {
    182             persistedCreateTime = INVALID_TIME;
    183         }
    184 
    185         updateModeFlags();
    186         return persistedModeFlags != before;
    187     }
    188 
    189     /**
    190      * @return if mode changes should trigger persisting.
    191      */
    192     boolean revokeModes(int modeFlags, boolean includingOwners) {
    193         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
    194         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    195                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    196 
    197         final int before = persistedModeFlags;
    198 
    199         if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
    200             if (persistable) {
    201                 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    202                 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    203             }
    204             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    205             if (mReadOwners != null && includingOwners) {
    206                 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    207                 for (UriPermissionOwner r : mReadOwners) {
    208                     r.removeReadPermission(this);
    209                 }
    210                 mReadOwners = null;
    211             }
    212         }
    213         if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
    214             if (persistable) {
    215                 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    216                 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    217             }
    218             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    219             if (mWriteOwners != null && includingOwners) {
    220                 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    221                 for (UriPermissionOwner r : mWriteOwners) {
    222                     r.removeWritePermission(this);
    223                 }
    224                 mWriteOwners = null;
    225             }
    226         }
    227 
    228         if (persistedModeFlags == 0) {
    229             persistedCreateTime = INVALID_TIME;
    230         }
    231 
    232         updateModeFlags();
    233         return persistedModeFlags != before;
    234     }
    235 
    236     /**
    237      * Return strength of this permission grant for the given flags.
    238      */
    239     public int getStrength(int modeFlags) {
    240         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
    241                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    242         if ((persistableModeFlags & modeFlags) == modeFlags) {
    243             return STRENGTH_PERSISTABLE;
    244         } else if ((globalModeFlags & modeFlags) == modeFlags) {
    245             return STRENGTH_GLOBAL;
    246         } else if ((ownedModeFlags & modeFlags) == modeFlags) {
    247             return STRENGTH_OWNED;
    248         } else {
    249             return STRENGTH_NONE;
    250         }
    251     }
    252 
    253     private void addReadOwner(UriPermissionOwner owner) {
    254         if (mReadOwners == null) {
    255             mReadOwners = Sets.newArraySet();
    256             ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
    257             updateModeFlags();
    258         }
    259         if (mReadOwners.add(owner)) {
    260             owner.addReadPermission(this);
    261         }
    262     }
    263 
    264     /**
    265      * Remove given read owner, updating {@Link #modeFlags} as needed.
    266      */
    267     void removeReadOwner(UriPermissionOwner owner) {
    268         if (!mReadOwners.remove(owner)) {
    269             Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
    270         }
    271         if (mReadOwners.size() == 0) {
    272             mReadOwners = null;
    273             ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
    274             updateModeFlags();
    275         }
    276     }
    277 
    278     private void addWriteOwner(UriPermissionOwner owner) {
    279         if (mWriteOwners == null) {
    280             mWriteOwners = Sets.newArraySet();
    281             ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    282             updateModeFlags();
    283         }
    284         if (mWriteOwners.add(owner)) {
    285             owner.addWritePermission(this);
    286         }
    287     }
    288 
    289     /**
    290      * Remove given write owner, updating {@Link #modeFlags} as needed.
    291      */
    292     void removeWriteOwner(UriPermissionOwner owner) {
    293         if (!mWriteOwners.remove(owner)) {
    294             Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
    295         }
    296         if (mWriteOwners.size() == 0) {
    297             mWriteOwners = null;
    298             ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    299             updateModeFlags();
    300         }
    301     }
    302 
    303     @Override
    304     public String toString() {
    305         if (stringName != null) {
    306             return stringName;
    307         }
    308         StringBuilder sb = new StringBuilder(128);
    309         sb.append("UriPermission{");
    310         sb.append(Integer.toHexString(System.identityHashCode(this)));
    311         sb.append(' ');
    312         sb.append(uri);
    313         sb.append('}');
    314         return stringName = sb.toString();
    315     }
    316 
    317     void dump(PrintWriter pw, String prefix) {
    318         pw.print(prefix);
    319         pw.print("targetUserId=" + targetUserId);
    320         pw.print(" sourcePkg=" + sourcePkg);
    321         pw.println(" targetPkg=" + targetPkg);
    322 
    323         pw.print(prefix);
    324         pw.print("mode=0x" + Integer.toHexString(modeFlags));
    325         pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
    326         pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
    327         pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
    328         pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
    329         if (persistedCreateTime != INVALID_TIME) {
    330             pw.print(" persistedCreate=" + persistedCreateTime);
    331         }
    332         pw.println();
    333 
    334         if (mReadOwners != null) {
    335             pw.print(prefix);
    336             pw.println("readOwners:");
    337             for (UriPermissionOwner owner : mReadOwners) {
    338                 pw.print(prefix);
    339                 pw.println("  * " + owner);
    340             }
    341         }
    342         if (mWriteOwners != null) {
    343             pw.print(prefix);
    344             pw.println("writeOwners:");
    345             for (UriPermissionOwner owner : mReadOwners) {
    346                 pw.print(prefix);
    347                 pw.println("  * " + owner);
    348             }
    349         }
    350     }
    351 
    352     public static class PersistedTimeComparator implements Comparator<UriPermission> {
    353         @Override
    354         public int compare(UriPermission lhs, UriPermission rhs) {
    355             return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
    356         }
    357     }
    358 
    359     /**
    360      * Snapshot of {@link UriPermission} with frozen
    361      * {@link UriPermission#persistedModeFlags} state.
    362      */
    363     public static class Snapshot {
    364         final int targetUserId;
    365         final String sourcePkg;
    366         final String targetPkg;
    367         final GrantUri uri;
    368         final int persistedModeFlags;
    369         final long persistedCreateTime;
    370 
    371         private Snapshot(UriPermission perm) {
    372             this.targetUserId = perm.targetUserId;
    373             this.sourcePkg = perm.sourcePkg;
    374             this.targetPkg = perm.targetPkg;
    375             this.uri = perm.uri;
    376             this.persistedModeFlags = perm.persistedModeFlags;
    377             this.persistedCreateTime = perm.persistedCreateTime;
    378         }
    379     }
    380 
    381     public Snapshot snapshot() {
    382         return new Snapshot(this);
    383     }
    384 
    385     public android.content.UriPermission buildPersistedPublicApiObject() {
    386         return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
    387     }
    388 }
    389