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