Merge "Fix privilege escalation for preferred activities"

This commit is contained in:
Robin Lee
2014-03-28 17:35:34 +00:00
committed by Android (Google) Code Review
2 changed files with 81 additions and 63 deletions

View File

@@ -51,6 +51,22 @@ import java.util.HashMap;
public final class DeviceAdminInfo implements Parcelable { public final class DeviceAdminInfo implements Parcelable {
static final String TAG = "DeviceAdminInfo"; static final String TAG = "DeviceAdminInfo";
/**
* A type of policy that this device admin can use: device owner meta-policy
* for an admin that is designated as owner of the device.
*
* @hide
*/
public static final int USES_POLICY_DEVICE_OWNER = -2;
/**
* A type of policy that this device admin can use: profile owner meta-policy
* for admins that have been installed as owner of some user profile.
*
* @hide
*/
public static final int USES_POLICY_PROFILE_OWNER = -1;
/** /**
* A type of policy that this device admin can use: limit the passwords * A type of policy that this device admin can use: limit the passwords
* that the user can select, via {@link DevicePolicyManager#setPasswordQuality} * that the user can select, via {@link DevicePolicyManager#setPasswordQuality}

View File

@@ -170,7 +170,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int mActivePasswordNonLetter = 0; int mActivePasswordNonLetter = 0;
int mFailedPasswordAttempts = 0; int mFailedPasswordAttempts = 0;
int mUserHandle;; int mUserHandle;
int mPasswordOwner = -1; int mPasswordOwner = -1;
long mLastMaximumTimeToLock = -1; long mLastMaximumTimeToLock = -1;
@@ -722,6 +722,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid();
final int userHandle = UserHandle.getUserId(callingUid); final int userHandle = UserHandle.getUserId(callingUid);
final DevicePolicyData policy = getUserData(userHandle); final DevicePolicyData policy = getUserData(userHandle);
List<ActiveAdmin> candidates = new ArrayList<ActiveAdmin>();
// Build a list of admins for this uid matching the given ComponentName
if (who != null) { if (who != null) {
ActiveAdmin admin = policy.mAdminMap.get(who); ActiveAdmin admin = policy.mAdminMap.get(who);
if (admin == null) { if (admin == null) {
@@ -731,22 +735,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new SecurityException("Admin " + who + " is not owned by uid " throw new SecurityException("Admin " + who + " is not owned by uid "
+ Binder.getCallingUid()); + Binder.getCallingUid());
} }
if (!admin.info.usesPolicy(reqPolicy)) { candidates.add(admin);
throw new SecurityException("Admin " + admin.info.getComponent()
+ " did not specify uses-policy for: "
+ admin.info.getTagForPolicy(reqPolicy));
}
return admin;
} else { } else {
final int N = policy.mAdminList.size(); for (ActiveAdmin admin : policy.mAdminList) {
for (int i=0; i<N; i++) { if (admin.getUid() == callingUid) {
ActiveAdmin admin = policy.mAdminList.get(i); candidates.add(admin);
if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) { }
}
}
// Try to find an admin which can use reqPolicy
for (ActiveAdmin admin : candidates) {
boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
boolean ownsProfile = (getProfileOwner(userHandle) != null
&& getProfileOwner(userHandle).equals(admin.info.getPackageName()));
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
if (ownsDevice) {
return admin;
}
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
if (ownsDevice || ownsProfile) {
return admin;
}
} else {
if (admin.info.usesPolicy(reqPolicy)) {
return admin; return admin;
} }
} }
}
if (who != null) {
throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+ " did not specify uses-policy for: "
+ candidates.get(0).info.getTagForPolicy(reqPolicy));
} else {
throw new SecurityException("No active admin owned by uid " throw new SecurityException("No active admin owned by uid "
+ Binder.getCallingUid() + " for policy #" + reqPolicy); + Binder.getCallingUid() + " for policy:" + reqPolicy);
} }
} }
@@ -2966,64 +2991,41 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} }
} }
private boolean isProfileOwner(String packageName, int userId) { public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
String profileOwnerPackage = getProfileOwner(userId);
// TODO: make public and connect with isProfileOwnerApp in DPM
return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
}
public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter,
ComponentName activity) { ComponentName activity) {
int callingUserId = UserHandle.getCallingUserId();
Slog.d(LOG_TAG,"called by user " + callingUserId);
synchronized (this) { synchronized (this) {
ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId); if (who == null) {
if (aa == null) { throw new NullPointerException("ComponentName is null");
throw new SecurityException("No active admin " + admin); }
} else { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
if (isProfileOwner(admin.getPackageName(), callingUserId)
|| isDeviceOwner(admin.getPackageName())) { IPackageManager pm = AppGlobals.getPackageManager();
IPackageManager pm = AppGlobals.getPackageManager(); long id = Binder.clearCallingIdentity();
long id = Binder.clearCallingIdentity(); try {
try { pm.addPersistentPreferredActivity(filter, activity, UserHandle.getCallingUserId());
pm.addPersistentPreferredActivity(filter, activity, callingUserId); } catch (RemoteException re) {
} catch (RemoteException re) { // Shouldn't happen
// Shouldn't happen } finally {
} finally { restoreCallingIdentity(id);
restoreCallingIdentity(id);
}
} else {
throw new SecurityException("Admin " + admin +
"is not device owner or profile owner" );
}
} }
} }
} }
public void clearPackagePersistentPreferredActivities(ComponentName admin, public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
String packageName) {
int callingUserId = UserHandle.getCallingUserId();
Slog.d(LOG_TAG,"called by user " + callingUserId);
synchronized (this) { synchronized (this) {
ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId); if (who == null) {
if (aa == null) { throw new NullPointerException("ComponentName is null");
throw new SecurityException("No active admin " + admin); }
} else { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
if (isProfileOwner(admin.getPackageName(), callingUserId)
|| isDeviceOwner(admin.getPackageName())) { IPackageManager pm = AppGlobals.getPackageManager();
IPackageManager pm = AppGlobals.getPackageManager(); long id = Binder.clearCallingIdentity();
long id = Binder.clearCallingIdentity(); try {
try{ pm.clearPackagePersistentPreferredActivities(packageName, UserHandle.getCallingUserId());
pm.clearPackagePersistentPreferredActivities(packageName, callingUserId); } catch (RemoteException re) {
} catch (RemoteException re) { // Shouldn't happen
// Shouldn't happen } finally {
} finally { restoreCallingIdentity(id);
restoreCallingIdentity(id);
}
} else {
throw new SecurityException("Admin " + admin +
"is not device owner or profile owner" );
}
} }
} }
} }