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 com.android.internal.util.ArrayUtils; 27 28 import libcore.util.EmptyArray; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * Settings data for a particular shared user ID we know about. 35 */ 36 public final class SharedUserSetting extends SettingBase { 37 final String name; 38 39 int userId; 40 41 // flags that are associated with this uid, regardless of any package flags 42 int uidFlags; 43 int uidPrivateFlags; 44 45 // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so 46 // that all apps within the sharedUser run in the same selinux context. 47 int seInfoTargetSdkVersion; 48 49 final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>(); 50 51 final PackageSignatures signatures = new PackageSignatures(); 52 Boolean signaturesChanged; 53 SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags)54 SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) { 55 super(_pkgFlags, _pkgPrivateFlags); 56 uidFlags = _pkgFlags; 57 uidPrivateFlags = _pkgPrivateFlags; 58 name = _name; 59 seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 60 } 61 62 @Override toString()63 public String toString() { 64 return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " " 65 + name + "/" + userId + "}"; 66 } 67 writeToProto(ProtoOutputStream proto, long fieldId)68 public void writeToProto(ProtoOutputStream proto, long fieldId) { 69 long token = proto.start(fieldId); 70 proto.write(PackageServiceDumpProto.SharedUserProto.UID, userId); 71 proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name); 72 proto.end(token); 73 } 74 removePackage(PackageSetting packageSetting)75 boolean removePackage(PackageSetting packageSetting) { 76 if (!packages.remove(packageSetting)) { 77 return false; 78 } 79 // recalculate the pkgFlags for this shared user if needed 80 if ((this.pkgFlags & packageSetting.pkgFlags) != 0) { 81 int aggregatedFlags = uidFlags; 82 for (PackageSetting ps : packages) { 83 aggregatedFlags |= ps.pkgFlags; 84 } 85 setFlags(aggregatedFlags); 86 } 87 if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) { 88 int aggregatedPrivateFlags = uidPrivateFlags; 89 for (PackageSetting ps : packages) { 90 aggregatedPrivateFlags |= ps.pkgPrivateFlags; 91 } 92 setPrivateFlags(aggregatedPrivateFlags); 93 } 94 return true; 95 } 96 addPackage(PackageSetting packageSetting)97 void addPackage(PackageSetting packageSetting) { 98 // If this is the first package added to this shared user, temporarily (until next boot) use 99 // its targetSdkVersion when assigning seInfo for the shared user. 100 if ((packages.size() == 0) && (packageSetting.pkg != null)) { 101 seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion; 102 } 103 if (packages.add(packageSetting)) { 104 setFlags(this.pkgFlags | packageSetting.pkgFlags); 105 setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags); 106 } 107 } 108 getPackages()109 public @Nullable List<PackageParser.Package> getPackages() { 110 if (packages == null || packages.size() == 0) { 111 return null; 112 } 113 final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size()); 114 for (PackageSetting ps : packages) { 115 if ((ps == null) || (ps.pkg == null)) { 116 continue; 117 } 118 pkgList.add(ps.pkg); 119 } 120 return pkgList; 121 } 122 isPrivileged()123 public boolean isPrivileged() { 124 return (this.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; 125 } 126 127 /** 128 * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo 129 * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest 130 * targetSdkVersion of all apps within the shared user, which corresponds to the least 131 * restrictive selinux domain. 132 */ fixSeInfoLocked()133 public void fixSeInfoLocked() { 134 final List<PackageParser.Package> pkgList = getPackages(); 135 if (pkgList == null || pkgList.size() == 0) { 136 return; 137 } 138 139 for (PackageParser.Package pkg : pkgList) { 140 if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) { 141 seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion; 142 } 143 } 144 for (PackageParser.Package pkg : pkgList) { 145 final boolean isPrivileged = isPrivileged() | pkg.isPrivileged(); 146 pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged, 147 seInfoTargetSdkVersion); 148 } 149 } 150 151 /** Returns userIds which doesn't have any packages with this sharedUserId */ getNotInstalledUserIds()152 public int[] getNotInstalledUserIds() { 153 int[] excludedUserIds = null; 154 for (PackageSetting ps : packages) { 155 final int[] userIds = ps.getNotInstalledUserIds(); 156 if (excludedUserIds == null) { 157 excludedUserIds = userIds; 158 } else { 159 for (int userId : excludedUserIds) { 160 if (!ArrayUtils.contains(userIds, userId)) { 161 excludedUserIds = ArrayUtils.removeInt(excludedUserIds, userId); 162 } 163 } 164 } 165 } 166 return excludedUserIds == null ? EmptyArray.INT : excludedUserIds; 167 } 168 169 /** Updates all fields in this shared user setting from another. */ updateFrom(SharedUserSetting sharedUser)170 public SharedUserSetting updateFrom(SharedUserSetting sharedUser) { 171 copyFrom(sharedUser); 172 this.userId = sharedUser.userId; 173 this.uidFlags = sharedUser.uidFlags; 174 this.uidPrivateFlags = sharedUser.uidPrivateFlags; 175 this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion; 176 this.packages.clear(); 177 this.packages.addAll(sharedUser.packages); 178 this.signaturesChanged = sharedUser.signaturesChanged; 179 return this; 180 } 181 } 182