diff options
Diffstat (limited to 'services/java/com/android/server')
9 files changed, 552 insertions, 64 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index a45c0ff..2a3c87e 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -63,6 +63,7 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; @@ -746,6 +747,9 @@ class BackupManagerService extends IBackupManager.Stub { // correct directory. mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup"); mBaseStateDir.mkdirs(); + if (!SELinux.restorecon(mBaseStateDir)) { + Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir); + } mDataDir = Environment.getDownloadCacheDirectory(); mPasswordHashFile = new File(mBaseStateDir, "pwhash"); @@ -2136,6 +2140,10 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE); + if (!SELinux.restorecon(mBackupDataName)) { + Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName); + } + mNewState = ParcelFileDescriptor.open(mNewStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE | @@ -4697,6 +4705,10 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE); + if (!SELinux.restorecon(mBackupDataName)) { + Slog.e(TAG, "SElinux restorecon failed for " + mBackupDataName); + } + if (mTransport.getRestoreData(mBackupData) != BackupConstants.TRANSPORT_OK) { // Transport-level failure, so we wind everything up and // terminate the restore operation. diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 18b4ec1..d3e7c24 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -41,10 +41,14 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -62,6 +66,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.util.AtomicFile; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; @@ -88,10 +93,11 @@ import java.util.Set; * Implementation of the device policy APIs. */ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { - private static final String DEVICE_POLICIES_XML = "device_policies.xml"; private static final String TAG = "DevicePolicyManagerService"; + private static final String DEVICE_POLICIES_XML = "device_policies.xml"; + private static final int REQUEST_EXPIRE_PASSWORD = 5571; private static final long MS_PER_DAY = 86400 * 1000; @@ -109,6 +115,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { IPowerManager mIPowerManager; IWindowManager mIWindowManager; + private DeviceOwner mDeviceOwner; + public static class DevicePolicyData { int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; int mActivePasswordLength = 0; @@ -507,6 +515,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addDataScheme("package"); context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); } @@ -545,6 +554,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + void loadDeviceOwner() { + synchronized (this) { + if (DeviceOwner.isRegistered()) { + mDeviceOwner = new DeviceOwner(); + } + } + } + /** * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration * reminders. Clears alarm if no expirations are configured. @@ -709,7 +726,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Intent resolveIntent = new Intent(); resolveIntent.setComponent(adminName); List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, PackageManager.GET_META_DATA, userHandle); + resolveIntent, + PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, + userHandle); if (infos == null || infos.size() <= 0) { throw new IllegalArgumentException("Unknown admin: " + adminName); } @@ -994,6 +1013,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void systemReady() { synchronized (this) { loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER); + loadDeviceOwner(); } } @@ -1052,6 +1072,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (replaceIndex == -1) { policy.mAdminList.add(newAdmin); + enableIfNecessary(info.getPackageName(), userHandle); } else { policy.mAdminList.set(replaceIndex, newAdmin); } @@ -1119,6 +1140,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } if (admin.getUid() != Binder.getCallingUid()) { + // If trying to remove device owner, refuse when the caller is not the owner. + if (mDeviceOwner != null + && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) { + return; + } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); } @@ -2351,6 +2377,49 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public boolean setDeviceOwner(String packageName) { + if (packageName == null + || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) { + throw new IllegalArgumentException("Invalid package name " + packageName + + " for device owner"); + } + synchronized (this) { + if (mDeviceOwner == null && !isDeviceProvisioned()) { + mDeviceOwner = new DeviceOwner(packageName); + mDeviceOwner.writeOwnerFile(); + return true; + } else { + throw new IllegalStateException("Trying to set device owner to " + packageName + + ", owner=" + mDeviceOwner.getPackageName() + + ", device_provisioned=" + isDeviceProvisioned()); + } + } + } + + @Override + public boolean isDeviceOwner(String packageName) { + synchronized (this) { + return mDeviceOwner != null + && mDeviceOwner.getPackageName().equals(packageName); + } + } + + @Override + public String getDeviceOwner() { + synchronized (this) { + if (mDeviceOwner != null) { + return mDeviceOwner.getPackageName(); + } + } + return null; + } + + private boolean isDeviceProvisioned() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0) > 0; + } + private void enforceCrossUserPermission(int userHandle) { if (userHandle < 0) { throw new IllegalArgumentException("Invalid userId " + userHandle); @@ -2364,6 +2433,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void enableIfNecessary(String packageName, int userId) { + try { + IPackageManager ipm = AppGlobals.getPackageManager(); + ApplicationInfo ai = ipm.getApplicationInfo(packageName, + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, + userId); + if (ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { + ipm.setApplicationEnabledSetting(packageName, + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP, userId); + } + } catch (RemoteException e) { + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -2399,4 +2484,92 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } + + static class DeviceOwner { + private static final String DEVICE_OWNER_XML = "device_owner.xml"; + private static final String TAG_DEVICE_OWNER = "device-owner"; + private static final String ATTR_PACKAGE = "package"; + private String mPackageName; + + DeviceOwner() { + readOwnerFile(); + } + + DeviceOwner(String packageName) { + this.mPackageName = packageName; + } + + static boolean isRegistered() { + return new File(Environment.getSystemSecureDirectory(), + DEVICE_OWNER_XML).exists(); + } + + String getPackageName() { + return mPackageName; + } + + static boolean isInstalled(String packageName, PackageManager pm) { + try { + PackageInfo pi; + if ((pi = pm.getPackageInfo(packageName, 0)) != null) { + if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + return true; + } + } + } catch (NameNotFoundException nnfe) { + Slog.w(TAG, "Device Owner package " + packageName + " not installed."); + } + return false; + } + + void readOwnerFile() { + AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(), + DEVICE_OWNER_XML)); + try { + FileInputStream input = file.openRead(); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(input, null); + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + String tag = parser.getName(); + if (!TAG_DEVICE_OWNER.equals(tag)) { + throw new XmlPullParserException( + "Device Owner file does not start with device-owner tag: found " + tag); + } + mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE); + input.close(); + } catch (XmlPullParserException xppe) { + Slog.e(TAG, "Error parsing device-owner file\n" + xppe); + } catch (IOException ioe) { + Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe); + } + } + + void writeOwnerFile() { + synchronized (this) { + writeOwnerFileLocked(); + } + } + + private void writeOwnerFileLocked() { + AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(), + DEVICE_OWNER_XML)); + try { + FileOutputStream output = file.startWrite(); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(output, "utf-8"); + out.startDocument(null, true); + out.startTag(null, TAG_DEVICE_OWNER); + out.attribute(null, ATTR_PACKAGE, mPackageName); + out.endTag(null, TAG_DEVICE_OWNER); + out.endDocument(); + out.flush(); + file.finishWrite(output); + } catch (IOException ioe) { + Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe); + } + } + } } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index c6aca2f..e8d7882 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -1603,7 +1603,7 @@ class MountService extends IMountService.Stub boolean mounted = false; try { mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath())); - } catch (IllegalStateException e) { + } catch (IllegalArgumentException e) { } if (!mounted) { diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java index 09daf56..c4b98ad 100644 --- a/services/java/com/android/server/accounts/AccountManagerService.java +++ b/services/java/com/android/server/accounts/AccountManagerService.java @@ -1425,9 +1425,9 @@ public class AccountManagerService if (accountType == null) throw new IllegalArgumentException("accountType is null"); checkManageAccountsPermission(); - // Is user allowed to modify accounts? - if (!getUserManager().getUserRestrictions(Binder.getCallingUserHandle()) - .getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) { + // Is user disallowed from modifying accounts? + if (getUserManager().getUserRestrictions(Binder.getCallingUserHandle()) + .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { try { response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED, "User is not allowed to add an account!"); @@ -2572,7 +2572,7 @@ public class AccountManagerService if (callingUid != android.os.Process.myUid()) { Bundle restrictions = getUserManager().getUserRestrictions( new UserHandle(UserHandle.getUserId(callingUid))); - if (!restrictions.getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) { + if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { return false; } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 6f092bf..04ffbd9 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2194,7 +2194,7 @@ public final class ActivityManagerService extends ActivityManagerNative // the PID of the new process, or else throw a RuntimeException. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, mountExternal, - app.info.targetSdkVersion, null, null); + app.info.targetSdkVersion, app.info.seinfo, null); BatteryStatsImpl bs = app.batteryStats.getBatteryStats(); synchronized (bs) { diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java index 02a2c1b..d9c85bf 100644 --- a/services/java/com/android/server/pm/Installer.java +++ b/services/java/com/android/server/pm/Installer.java @@ -188,7 +188,7 @@ public final class Installer { } } - public int install(String name, int uid, int gid) { + public int install(String name, int uid, int gid, String seinfo) { StringBuilder builder = new StringBuilder("install"); builder.append(' '); builder.append(name); @@ -196,6 +196,8 @@ public final class Installer { builder.append(uid); builder.append(' '); builder.append(gid); + builder.append(' '); + builder.append(seinfo != null ? seinfo : "!"); return execute(builder.toString()); } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 09d1426..afdd294 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -362,6 +362,9 @@ public class PackageManagerService extends IPackageManager.Stub { final HashMap<String, FeatureInfo> mAvailableFeatures = new HashMap<String, FeatureInfo>(); + // If mac_permissions.xml was found for seinfo labeling. + boolean mFoundPolicyFile; + // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = new ActivityIntentResolver(); @@ -1029,8 +1032,11 @@ public class PackageManagerService extends IPackageManager.Stub { readPermissions(); + mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); + mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore); + long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, @@ -2236,6 +2242,34 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private static void checkGrantRevokePermissions(PackageParser.Package pkg, BasePermission bp) { + int index = pkg.requestedPermissions.indexOf(bp.name); + if (index == -1) { + throw new SecurityException("Package " + pkg.packageName + + " has not requested permission " + bp.name); + } + boolean isNormal = + ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) + == PermissionInfo.PROTECTION_NORMAL); + boolean isDangerous = + ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) + == PermissionInfo.PROTECTION_DANGEROUS); + boolean isDevelopment = + ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0); + + if (!isNormal && !isDangerous && !isDevelopment) { + throw new SecurityException("Permission " + bp.name + + " is not a changeable permission type"); + } + + if (isNormal || isDangerous) { + if (pkg.requestedPermissionsRequired.get(index)) { + throw new SecurityException("Can't change " + bp.name + + ". It is required by the application"); + } + } + } + public void grantPermission(String packageName, String permissionName) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null); @@ -2246,21 +2280,16 @@ public class PackageManagerService extends IPackageManager.Stub { } final BasePermission bp = mSettings.mPermissions.get(permissionName); if (bp == null) { - throw new IllegalArgumentException("Unknown permission: " + packageName); - } - if (!pkg.requestedPermissions.contains(permissionName)) { - throw new SecurityException("Package " + packageName - + " has not requested permission " + permissionName); - } - if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) { - throw new SecurityException("Permission " + permissionName - + " is not a development permission"); + throw new IllegalArgumentException("Unknown permission: " + permissionName); } + + checkGrantRevokePermissions(pkg, bp); + final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps; if (gp.grantedPermissions.add(permissionName)) { if (ps.haveGids) { gp.gids = appendInts(gp.gids, bp.gids); @@ -2282,21 +2311,16 @@ public class PackageManagerService extends IPackageManager.Stub { } final BasePermission bp = mSettings.mPermissions.get(permissionName); if (bp == null) { - throw new IllegalArgumentException("Unknown permission: " + packageName); - } - if (!pkg.requestedPermissions.contains(permissionName)) { - throw new SecurityException("Package " + packageName - + " has not requested permission " + permissionName); - } - if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) { - throw new SecurityException("Permission " + permissionName - + " is not a development permission"); + throw new IllegalArgumentException("Unknown permission: " + permissionName); } + + checkGrantRevokePermissions(pkg, bp); + final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps; if (gp.grantedPermissions.remove(permissionName)) { gp.grantedPermissions.remove(permissionName); if (ps.haveGids) { @@ -3676,9 +3700,9 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private int createDataDirsLI(String packageName, int uid) { + private int createDataDirsLI(String packageName, int uid, String seinfo) { int[] users = sUserManager.getUserIds(); - int res = mInstaller.install(packageName, uid, uid); + int res = mInstaller.install(packageName, uid, uid, seinfo); if (res < 0) { return res; } @@ -4020,6 +4044,10 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } + if (mFoundPolicyFile) { + SELinuxMMAC.assignSeinfoValue(pkg); + } + pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting; @@ -4158,7 +4186,8 @@ public class PackageManagerService extends IPackageManager.Stub { recovered = true; // And now re-install the app. - ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid); + ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid, + pkg.applicationInfo.seinfo); if (ret == -1) { // Ack should not happen! msg = prefix + pkg.packageName @@ -4204,7 +4233,8 @@ public class PackageManagerService extends IPackageManager.Stub { Log.v(TAG, "Want this data dir: " + dataPath); } //invoke installer to do the actual installation - int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid); + int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid, + pkg.applicationInfo.seinfo); if (ret < 0) { // Error from installer mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; @@ -5915,7 +5945,7 @@ public class PackageManagerService extends IPackageManager.Stub { null); final int uid = Binder.getCallingUid(); - if (!isUserAllowed(UserHandle.getUserId(uid), UserManager.ALLOW_INSTALL_APPS)) { + if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) { try { observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED); } catch (RemoteException re) { @@ -5963,7 +5993,7 @@ public class PackageManagerService extends IPackageManager.Stub { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "installExistingPackage for user " + userId); } - if (!isUserAllowed(userId, UserManager.ALLOW_INSTALL_APPS)) { + if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { return PackageManager.INSTALL_FAILED_USER_RESTRICTED; } @@ -5997,13 +6027,13 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.INSTALL_SUCCEEDED; } - private boolean isUserAllowed(int userId, String restrictionKey) { + private boolean isUserRestricted(int userId, String restrictionKey) { Bundle restrictions = sUserManager.getUserRestrictions(userId); - if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) { - Log.w(TAG, "User does not have permission to: " + restrictionKey); - return false; + if (restrictions.getBoolean(restrictionKey, false)) { + Log.w(TAG, "User is restricted: " + restrictionKey); + return true; } - return true; + return false; } @Override @@ -8400,7 +8430,7 @@ public class PackageManagerService extends IPackageManager.Stub { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "deletePackage for user " + userId); } - if (!isUserAllowed(userId, UserManager.ALLOW_UNINSTALL_APPS)) { + if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) { try { observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED); } catch (RemoteException re) { @@ -8446,7 +8476,8 @@ public class PackageManagerService extends IPackageManager.Stub { IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface( ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); try { - if (dpm != null && dpm.packageHasActiveAdmins(packageName, userId)) { + if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId) + || dpm.isDeviceOwner(packageName))) { Slog.w(TAG, "Not removing package " + packageName + ": has active device admin"); return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER; } diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java new file mode 100644 index 0000000..15d2a5a --- /dev/null +++ b/services/java/com/android/server/pm/SELinuxMMAC.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageParser; +import android.content.pm.Signature; +import android.os.Environment; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.util.XmlUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +import java.util.HashMap; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +/** + * Centralized access to SELinux MMAC (middleware MAC) implementation. + * {@hide} + */ +public final class SELinuxMMAC { + + private static final String TAG = "SELinuxMMAC"; + + private static final boolean DEBUG_POLICY = false; + private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false; + + // Signature seinfo values read from policy. + private static final HashMap<Signature, String> sSigSeinfo = + new HashMap<Signature, String>(); + + // Package name seinfo values read from policy. + private static final HashMap<String, String> sPackageSeinfo = + new HashMap<String, String>(); + + // Locations of potential install policy files. + private static final File[] INSTALL_POLICY_FILE = { + new File(Environment.getDataDirectory(), "system/mac_permissions.xml"), + new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"), + null}; + + private static void flushInstallPolicy() { + sSigSeinfo.clear(); + sPackageSeinfo.clear(); + } + + /** + * Parses an MMAC install policy from a predefined list of locations. + * @param none + * @return boolean indicating whether an install policy was correctly parsed. + */ + public static boolean readInstallPolicy() { + + return readInstallPolicy(INSTALL_POLICY_FILE); + } + + /** + * Parses an MMAC install policy given as an argument. + * @param File object representing the path of the policy. + * @return boolean indicating whether the install policy was correctly parsed. + */ + public static boolean readInstallPolicy(File policyFile) { + + return readInstallPolicy(new File[]{policyFile,null}); + } + + private static boolean readInstallPolicy(File[] policyFiles) { + + FileReader policyFile = null; + int i = 0; + while (policyFile == null && policyFiles != null && policyFiles[i] != null) { + try { + policyFile = new FileReader(policyFiles[i]); + break; + } catch (FileNotFoundException e) { + Slog.d(TAG,"Couldn't find install policy " + policyFiles[i].getPath()); + } + i++; + } + + if (policyFile == null) { + Slog.d(TAG, "No policy file found. All seinfo values will be null."); + return false; + } + + Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath()); + + flushInstallPolicy(); + + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(policyFile); + + XmlUtils.beginDocument(parser, "policy"); + while (true) { + XmlUtils.nextElement(parser); + if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { + break; + } + + String tagName = parser.getName(); + if ("signer".equals(tagName)) { + String cert = parser.getAttributeValue(null, "signature"); + if (cert == null) { + Slog.w(TAG, "<signer> without signature at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + Signature signature; + try { + signature = new Signature(cert); + } catch (IllegalArgumentException e) { + Slog.w(TAG, "<signer> with bad signature at " + + parser.getPositionDescription(), e); + XmlUtils.skipCurrentTag(parser); + continue; + } + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo=" + + seinfo); + + sSigSeinfo.put(signature, seinfo); + } + } else if ("default".equals(tagName)) { + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo); + + // The 'null' signature is the default seinfo value + sSigSeinfo.put(null, seinfo); + } + } else if ("package".equals(tagName)) { + String pkgName = parser.getAttributeValue(null, "name"); + if (pkgName == null) { + Slog.w(TAG, "<package> without name at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<package> tag: (" + pkgName + + ") assigned seinfo=" + seinfo); + + sPackageSeinfo.put(pkgName, seinfo); + } + } else { + XmlUtils.skipCurrentTag(parser); + continue; + } + } + } catch (XmlPullParserException e) { + Slog.w(TAG, "Got execption parsing ", e); + } catch (IOException e) { + Slog.w(TAG, "Got execption parsing ", e); + } + try { + policyFile.close(); + } catch (IOException e) { + //omit + } + return true; + } + + private static String readSeinfoTag(XmlPullParser parser) throws + IOException, XmlPullParserException { + + int type; + int outerDepth = parser.getDepth(); + String seinfo = null; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if ("seinfo".equals(tagName)) { + String seinfoValue = parser.getAttributeValue(null, "value"); + if (seinfoValue != null) { + seinfo = seinfoValue; + } else { + Slog.w(TAG, "<seinfo> without value at " + + parser.getPositionDescription()); + } + } + XmlUtils.skipCurrentTag(parser); + } + return seinfo; + } + + /** + * Labels a package based on an seinfo tag from install policy. + * The label is attached to the ApplicationInfo instance of the package. + * @param PackageParser.Package object representing the package + * to labeled. + * @return String holding the value of the seinfo label that was assigned. + * Value may be null which indicates no seinfo label was assigned. + */ + public static void assignSeinfoValue(PackageParser.Package pkg) { + + /* + * Non system installed apps should be treated the same. This + * means that any post-loaded apk will be assigned the default + * tag, if one exists in the policy, else null, without respect + * to the signing key. + */ + if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) || + ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) { + + // We just want one of the signatures to match. + for (Signature s : pkg.mSignatures) { + if (s == null) + continue; + + if (sSigSeinfo.containsKey(s)) { + String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + seinfo); + + return; + } + } + + // Check for seinfo labeled by package. + if (sPackageSeinfo.containsKey(pkg.packageName)) { + String seinfo = pkg.applicationInfo.seinfo = sPackageSeinfo.get(pkg.packageName); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + seinfo); + return; + } + } + + // If we have a default seinfo value then great, otherwise + // we set a null object and that is what we started with. + String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + (seinfo == null ? "null" : seinfo)); + } +} diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index 636b0e5..fecc2df 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -226,6 +226,13 @@ public class UserManagerService extends IUserManager.Stub { } } + @Override + public boolean isRestricted() { + synchronized (mPackagesLock) { + return getUserInfoLocked(UserHandle.getCallingUserId()).isRestricted(); + } + } + /* * Should be locked on mUsers before calling this. */ @@ -558,7 +565,6 @@ public class UserManagerService extends IUserManager.Stub { mNextSerialNumber = MIN_USER_ID; Bundle restrictions = new Bundle(); - initRestrictionsToDefaults(restrictions); mUserRestrictions.append(UserHandle.USER_OWNER, restrictions); updateUserIdsLocked(); @@ -608,11 +614,11 @@ public class UserManagerService extends IUserManager.Stub { Bundle restrictions = mUserRestrictions.get(userInfo.id); if (restrictions != null) { serializer.startTag(null, TAG_RESTRICTIONS); - writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_WIFI); - writeBoolean(serializer, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS); - writeBoolean(serializer, restrictions, UserManager.ALLOW_INSTALL_APPS); - writeBoolean(serializer, restrictions, UserManager.ALLOW_UNINSTALL_APPS); - writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_LOCATION_ACCESS); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_WIFI); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_INSTALL_APPS); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNINSTALL_APPS); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_SHARE_LOCATION); serializer.endTag(null, TAG_RESTRICTIONS); } serializer.endTag(null, TAG_USER); @@ -676,7 +682,6 @@ public class UserManagerService extends IUserManager.Stub { long lastLoggedInTime = 0L; boolean partial = false; Bundle restrictions = new Bundle(); - initRestrictionsToDefaults(restrictions); FileInputStream fis = null; try { @@ -725,11 +730,11 @@ public class UserManagerService extends IUserManager.Stub { name = parser.getText(); } } else if (TAG_RESTRICTIONS.equals(tag)) { - readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_WIFI); - readBoolean(parser, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS); - readBoolean(parser, restrictions, UserManager.ALLOW_INSTALL_APPS); - readBoolean(parser, restrictions, UserManager.ALLOW_UNINSTALL_APPS); - readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_LOCATION_ACCESS); + readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_WIFI); + readBoolean(parser, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS); + readBoolean(parser, restrictions, UserManager.DISALLOW_INSTALL_APPS); + readBoolean(parser, restrictions, UserManager.DISALLOW_UNINSTALL_APPS); + readBoolean(parser, restrictions, UserManager.DISALLOW_SHARE_LOCATION); } } } @@ -758,7 +763,9 @@ public class UserManagerService extends IUserManager.Stub { private void readBoolean(XmlPullParser parser, Bundle restrictions, String restrictionKey) { String value = parser.getAttributeValue(null, restrictionKey); - restrictions.putBoolean(restrictionKey, value == null ? true : Boolean.parseBoolean(value)); + if (value != null) { + restrictions.putBoolean(restrictionKey, Boolean.parseBoolean(value)); + } } private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey) @@ -769,14 +776,6 @@ public class UserManagerService extends IUserManager.Stub { } } - private void initRestrictionsToDefaults(Bundle restrictions) { - restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true); - restrictions.putBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS, true); - restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, true); - restrictions.putBoolean(UserManager.ALLOW_UNINSTALL_APPS, true); - restrictions.putBoolean(UserManager.ALLOW_CONFIG_LOCATION_ACCESS, true); - } - private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) { String valueString = parser.getAttributeValue(null, attr); if (valueString == null) return defaultValue; @@ -823,7 +822,6 @@ public class UserManagerService extends IUserManager.Stub { writeUserLocked(userInfo); updateUserIdsLocked(); Bundle restrictions = new Bundle(); - initRestrictionsToDefaults(restrictions); mUserRestrictions.append(userId, restrictions); } } |