Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2011 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.pm;
     18 
     19 import android.annotation.Nullable;
     20 import android.content.pm.ApplicationInfo;
     21 import android.content.pm.PackageParser;
     22 import android.service.pm.PackageServiceDumpProto;
     23 import android.util.ArraySet;
     24 import android.util.proto.ProtoOutputStream;
     25 
     26 import java.util.ArrayList;
     27 import java.util.Collection;
     28 import java.util.List;
     29 
     30 /**
     31  * Settings data for a particular shared user ID we know about.
     32  */
     33 public final class SharedUserSetting extends SettingBase {
     34     final String name;
     35 
     36     int userId;
     37 
     38     // flags that are associated with this uid, regardless of any package flags
     39     int uidFlags;
     40     int uidPrivateFlags;
     41 
     42     // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
     43     // that all apps within the sharedUser run in the same selinux context.
     44     int seInfoTargetSdkVersion;
     45 
     46     final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
     47 
     48     final PackageSignatures signatures = new PackageSignatures();
     49     Boolean signaturesChanged;
     50 
     51     SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
     52         super(_pkgFlags, _pkgPrivateFlags);
     53         uidFlags =  _pkgFlags;
     54         uidPrivateFlags = _pkgPrivateFlags;
     55         name = _name;
     56         seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
     57     }
     58 
     59     @Override
     60     public String toString() {
     61         return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
     62                 + name + "/" + userId + "}";
     63     }
     64 
     65     public void writeToProto(ProtoOutputStream proto, long fieldId) {
     66         long token = proto.start(fieldId);
     67         proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, userId);
     68         proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
     69         proto.end(token);
     70     }
     71 
     72     void removePackage(PackageSetting packageSetting) {
     73         if (packages.remove(packageSetting)) {
     74             // recalculate the pkgFlags for this shared user if needed
     75             if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
     76                 int aggregatedFlags = uidFlags;
     77                 for (PackageSetting ps : packages) {
     78                     aggregatedFlags |= ps.pkgFlags;
     79                 }
     80                 setFlags(aggregatedFlags);
     81             }
     82             if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
     83                 int aggregatedPrivateFlags = uidPrivateFlags;
     84                 for (PackageSetting ps : packages) {
     85                     aggregatedPrivateFlags |= ps.pkgPrivateFlags;
     86                 }
     87                 setPrivateFlags(aggregatedPrivateFlags);
     88             }
     89         }
     90     }
     91 
     92     void addPackage(PackageSetting packageSetting) {
     93         // If this is the first package added to this shared user, temporarily (until next boot) use
     94         // its targetSdkVersion when assigning seInfo for the shared user.
     95         if ((packages.size() == 0) && (packageSetting.pkg != null)) {
     96             seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
     97         }
     98         if (packages.add(packageSetting)) {
     99             setFlags(this.pkgFlags | packageSetting.pkgFlags);
    100             setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
    101         }
    102     }
    103 
    104     public @Nullable List<PackageParser.Package> getPackages() {
    105         if (packages == null || packages.size() == 0) {
    106             return null;
    107         }
    108         final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
    109         for (PackageSetting ps : packages) {
    110             if ((ps == null) || (ps.pkg == null)) {
    111                 continue;
    112             }
    113             pkgList.add(ps.pkg);
    114         }
    115         return pkgList;
    116     }
    117 
    118     public boolean isPrivileged() {
    119         return (this.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
    120     }
    121 
    122     /**
    123      * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
    124      * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
    125      * targetSdkVersion of all apps within the shared user, which corresponds to the least
    126      * restrictive selinux domain.
    127      */
    128     public void fixSeInfoLocked() {
    129         final List<PackageParser.Package> pkgList = getPackages();
    130         if (pkgList == null || pkgList.size() == 0) {
    131             return;
    132         }
    133 
    134         for (PackageParser.Package pkg : pkgList) {
    135             if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
    136                 seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
    137             }
    138         }
    139         for (PackageParser.Package pkg : pkgList) {
    140             final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
    141             pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
    142                 pkg.applicationInfo.targetSandboxVersion, seInfoTargetSdkVersion);
    143         }
    144     }
    145 
    146 }
    147