diff options
| author | 2019-05-21 16:50:52 +0000 | |
|---|---|---|
| committer | 2019-05-21 16:50:52 +0000 | |
| commit | 743288a029deba1df1e0d01eca5d5db9dd855fc5 (patch) | |
| tree | c1e72a7a5b59bc22ee2b69fab7e6555cfb409209 | |
| parent | 376830178b8055930f7d4ca89702db17572199d1 (diff) | |
| parent | 33f56060d57a0aca3693caedbc37b5dc94a11ef3 (diff) | |
Merge "Fix sysui's security issue of cross-user copy/paste" into qt-dev
| -rw-r--r-- | core/java/android/content/ClipboardManager.java | 19 | ||||
| -rw-r--r-- | core/java/android/content/IClipboard.aidl | 17 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 31 | ||||
| -rw-r--r-- | services/core/java/com/android/server/clipboard/ClipboardService.java | 239 |
4 files changed, 219 insertions, 87 deletions
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 8760efeafd8c..dc1c700f5d08 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -103,7 +103,7 @@ public class ClipboardManager extends android.text.ClipboardManager { try { Preconditions.checkNotNull(clip); clip.prepareToLeaveProcess(true); - mService.setPrimaryClip(clip, mContext.getOpPackageName()); + mService.setPrimaryClip(clip, mContext.getOpPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -116,7 +116,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public void clearPrimaryClip() { try { - mService.clearPrimaryClip(mContext.getOpPackageName()); + mService.clearPrimaryClip(mContext.getOpPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -132,7 +132,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public @Nullable ClipData getPrimaryClip() { try { - return mService.getPrimaryClip(mContext.getOpPackageName()); + return mService.getPrimaryClip(mContext.getOpPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -149,7 +149,8 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public @Nullable ClipDescription getPrimaryClipDescription() { try { - return mService.getPrimaryClipDescription(mContext.getOpPackageName()); + return mService.getPrimaryClipDescription(mContext.getOpPackageName(), + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -163,7 +164,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public boolean hasPrimaryClip() { try { - return mService.hasPrimaryClip(mContext.getOpPackageName()); + return mService.hasPrimaryClip(mContext.getOpPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -174,7 +175,8 @@ public class ClipboardManager extends android.text.ClipboardManager { if (mPrimaryClipChangedListeners.isEmpty()) { try { mService.addPrimaryClipChangedListener( - mPrimaryClipChangedServiceListener, mContext.getOpPackageName()); + mPrimaryClipChangedServiceListener, mContext.getOpPackageName(), + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -189,7 +191,8 @@ public class ClipboardManager extends android.text.ClipboardManager { if (mPrimaryClipChangedListeners.isEmpty()) { try { mService.removePrimaryClipChangedListener( - mPrimaryClipChangedServiceListener); + mPrimaryClipChangedServiceListener, mContext.getOpPackageName(), + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -226,7 +229,7 @@ public class ClipboardManager extends android.text.ClipboardManager { @Deprecated public boolean hasText() { try { - return mService.hasClipboardText(mContext.getOpPackageName()); + return mService.hasClipboardText(mContext.getOpPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl index 135a4363ef21..0d5a46016f19 100644 --- a/core/java/android/content/IClipboard.aidl +++ b/core/java/android/content/IClipboard.aidl @@ -26,17 +26,18 @@ import android.content.IOnPrimaryClipChangedListener; * {@hide} */ interface IClipboard { - void setPrimaryClip(in ClipData clip, String callingPackage); - void clearPrimaryClip(String callingPackage); - ClipData getPrimaryClip(String pkg); - ClipDescription getPrimaryClipDescription(String callingPackage); - boolean hasPrimaryClip(String callingPackage); + void setPrimaryClip(in ClipData clip, String callingPackage, int userId); + void clearPrimaryClip(String callingPackage, int userId); + ClipData getPrimaryClip(String pkg, int userId); + ClipDescription getPrimaryClipDescription(String callingPackage, int userId); + boolean hasPrimaryClip(String callingPackage, int userId); void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener, - String callingPackage); - void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener); + String callingPackage, int userId); + void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener, + String callingPackage, int userId); /** * Returns true if the clipboard contains text; false otherwise. */ - boolean hasClipboardText(String callingPackage); + boolean hasClipboardText(String callingPackage, int userId); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 17c56c3f216a..a9e183ad5bf2 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -11244,13 +11244,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Nullable final TextServicesManager getTextServicesManagerForUser() { + return getServiceManagerForUser("android", TextServicesManager.class); + } + + @Nullable + final ClipboardManager getClipboardManagerForUser() { + return getServiceManagerForUser(getContext().getPackageName(), ClipboardManager.class); + } + + @Nullable + final <T> T getServiceManagerForUser(String packageName, Class<T> managerClazz) { if (mTextOperationUser == null) { - return getContext().getSystemService(TextServicesManager.class); + return getContext().getSystemService(managerClazz); } try { - return getContext().createPackageContextAsUser( - "android", 0 /* flags */, mTextOperationUser) - .getSystemService(TextServicesManager.class); + Context context = getContext().createPackageContextAsUser( + packageName, 0 /* flags */, mTextOperationUser); + return context.getSystemService(managerClazz); } catch (PackageManager.NameNotFoundException e) { return null; } @@ -12540,8 +12550,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && mEditor != null && mEditor.mKeyListener != null && getSelectionStart() >= 0 && getSelectionEnd() >= 0 - && ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE)) - .hasPrimaryClip()); + && getClipboardManagerForUser().hasPrimaryClip()); } boolean canPasteAsPlainText() { @@ -12549,9 +12558,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - final ClipData clipData = - ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE)) - .getPrimaryClip(); + final ClipData clipData = getClipboardManagerForUser().getPrimaryClip(); final ClipDescription description = clipData.getDescription(); final boolean isPlainType = description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN); final CharSequence text = clipData.getItemAt(0).getText(); @@ -12594,8 +12601,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Paste clipboard content between min and max positions. */ private void paste(int min, int max, boolean withFormatting) { - ClipboardManager clipboard = - (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + ClipboardManager clipboard = getClipboardManagerForUser(); ClipData clip = clipboard.getPrimaryClip(); if (clip != null) { boolean didFirst = false; @@ -12638,8 +12644,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @CheckResult private boolean setPrimaryClip(ClipData clip) { - ClipboardManager clipboard = - (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + ClipboardManager clipboard = getClipboardManagerForUser(); try { clipboard.setPrimaryClip(clip); } catch (Throwable t) { diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index d28482ef82ab..af25ad56a2a7 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -16,11 +16,14 @@ package com.android.server.clipboard; +import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; + +import android.Manifest; import android.annotation.Nullable; -import android.app.ActivityManager; +import android.annotation.UserIdInt; +import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.AppOpsManager; -import android.app.IActivityManager; import android.app.IUriGrantsManager; import android.app.KeyguardManager; import android.app.UriGrantsManager; @@ -145,6 +148,11 @@ class HostClipboardMonitor implements Runnable { /** * Implementation of the clipboard for copy and paste. + * <p> + * Caution: exception for clipboard data and isInternalSysWindowAppWithWindowFocus, any of data + * is accessed by userId or uid should be in * the try segment between + * Binder.clearCallingIdentity and Binder.restoreCallingIdentity. + * </p> */ public class ClipboardService extends SystemService { @@ -152,7 +160,7 @@ public class ClipboardService extends SystemService { private static final boolean IS_EMULATOR = SystemProperties.getBoolean("ro.kernel.qemu", false); - private final IActivityManager mAm; + private final ActivityManagerInternal mAmInternal; private final IUriGrantsManager mUgm; private final UriGrantsManagerInternal mUgmInternal; private final WindowManagerInternal mWm; @@ -173,7 +181,7 @@ public class ClipboardService extends SystemService { public ClipboardService(Context context) { super(context); - mAm = ActivityManager.getService(); + mAmInternal = LocalServices.getService(ActivityManagerInternal.class); mUgm = UriGrantsManager.getService(); mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class); mWm = LocalServices.getService(WindowManagerInternal.class); @@ -244,6 +252,87 @@ public class ClipboardService extends SystemService { } } + /** + * To check if the application has granted the INTERNAL_SYSTEM_WINDOW permission and window + * focus. + * <p> + * All of applications granted INTERNAL_SYSTEM_WINDOW has the risk to leak clip information to + * the other user because INTERNAL_SYSTEM_WINDOW is signature level. i.e. platform key. Because + * some of applications have both of INTERNAL_SYSTEM_WINDOW and INTERACT_ACROSS_USERS_FULL at + * the same time, that means they show the same window to all of users. + * </p><p> + * Unfortunately, all of applications with INTERNAL_SYSTEM_WINDOW starts very early and then + * the real window show is belong to user 0 rather user X. The result of + * WindowManager.isUidFocused checking user X window is false. + * </p> + * @return true if the app granted INTERNAL_SYSTEM_WINDOW permission. + */ + private boolean isInternalSysWindowAppWithWindowFocus(String callingPackage) { + // Shell can access the clipboard for testing purposes. + if (mPm.checkPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW, + callingPackage) == PackageManager.PERMISSION_GRANTED) { + if (mWm.isUidFocused(Binder.getCallingUid())) { + return true; + } + } + + return false; + } + + /** + * To get the validate current userId. + * <p> + * The intending userId needs to be validated by ActivityManagerInternal.handleIncomingUser. + * To check if the uid of the process have the permission to run as the userId. + * e.x. INTERACT_ACROSS_USERS_FULL or INTERACT_ACROSS_USERS permission granted. + * </p> + * <p> + * The application with the granted INTERNAL_SYSTEM_WINDOW permission should run as the output + * of ActivityManagerInternal.handleIncomingUser rather the userId of Binder.getCAllingUid(). + * To use the userId of Binder.getCallingUid() is the root cause that leaks the information + * comes from user 0 to user X. + * </p> + * + * @param packageName the package name of the calling side + * @param userId the userId passed by the calling side + * @return return the intending userId that has been validated by ActivityManagerInternal. + */ + @UserIdInt + private int getIntendingUserId(String packageName, @UserIdInt int userId) { + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getUserId(callingUid); + if (!UserManager.supportsMultipleUsers() || callingUserId == userId) { + return callingUserId; + } + + int intendingUserId = callingUserId; + intendingUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false /* allow all */, ALLOW_FULL_ONLY, + "checkClipboardServiceCallingUser", packageName); + + return intendingUserId; + } + + /** + * To get the current running uid who is intend to run as. + * In ording to distinguish the nameing and reducing the confusing names, the client client + * side pass userId that is intend to run as, + * @return return IntentingUid = validated intenting userId + + * UserHandle.getAppId(Binder.getCallingUid()) + */ + private int getIntendingUid(String packageName, @UserIdInt int userId) { + return UserHandle.getUid(getIntendingUserId(packageName, userId), + UserHandle.getAppId(Binder.getCallingUid())); + } + + /** + * To handle the difference between userId and intendingUserId, uid and intendingUid. + * + * userId means that comes from the calling side and should be validated by + * ActivityManagerInternal.handleIncomingUser. + * After validation of ActivityManagerInternal.handleIncomingUser, the userId is called + * 'intendingUserId' and the uid is called 'intendingUid'. + */ private class ClipboardImpl extends IClipboard.Stub { @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) @@ -260,92 +349,112 @@ public class ClipboardService extends SystemService { } @Override - public void setPrimaryClip(ClipData clip, String callingPackage) { + public void setPrimaryClip(ClipData clip, String callingPackage, @UserIdInt int userId) { synchronized (this) { if (clip == null || clip.getItemCount() <= 0) { throw new IllegalArgumentException("No items"); } - final int callingUid = Binder.getCallingUid(); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, - callingUid)) { + intendingUid, intendingUserId)) { return; } - checkDataOwnerLocked(clip, callingUid); - setPrimaryClipInternal(clip, callingUid); + checkDataOwnerLocked(clip, intendingUid); + setPrimaryClipInternal(clip, intendingUid); } } @Override - public void clearPrimaryClip(String callingPackage) { + public void clearPrimaryClip(String callingPackage, @UserIdInt int userId) { synchronized (this) { - final int callingUid = Binder.getCallingUid(); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, - callingUid)) { + intendingUid, intendingUserId)) { return; } - setPrimaryClipInternal(null, callingUid); + setPrimaryClipInternal(null, intendingUid); } } @Override - public ClipData getPrimaryClip(String pkg) { + public ClipData getPrimaryClip(String pkg, @UserIdInt int userId) { synchronized (this) { + final int intendingUid = getIntendingUid(pkg, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg, - Binder.getCallingUid()) || isDeviceLocked()) { + intendingUid, intendingUserId) + || isDeviceLocked(intendingUserId)) { return null; } - addActiveOwnerLocked(Binder.getCallingUid(), pkg); - return getClipboard().primaryClip; + addActiveOwnerLocked(intendingUid, pkg); + return getClipboard(intendingUserId).primaryClip; } } @Override - public ClipDescription getPrimaryClipDescription(String callingPackage) { + public ClipDescription getPrimaryClipDescription(String callingPackage, + @UserIdInt int userId) { synchronized (this) { + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - Binder.getCallingUid()) || isDeviceLocked()) { + intendingUid, intendingUserId) + || isDeviceLocked(intendingUserId)) { return null; } - PerUserClipboard clipboard = getClipboard(); - return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null; + PerUserClipboard clipboard = getClipboard(intendingUserId); + return clipboard.primaryClip != null + ? clipboard.primaryClip.getDescription() : null; } } @Override - public boolean hasPrimaryClip(String callingPackage) { + public boolean hasPrimaryClip(String callingPackage, @UserIdInt int userId) { synchronized (this) { + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - Binder.getCallingUid()) || isDeviceLocked()) { + intendingUid, intendingUserId) + || isDeviceLocked(intendingUserId)) { return false; } - return getClipboard().primaryClip != null; + return getClipboard(intendingUserId).primaryClip != null; } } @Override public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, - String callingPackage) { + String callingPackage, @UserIdInt int userId) { synchronized (this) { - getClipboard().primaryClipListeners.register(listener, - new ListenerInfo(Binder.getCallingUid(), callingPackage)); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + getClipboard(intendingUserId).primaryClipListeners.register(listener, + new ListenerInfo(intendingUid, callingPackage)); } } @Override - public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) { + public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, + String callingPackage, @UserIdInt int userId) { synchronized (this) { - getClipboard().primaryClipListeners.unregister(listener); + final int intendingUserId = getIntendingUserId(callingPackage, userId); + getClipboard(intendingUserId).primaryClipListeners.unregister(listener); } } @Override - public boolean hasClipboardText(String callingPackage) { + public boolean hasClipboardText(String callingPackage, int userId) { synchronized (this) { + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - Binder.getCallingUid()) || isDeviceLocked()) { + intendingUid, intendingUserId) + || isDeviceLocked(intendingUserId)) { return false; } - PerUserClipboard clipboard = getClipboard(); + PerUserClipboard clipboard = getClipboard(intendingUserId); if (clipboard.primaryClip != null) { CharSequence text = clipboard.primaryClip.getItemAt(0).getText(); return text != null && text.length() > 0; @@ -355,11 +464,7 @@ public class ClipboardService extends SystemService { } }; - private PerUserClipboard getClipboard() { - return getClipboard(UserHandle.getCallingUserId()); - } - - private PerUserClipboard getClipboard(int userId) { + private PerUserClipboard getClipboard(@UserIdInt int userId) { synchronized (mClipboards) { PerUserClipboard puc = mClipboards.get(userId); if (puc == null) { @@ -370,7 +475,7 @@ public class ClipboardService extends SystemService { } } - List<UserInfo> getRelatedProfiles(int userId) { + List<UserInfo> getRelatedProfiles(@UserIdInt int userId) { final List<UserInfo> related; final long origId = Binder.clearCallingIdentity(); try { @@ -397,7 +502,7 @@ public class ClipboardService extends SystemService { } } - void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) { + void setPrimaryClipInternal(@Nullable ClipData clip, int uid) { // Push clipboard to host, if any if (mHostClipboardMonitor != null) { if (clip == null) { @@ -412,8 +517,8 @@ public class ClipboardService extends SystemService { } // Update this user - final int userId = UserHandle.getUserId(callingUid); - setPrimaryClipInternal(getClipboard(userId), clip, callingUid); + final int userId = UserHandle.getUserId(uid); + setPrimaryClipInternal(getClipboard(userId), clip, uid); // Update related users List<UserInfo> related = getRelatedProfiles(userId); @@ -426,11 +531,15 @@ public class ClipboardService extends SystemService { // primary clip in related users to prevent pasting stale content. if (!canCopy) { clip = null; + } else if (clip == null) { + // do nothing for canCopy == true and clip == null case + // To prevent from NPE happen in 'new ClipData(clip)' when run + // android.content.cts.ClipboardManagerTest#testClearPrimaryClip } else { // We want to fix the uris of the related user's clip without changing the // uris of the current user's clip. // So, copy the ClipData, and then copy all the items, so that nothing - // is shared in memmory. + // is shared in memory. clip = new ClipData(clip); for (int i = clip.getItemCount() - 1; i >= 0; i--) { clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i))); @@ -443,7 +552,7 @@ public class ClipboardService extends SystemService { final boolean canCopyIntoProfile = !hasRestriction( UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id); if (canCopyIntoProfile) { - setPrimaryClipInternal(getClipboard(id), clip, callingUid); + setPrimaryClipInternal(getClipboard(id), clip, uid); } } } @@ -452,7 +561,7 @@ public class ClipboardService extends SystemService { } void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip, - int callingUid) { + int uid) { revokeUris(clipboard); clipboard.activePermissionOwners.clear(); if (clip == null && clipboard.primaryClip == null) { @@ -460,7 +569,7 @@ public class ClipboardService extends SystemService { } clipboard.primaryClip = clip; if (clip != null) { - clipboard.primaryClipUid = callingUid; + clipboard.primaryClipUid = uid; } else { clipboard.primaryClipUid = android.os.Process.NOBODY_UID; } @@ -479,7 +588,7 @@ public class ClipboardService extends SystemService { clipboard.primaryClipListeners.getBroadcastCookie(i); if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName, - li.mUid)) { + li.mUid, UserHandle.getUserId(li.mUid))) { clipboard.primaryClipListeners.getBroadcastItem(i) .dispatchPrimaryClipChanged(); } @@ -494,13 +603,12 @@ public class ClipboardService extends SystemService { } } - private boolean isDeviceLocked() { - int callingUserId = UserHandle.getCallingUserId(); + private boolean isDeviceLocked(@UserIdInt int userId) { final long token = Binder.clearCallingIdentity(); try { final KeyguardManager keyguardManager = getContext().getSystemService( KeyguardManager.class); - return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId); + return keyguardManager != null && keyguardManager.isDeviceLocked(userId); } finally { Binder.restoreCallingIdentity(token); } @@ -585,7 +693,7 @@ public class ClipboardService extends SystemService { } finally { Binder.restoreCallingIdentity(oldIdentity); } - PerUserClipboard clipboard = getClipboard(); + PerUserClipboard clipboard = getClipboard(UserHandle.getUserId(uid)); if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { final int N = clipboard.primaryClip.getItemCount(); for (int i=0; i<N; i++) { @@ -630,9 +738,10 @@ public class ClipboardService extends SystemService { } } - private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) { + private boolean clipboardAccessAllowed(int op, String callingPackage, int uid, + @UserIdInt int userId) { // Check the AppOp. - if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) { + if (mAppOps.noteOp(op, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) { return false; } // Shell can access the clipboard for testing purposes. @@ -641,7 +750,6 @@ public class ClipboardService extends SystemService { return true; } // The default IME is always allowed to access the clipboard. - int userId = UserHandle.getUserId(callingUid); String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, userId); if (!TextUtils.isEmpty(defaultIme)) { @@ -654,16 +762,31 @@ public class ClipboardService extends SystemService { switch (op) { case AppOpsManager.OP_READ_CLIPBOARD: // Clipboard can only be read by applications with focus.. - boolean allowed = mWm.isUidFocused(callingUid); + // or the application have the INTERNAL_SYSTEM_WINDOW and INTERACT_ACROSS_USERS_FULL + // at the same time. e.x. SystemUI. It needs to check the window focus of + // Binder.getCallingUid(). Without checking, the user X can't copy any thing from + // INTERNAL_SYSTEM_WINDOW to the other applications. + boolean allowed = mWm.isUidFocused(uid) + || isInternalSysWindowAppWithWindowFocus(callingPackage); if (!allowed && mContentCaptureInternal != null) { // ...or the Content Capture Service - allowed = mContentCaptureInternal.isContentCaptureServiceForUser(callingUid, - userId); + // The uid parameter of mContentCaptureInternal.isContentCaptureServiceForUser + // is used to check if the uid has the permission BIND_CONTENT_CAPTURE_SERVICE. + // if the application has the permission, let it to access user's clipboard. + // To passed synthesized uid user#10_app#systemui may not tell the real uid. + // userId must pass intending userId. i.e. user#10. + allowed = mContentCaptureInternal.isContentCaptureServiceForUser( + Binder.getCallingUid(), userId); } if (!allowed && mAutofillInternal != null) { // ...or the Augmented Autofill Service - allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(callingUid, - userId); + // The uid parameter of mAutofillInternal.isAugmentedAutofillServiceForUser + // is used to check if the uid has the permission BIND_AUTOFILL_SERVICE. + // if the application has the permission, let it to access user's clipboard. + // To passed synthesized uid user#10_app#systemui may not tell the real uid. + // userId must pass intending userId. i.e. user#10. + allowed = mAutofillInternal.isAugmentedAutofillServiceForUser( + Binder.getCallingUid(), userId); } if (!allowed) { Slog.e(TAG, "Denying clipboard access to " + callingPackage |