diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-05-02 19:22:30 +0200 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-05-02 19:22:30 +0200 |
commit | a0ce80942766948d4cd1036b97e2ee721ed8ecce (patch) | |
tree | 5d596eea5771aa9f494d2b1fcf6b3b44da2d401c /services | |
parent | a3f7b1e4871de0b508bbefb0236d258d47a38f15 (diff) | |
parent | 0e4f9e2f03e376f0816c1e653bf97fe1d0176794 (diff) | |
download | frameworks_base-replicant-6.0.zip frameworks_base-replicant-6.0.tar.gz frameworks_base-replicant-6.0.tar.bz2 |
Merge branch 'cm-13.0' of https://github.com/LineageOS/android_frameworks_base into replicant-6.0HEADreplicant-6.0-0001replicant-6.0
Diffstat (limited to 'services')
7 files changed, 179 insertions, 78 deletions
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 6cd8e10..5019161 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -88,6 +88,8 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; +import android.text.TextUtils; +import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -2638,9 +2640,22 @@ public class LocationManagerService extends ILocationManager.Stub { if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } + + // Ensure that the location is marked as being mock. There's some logic to do this in + // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107). + Location mock = new Location(loc); + mock.setIsFromMockProvider(true); + + if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) { + // The location has an explicit provider that is different from the mock provider + // name. The caller may be trying to fool us via bug 33091107. + EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(), + provider + "!=" + loc.getProvider()); + } + // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required long identity = Binder.clearCallingIdentity(); - mockProvider.setLocation(loc); + mockProvider.setLocation(mock); Binder.restoreCallingIdentity(identity); } } diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index 94316fe..9346083 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -29,6 +29,7 @@ import android.service.persistentdata.IPersistentDataBlockService; import android.util.Slog; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import libcore.io.IoUtils; @@ -50,15 +51,14 @@ import java.util.Arrays; * This data will live across factory resets not initiated via the Settings UI. * When a device is factory reset through Settings this data is wiped. * - * Allows writing one block at a time. Namely, each time - * {@link android.service.persistentdata.IPersistentDataBlockService}.write(byte[] data) - * is called, it will overwite the data that was previously written on the block. + * Allows writing one block at a time. Namely, each time {@link IPersistentDataBlockService#write} + * is called, it will overwrite the data that was previously written on the block. * * Clients can query the size of the currently written block via - * {@link android.service.persistentdata.IPersistentDataBlockService}.getTotalDataSize(). + * {@link IPersistentDataBlockService#getDataBlockSize} * - * Clients can any number of bytes from the currently written block up to its total size by invoking - * {@link android.service.persistentdata.IPersistentDataBlockService}.read(byte[] data) + * Clients can read any number of bytes from the currently written block up to its total size by + * invoking {@link IPersistentDataBlockService#read} */ public class PersistentDataBlockService extends SystemService { private static final String TAG = PersistentDataBlockService.class.getSimpleName(); @@ -79,6 +79,9 @@ public class PersistentDataBlockService extends SystemService { private int mAllowedUid = -1; private long mBlockDeviceSize; + @GuardedBy("mLock") + private boolean mIsWritable = true; + public PersistentDataBlockService(Context context) { super(context); mContext = context; @@ -349,6 +352,11 @@ public class PersistentDataBlockService extends SystemService { headerAndData.put(data); synchronized (mLock) { + if (!mIsWritable) { + IoUtils.closeQuietly(outputStream); + return -1; + } + try { byte[] checksum = new byte[DIGEST_SIZE_BYTES]; outputStream.write(checksum, 0, DIGEST_SIZE_BYTES); @@ -423,6 +431,9 @@ public class PersistentDataBlockService extends SystemService { if (ret < 0) { Slog.e(TAG, "failed to wipe persistent partition"); + } else { + mIsWritable = false; + Slog.i(TAG, "persistent partition now wiped and unwritable"); } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 23f34e6..3715620 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -219,6 +219,7 @@ import android.os.UpdateLock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.provider.Downloads; import android.telecom.TelecomManager; import android.text.format.DateUtils; import android.text.format.Time; @@ -8181,6 +8182,12 @@ public final class ActivityManagerService extends ActivityManagerNative // Only inspect grants matching package if (packageName == null || perm.sourcePkg.equals(packageName) || perm.targetPkg.equals(packageName)) { + // Hacky solution as part of fixing a security bug; ignore + // grants associated with DownloadManager so we don't have + // to immediately launch it to regrant the permissions + if (Downloads.Impl.AUTHORITY.equals(perm.uri.uri.getAuthority()) + && !persistable) continue; + persistChanged |= perm.revokeModes(persistable ? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true); @@ -9623,6 +9630,44 @@ public final class ActivityManagerService extends ActivityManagerNative } /** + * Check if the calling UID has a possible chance at accessing the provider + * at the given authority and user. + */ + public String checkContentProviderAccess(String authority, int userId) { + if (userId == UserHandle.USER_ALL) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); + userId = UserHandle.getCallingUserId(); + } + + ProviderInfo cpi = null; + try { + cpi = AppGlobals.getPackageManager().resolveContentProvider(authority, + STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, + userId); + } catch (RemoteException ignored) { + } + if (cpi == null) { + // TODO: make this an outright failure in a future platform release; + // until then anonymous content notifications are unprotected + //return "Failed to find provider " + authority + " for user " + userId; + return null; + } + + ProcessRecord r = null; + synchronized (mPidsSelfLocked) { + r = mPidsSelfLocked.get(Binder.getCallingPid()); + } + if (r == null) { + return "Failed to find PID " + Binder.getCallingPid(); + } + + synchronized (this) { + return checkContentProviderPermissionLocked(cpi, r, userId, true); + } + } + + /** * Check if {@link ProcessRecord} has a possible chance at accessing the * given {@link ProviderInfo}. Final permission checking is always done * in {@link ContentProvider}. @@ -21136,6 +21181,11 @@ public final class ActivityManagerService extends ActivityManagerNative private final class LocalService extends ActivityManagerInternal { @Override + public String checkContentProviderAccess(String authority, int userId) { + return ActivityManagerService.this.checkContentProviderAccess(authority, userId); + } + + @Override public void onWakefulnessChanged(int wakefulness) { ActivityManagerService.this.onWakefulnessChanged(wakefulness); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index fe3df61..7b90c83 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1101,10 +1101,13 @@ public class AudioService extends IAudioService.Stub { mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; - if (mLinkNotificationWithVolume && mVoiceCapable) { - mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; - } else { - mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; + if (mVoiceCapable) { + if (mLinkNotificationWithVolume) { + mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; + } else { + mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = + AudioSystem.STREAM_NOTIFICATION; + } } if (updateVolumes) { diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 60d6772..873e0c3 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1696,9 +1696,8 @@ public class Tethering extends BaseNetworkObserver { // used to verify this receiver is still current final private int mGenerationNumber; - // we're interested in edge-triggered LOADED notifications, so - // ignore LOADED unless we saw an ABSENT state first - private boolean mSimAbsentSeen = false; + // used to check the sim state transition from non-loaded to loaded + private boolean mSimNotLoadedSeen = false; public SimChangeBroadcastReceiver(int generationNumber) { super(); @@ -1716,14 +1715,14 @@ public class Tethering extends BaseNetworkObserver { final String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); - Log.d(TAG, "got Sim changed to state " + state + ", mSimAbsentSeen=" + - mSimAbsentSeen); - if (!mSimAbsentSeen && IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) { - mSimAbsentSeen = true; + Log.d(TAG, "got Sim changed to state " + state + ", mSimNotLoadedSeen=" + + mSimNotLoadedSeen); + if (!mSimNotLoadedSeen && !IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { + mSimNotLoadedSeen = true; } - if (mSimAbsentSeen && IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { - mSimAbsentSeen = false; + if (mSimNotLoadedSeen && IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { + mSimNotLoadedSeen = false; try { if (mContext.getResources().getString(com.android.internal.R.string. config_mobile_hotspot_provision_app_no_ui).isEmpty() == false) { diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index f581a7f..1db31c9 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -19,6 +19,8 @@ package com.android.server.content; import android.Manifest; import android.accounts.Account; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -51,7 +53,6 @@ import com.android.server.LocalServices; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -190,23 +191,15 @@ public final class ContentService extends IContentService.Stub { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); - final int callingUserHandle = UserHandle.getCallingUserId(); - // Registering an observer for any user other than the calling user requires uri grant or - // cross user permission - if (callingUserHandle != userHandle && - mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) - != PackageManager.PERMISSION_GRANTED) { - enforceCrossUserPermission(userHandle, - "no permission to observe other users' provider view"); - } - if (userHandle < 0) { - if (userHandle == UserHandle.USER_CURRENT) { - userHandle = ActivityManager.getCurrentUser(); - } else if (userHandle != UserHandle.USER_ALL) { - throw new InvalidParameterException("Bad user handle for registerContentObserver: " - + userHandle); - } + userHandle = handleIncomingUser(uri, pid, uid, + Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle); + + final String msg = LocalServices.getService(ActivityManagerInternal.class) + .checkContentProviderAccess(uri.getAuthority(), userHandle); + if (msg != null) { + Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg); + return; } synchronized (mRootNode) { @@ -253,21 +246,15 @@ public final class ContentService extends IContentService.Stub { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final int callingUserHandle = UserHandle.getCallingUserId(); - // Notify for any user other than the caller requires uri grant or cross user permission - if (callingUserHandle != userHandle && - mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - != PackageManager.PERMISSION_GRANTED) { - enforceCrossUserPermission(userHandle, "no permission to notify other users"); - } - // We passed the permission check; resolve pseudouser targets as appropriate - if (userHandle < 0) { - if (userHandle == UserHandle.USER_CURRENT) { - userHandle = ActivityManager.getCurrentUser(); - } else if (userHandle != UserHandle.USER_ALL) { - throw new InvalidParameterException("Bad user handle for notifyChange: " - + userHandle); - } + userHandle = handleIncomingUser(uri, pid, uid, + Intent.FLAG_GRANT_WRITE_URI_PERMISSION, userHandle); + + final String msg = LocalServices.getService(ActivityManagerInternal.class) + .checkContentProviderAccess(uri.getAuthority(), userHandle); + if (msg != null) { + Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg); + return; } // This makes it so that future permission checks will be in the context of this @@ -317,6 +304,15 @@ public final class ContentService extends IContentService.Stub { } } + private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) { + try { + return ActivityManagerNative.getDefault().checkUriPermission( + uri, pid, uid, modeFlags, userHandle, null); + } catch (RemoteException e) { + return PackageManager.PERMISSION_DENIED; + } + } + public void notifyChange(Uri uri, IContentObserver observer, boolean observerWantsSelfNotifications, boolean syncToNetwork) { notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork, @@ -924,6 +920,27 @@ public final class ContentService extends IContentService.Stub { return service; } + private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, int userId) { + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + if (userId == UserHandle.USER_ALL) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); + } else if (userId < 0) { + throw new IllegalArgumentException("Invalid user: " + userId); + } else if (userId != UserHandle.getCallingUserId()) { + if (checkUriPermission(uri, pid, uid, modeFlags, + userId) != PackageManager.PERMISSION_GRANTED) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); + } + } + + return userId; + } + /** * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL * permission, if the userHandle is not for the caller. diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 302d23a..911862e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3322,7 +3322,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void wipeDataLocked(boolean wipeExtRequested, String reason) { + private void wipeDataNoLock(boolean wipeExtRequested, String reason) { if (wipeExtRequested) { StorageManager sm = (StorageManager) mContext.getSystemService( Context.STORAGE_SERVICE); @@ -3341,13 +3341,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceCrossUserPermission(userHandle); + + final String source; synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. final ActiveAdmin admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA); - final String source; final ComponentName cname = admin.info.getComponent(); if (cname != null) { source = cname.flattenToShortString(); @@ -3372,39 +3373,44 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { manager.wipe(); } } - boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0; - wipeDeviceOrUserLocked(wipeExtRequested, userHandle, - "DevicePolicyManager.wipeData() from " + source); } finally { Binder.restoreCallingIdentity(ident); } } + final boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0; + wipeDeviceNoLock(wipeExtRequested, userHandle, + "DevicePolicyManager.wipeData() from " + source); } - private void wipeDeviceOrUserLocked(boolean wipeExtRequested, final int userHandle, String reason) { - if (userHandle == UserHandle.USER_OWNER) { - wipeDataLocked(wipeExtRequested, reason); - } else { - mHandler.post(new Runnable() { - @Override - public void run() { - try { - IActivityManager am = ActivityManagerNative.getDefault(); - if (am.getCurrentUser().id == userHandle) { - am.switchUser(UserHandle.USER_OWNER); - } + private void wipeDeviceNoLock(boolean wipeExtRequested, final int userHandle, String reason) { + final long ident = Binder.clearCallingIdentity(); + try { + if (userHandle == UserHandle.USER_OWNER) { + wipeDataNoLock(wipeExtRequested, reason); + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + try { + IActivityManager am = ActivityManagerNative.getDefault(); + if (am.getCurrentUser().id == userHandle) { + am.switchUser(UserHandle.USER_OWNER); + } - boolean isManagedProfile = isManagedProfile(userHandle); - if (!mUserManager.removeUser(userHandle)) { - Slog.w(LOG_TAG, "Couldn't remove user " + userHandle); - } else if (isManagedProfile) { - sendWipeProfileNotification(); + boolean isManagedProfile = isManagedProfile(userHandle); + if (!mUserManager.removeUser(userHandle)) { + Slog.w(LOG_TAG, "Couldn't remove user " + userHandle); + } else if (isManagedProfile) { + sendWipeProfileNotification(); + } + } catch (RemoteException re) { + // Shouldn't happen } - } catch (RemoteException re) { - // Shouldn't happen } - } - }); + }); + } + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -3562,7 +3568,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (wipeData) { // Call without holding lock. - wipeDeviceOrUserLocked(false, identifier, + wipeDeviceNoLock(false, identifier, "reportFailedPasswordAttempt()"); } } finally { |