summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java17
-rw-r--r--services/core/java/com/android/server/PersistentDataBlockService.java23
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java50
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java11
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java17
-rw-r--r--services/core/java/com/android/server/content/ContentService.java79
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java60
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 {