From b90e737c3f54c3096467fafd38334b96a7e929bf Mon Sep 17 00:00:00 2001 From: AlamIntel Date: Mon, 16 Dec 2024 13:38:47 +0530 Subject: [PATCH] ASB JAN 2025 Security Patches integration Integrating Google Android Security Bulletin Patches. Test done: STS r34 TCs Passed (Tested on EB-4417 & 4149) Tracked-On: OAM-128566 Signed-off-by: AlamIntel --- ...LEASE_PLATFORM_SECURITY_PATCH-string.patch | 27 + ...ng-Error-logs-During-framework-boot.patch} | 0 ...atch => 0012-Enable-ART-AutoFastJni.patch} | 0 ...msFilterSettings-properties.bulletin.patch | 84 ++ ...ations-added-directly-by-NM.bulletin.patch | 80 ++ ...line-SECURE_ALLOWLIST_TOKEN.bulletin.patch | 200 ++++ .../0016-Update-checkKeyIntent.bulletin.patch | 54 ++ ...effects-stored-on-a-NotificationChan.patch | 63 ++ ...caller-for-startActivityInT.bulletin.patch | 71 ++ ...D-for-hidden-Perm-Sync-APIs.bulletin.patch | 48 + ...ways-show-all-approved-apps.bulletin.patch | 201 ++++ ...fault-format-for-software-rendering.patch} | 0 ...putDevice-Use-location-for-idc-file.patch} | 0 ...D-handling-in-continueWrite.bulletin.patch | 389 ++++++++ ...grow-rejects-large-data-pos.bulletin.patch | 41 + ...date-read-data-before-write.bulletin.patch | 59 ++ ...ckjacking-attack-in-DocsUi-.bulletin.patch | 76 ++ ...ervice-has-an-intent-filter.bulletin.patch | 147 +++ ...n-group-auto-grant-behaivor.bulletin.patch | 897 ++++++++++++++++++ ...security.cts.CVE_2023_20913-failure.patch} | 0 ...fault-dialer-for-VisualVoic.bulletin.patch | 52 + 21 files changed, 2489 insertions(+) create mode 100644 aosp_diff/preliminary/build/release/0001-Update-RELEASE_PLATFORM_SECURITY_PATCH-string.patch rename aosp_diff/preliminary/frameworks/base/{23_0023-Avoiding-Error-logs-During-framework-boot.patch => 0011-Avoiding-Error-logs-During-framework-boot.patch} (100%) rename aosp_diff/preliminary/frameworks/base/{24_0024-Enable-ART-AutoFastJni.patch => 0012-Enable-ART-AutoFastJni.patch} (100%) create mode 100644 aosp_diff/preliminary/frameworks/base/0013-enforce-limits-for-VisualVoicemailSmsFilterSettings-properties.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0014-Ensure-group-summary-and-any-notifications-added-directly-by-NM.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0015-Inline-SECURE_ALLOWLIST_TOKEN.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0016-Update-checkKeyIntent.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0017-Limit-the-size-of-vibration-effects-stored-on-a-NotificationChan.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0018-Pass-SafeActivityOptions-with-actual-caller-for-startActivityInT.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0019-CDM-Check-if-it-s-system-UID-for-hidden-Perm-Sync-APIs.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/0020-Always-show-all-approved-apps.bulletin.patch rename aosp_diff/preliminary/frameworks/native/{01_0001-Use-BRGA-as-default-format-for-software-rendering.patch => 0001-Use-BRGA-as-default-format-for-software-rendering.patch} (100%) rename aosp_diff/preliminary/frameworks/native/{03_0003-InputDevice-Use-location-for-idc-file.patch => 0002-InputDevice-Use-location-for-idc-file.patch} (100%) create mode 100644 aosp_diff/preliminary/frameworks/native/0003-binder-fix-FD-handling-in-continueWrite.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/native/0004-libbinder-Parcel-grow-rejects-large-data-pos.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/native/0005-libbinder-Parcel-validate-read-data-before-write.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/apps/DocumentsUI/0001-Prevent-clickjacking-attack-in-DocsUi-.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/apps/Settings/0001-CDM-NLS-Check-if-the-NLS-service-has-an-intent-filter.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/modules/Permission/0001-Fix-Dynamic-Permission-group-auto-grant-behaivor.bulletin.patch rename aosp_diff/preliminary/packages/services/Telephony/{03_0003-Fix-for-android.security.cts.CVE_2023_20913-failure.patch => 0001-Fix-for-android.security.cts.CVE_2023_20913-failure.patch} (100%) create mode 100644 aosp_diff/preliminary/packages/services/Telephony/0002-enforce-the-calling-package-is-the-default-dialer-for-VisualVoic.bulletin.patch diff --git a/aosp_diff/preliminary/build/release/0001-Update-RELEASE_PLATFORM_SECURITY_PATCH-string.patch b/aosp_diff/preliminary/build/release/0001-Update-RELEASE_PLATFORM_SECURITY_PATCH-string.patch new file mode 100644 index 0000000000..95ae9446ed --- /dev/null +++ b/aosp_diff/preliminary/build/release/0001-Update-RELEASE_PLATFORM_SECURITY_PATCH-string.patch @@ -0,0 +1,27 @@ +From 557549b925dd19c62bfe522d1769bee59d2beed2 Mon Sep 17 00:00:00 2001 +From: "Alam, Sahibex" +Date: Thu, 9 Jan 2025 20:44:37 +0530 +Subject: [PATCH] Update RELEASE_PLATFORM_SECURITY_PATCH string + +Security_patch_level needs to be updated +When ASB Security patches are integrated + +Tracked-On: OAM-125942 +Signed-off-by: Alam, Sahibex +--- + flag_values/ap3a/RELEASE_PLATFORM_SECURITY_PATCH.textproto | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/flag_values/ap3a/RELEASE_PLATFORM_SECURITY_PATCH.textproto b/flag_values/ap3a/RELEASE_PLATFORM_SECURITY_PATCH.textproto +index ce29523c..5f7ab423 100644 +--- a/flag_values/ap3a/RELEASE_PLATFORM_SECURITY_PATCH.textproto ++++ b/flag_values/ap3a/RELEASE_PLATFORM_SECURITY_PATCH.textproto +@@ -1,4 +1,4 @@ + name: "RELEASE_PLATFORM_SECURITY_PATCH" + value: { +- string_value: "2024-11-05" ++ string_value: "2025-01-01" + } +-- +2.34.1 + diff --git a/aosp_diff/preliminary/frameworks/base/23_0023-Avoiding-Error-logs-During-framework-boot.patch b/aosp_diff/preliminary/frameworks/base/0011-Avoiding-Error-logs-During-framework-boot.patch similarity index 100% rename from aosp_diff/preliminary/frameworks/base/23_0023-Avoiding-Error-logs-During-framework-boot.patch rename to aosp_diff/preliminary/frameworks/base/0011-Avoiding-Error-logs-During-framework-boot.patch diff --git a/aosp_diff/preliminary/frameworks/base/24_0024-Enable-ART-AutoFastJni.patch b/aosp_diff/preliminary/frameworks/base/0012-Enable-ART-AutoFastJni.patch similarity index 100% rename from aosp_diff/preliminary/frameworks/base/24_0024-Enable-ART-AutoFastJni.patch rename to aosp_diff/preliminary/frameworks/base/0012-Enable-ART-AutoFastJni.patch diff --git a/aosp_diff/preliminary/frameworks/base/0013-enforce-limits-for-VisualVoicemailSmsFilterSettings-properties.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0013-enforce-limits-for-VisualVoicemailSmsFilterSettings-properties.bulletin.patch new file mode 100644 index 0000000000..a4f8f549e7 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0013-enforce-limits-for-VisualVoicemailSmsFilterSettings-properties.bulletin.patch @@ -0,0 +1,84 @@ +From bcb1316835dc31f33f0c3b409ee847c389c09d2b Mon Sep 17 00:00:00 2001 +From: Thomas Stuart +Date: Thu, 6 Jun 2024 22:36:40 +0000 +Subject: [PATCH] enforce limits for VisualVoicemailSmsFilterSettings + properties + +- clientPrefix is now limited to 256 characters +- originatingNumbers is now limited to a list size of 100 and + each element is also limited to 256 characters + +Bug: 308932906 +Test: CTS +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:25b326e4844671a18c30426c5bc5d7481fb83d54) +Merged-In: Id4b4358b141bb211a7e340b979774850b4bd2403 +Change-Id: Id4b4358b141bb211a7e340b979774850b4bd2403 +--- + .../VisualVoicemailSmsFilterSettings.java | 27 +++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java +index eadb726bf63b..2b515c9b5cd1 100644 +--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java ++++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java +@@ -64,6 +64,14 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { + * @hide + */ + public static final int DEFAULT_DESTINATION_PORT = DESTINATION_PORT_ANY; ++ /** ++ * @hide ++ */ ++ public static final int MAX_STRING_LENGTH = 256; ++ /** ++ * @hide ++ */ ++ public static final int MAX_LIST_SIZE = 100; + + /** + * Builder class for {@link VisualVoicemailSmsFilterSettings} objects. +@@ -82,11 +90,16 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { + /** + * Sets the client prefix for the visual voicemail SMS filter. The client prefix will appear + * at the start of a visual voicemail SMS message, followed by a colon(:). ++ * @throws IllegalArgumentException if the string length is greater than 256 characters + */ + public Builder setClientPrefix(String clientPrefix) { + if (clientPrefix == null) { + throw new IllegalArgumentException("Client prefix cannot be null"); + } ++ if (clientPrefix.length() > MAX_STRING_LENGTH) { ++ throw new IllegalArgumentException("Client prefix cannot be greater than " ++ + MAX_STRING_LENGTH + " characters"); ++ } + mClientPrefix = clientPrefix; + return this; + } +@@ -95,11 +108,25 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { + * Sets the originating number allow list for the visual voicemail SMS filter. If the list + * is not null only the SMS messages from a number in the list can be considered as a visual + * voicemail SMS. Otherwise, messages from any address will be considered. ++ * @throws IllegalArgumentException if the size of the originatingNumbers list is greater ++ * than 100 elements ++ * @throws IllegalArgumentException if an element within the originatingNumbers list has ++ * a string length greater than 256 + */ + public Builder setOriginatingNumbers(List originatingNumbers) { + if (originatingNumbers == null) { + throw new IllegalArgumentException("Originating numbers cannot be null"); + } ++ if (originatingNumbers.size() > MAX_LIST_SIZE) { ++ throw new IllegalArgumentException("The originatingNumbers list size cannot be" ++ + " greater than " + MAX_STRING_LENGTH + " elements"); ++ } ++ for (String num : originatingNumbers) { ++ if (num != null && num.length() > MAX_STRING_LENGTH) { ++ throw new IllegalArgumentException("Numbers within the originatingNumbers list" ++ + " cannot be greater than" + MAX_STRING_LENGTH + " characters"); ++ } ++ } + mOriginatingNumbers = originatingNumbers; + return this; + } +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/base/0014-Ensure-group-summary-and-any-notifications-added-directly-by-NM.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0014-Ensure-group-summary-and-any-notifications-added-directly-by-NM.bulletin.patch new file mode 100644 index 0000000000..87740f46f3 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0014-Ensure-group-summary-and-any-notifications-added-directly-by-NM.bulletin.patch @@ -0,0 +1,80 @@ +From 92b1da4e4c657d73ad10fdf21ad1729f654be1a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= +Date: Mon, 24 Jun 2024 18:43:59 +0200 +Subject: [PATCH] Ensure group summary (and any notifications added directly by + NMS) have the correct token + +All notifications must have the same token so that their serialization works as intended. + +Bug: 328254922 +Bug: 305695605 +Bug: 346360609 +Flag: android.app.secure_allowlist_token +Test: atest NotificationManagerServiceTest +(cherry picked from commit c18c614aec9e5345caab70446f058d8706185776) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:faba96efff401d77243a3f257fb12512a8efe379) +Merged-In: I26784a729506169b3fe8481094cc4f5ab7b8a92b +Change-Id: I26784a729506169b3fe8481094cc4f5ab7b8a92b +--- + .../NotificationManagerService.java | 10 ++++---- + .../NotificationManagerServiceTest.java | 23 +++++++++++++++++++ + 2 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java +index b15fcc917588..d289c50dff41 100644 +--- a/services/core/java/com/android/server/notification/NotificationManagerService.java ++++ b/services/core/java/com/android/server/notification/NotificationManagerService.java +@@ -8863,10 +8863,12 @@ public class NotificationManagerService extends SystemService { + */ + private boolean enqueueNotification() { + synchronized (mNotificationLock) { +- // allowlistToken is populated by unparceling, so it will be absent if the +- // EnqueueNotificationRunnable is created directly by NMS (as we do for group +- // summaries) instead of via notify(). Fix that. +- r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN); ++ if (android.app.Flags.secureAllowlistToken()) { ++ // allowlistToken is populated by unparceling, so it will be absent if the ++ // EnqueueNotificationRunnable is created directly by NMS (as we do for group ++ // summaries) instead of via notify(). Fix that. ++ r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN); ++ } + + final long snoozeAt = + mSnoozeHelper.getSnoozeTimeForUnpostedNotification( +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index 130690d80b70..58ce5fda4e79 100644 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -14331,6 +14331,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); + } + ++ @Test ++ @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) ++ public void enqueueNotification_directlyThroughRunnable_populatesAllowlistToken() { ++ Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) ++ .setContentIntent(createPendingIntent("content")) ++ .build(); ++ NotificationRecord record = new NotificationRecord( ++ mContext, ++ new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 44, receivedWithoutParceling, ++ mUser, "groupKey", 0), ++ mTestNotificationChannel); ++ assertThat(record.getNotification().getAllowlistToken()).isNull(); ++ ++ mWorkerHandler.post( ++ mService.new EnqueueNotificationRunnable(mUserId, record, false, false, ++ mPostNotificationTrackerFactory.newTracker(null))); ++ waitForIdle(); ++ ++ assertThat(mService.mNotificationList).hasSize(1); ++ assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) ++ .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); ++ } ++ + @Test + public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible() + throws Exception { +-- +2.34.1 + diff --git a/aosp_diff/preliminary/frameworks/base/0015-Inline-SECURE_ALLOWLIST_TOKEN.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0015-Inline-SECURE_ALLOWLIST_TOKEN.bulletin.patch new file mode 100644 index 0000000000..a2d2b36fda --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0015-Inline-SECURE_ALLOWLIST_TOKEN.bulletin.patch @@ -0,0 +1,200 @@ +From b8a1a5d47c3916fe08deefaefd8772092b4fb03c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= +Date: Tue, 3 Sep 2024 18:48:33 +0200 +Subject: [PATCH] Inline SECURE_ALLOWLIST_TOKEN + +Bug: 328254922 +Bug: 305695605 +Test: atest NotificationManagerServiceTest +Flag: EXEMPT removing flag :) +(cherry picked from commit a926ac791b2cab8617d6ad99058f28c91711fdf0) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:877a8de71a9c9c6eb560f137df1a20eb30e8ab69) +Merged-In: Ife35a1f51a511cd199ee6aeac4b476ef860547a5 +Change-Id: Ife35a1f51a511cd199ee6aeac4b476ef860547a5 +--- + core/java/android/app/Notification.java | 53 +++++++------------ + .../NotificationManagerService.java | 26 ++++----- + .../NotificationManagerServiceTest.java | 6 --- + 3 files changed, 30 insertions(+), 55 deletions(-) + +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java +index a1fa4047f839..08c62b7541b4 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -2678,14 +2678,9 @@ public class Notification implements Parcelable + if (mAllowlistToken == null) { + mAllowlistToken = processAllowlistToken; + } +- if (Flags.secureAllowlistToken()) { +- // Propagate this token to all pending intents that are unmarshalled from the parcel, +- // or keep the one we're already propagating, if that's the case. +- if (!parcel.hasClassCookie(PendingIntent.class)) { +- parcel.setClassCookie(PendingIntent.class, mAllowlistToken); +- } +- } else { +- // Propagate this token to all pending intents that are unmarshalled from the parcel. ++ // Propagate this token to all pending intents that are unmarshalled from the parcel, ++ // or keep the one we're already propagating, if that's the case. ++ if (!parcel.hasClassCookie(PendingIntent.class)) { + parcel.setClassCookie(PendingIntent.class, mAllowlistToken); + } + +@@ -3301,28 +3296,22 @@ public class Notification implements Parcelable + PendingIntent.addOnMarshaledListener(addedListener); + } + try { +- if (Flags.secureAllowlistToken()) { +- boolean mustClearCookie = false; +- if (!parcel.hasClassCookie(Notification.class)) { +- // This is the "root" notification, and not an "inner" notification (including +- // publicVersion or anything else that might be embedded in extras). So we want +- // to use its token for every inner notification (might be null). +- parcel.setClassCookie(Notification.class, mAllowlistToken); +- mustClearCookie = true; +- } +- try { +- // IMPORTANT: Add marshaling code in writeToParcelImpl as we +- // want to intercept all pending events written to the parcel. +- writeToParcelImpl(parcel, flags); +- } finally { +- if (mustClearCookie) { +- parcel.removeClassCookie(Notification.class, mAllowlistToken); +- } +- } +- } else { ++ boolean mustClearCookie = false; ++ if (!parcel.hasClassCookie(Notification.class)) { ++ // This is the "root" notification, and not an "inner" notification (including ++ // publicVersion or anything else that might be embedded in extras). So we want ++ // to use its token for every inner notification (might be null). ++ parcel.setClassCookie(Notification.class, mAllowlistToken); ++ mustClearCookie = true; ++ } ++ try { + // IMPORTANT: Add marshaling code in writeToParcelImpl as we + // want to intercept all pending events written to the parcel. + writeToParcelImpl(parcel, flags); ++ } finally { ++ if (mustClearCookie) { ++ parcel.removeClassCookie(Notification.class, mAllowlistToken); ++ } + } + + synchronized (this) { +@@ -3339,13 +3328,9 @@ public class Notification implements Parcelable + private void writeToParcelImpl(Parcel parcel, int flags) { + parcel.writeInt(1); + +- if (Flags.secureAllowlistToken()) { +- // Always use the same token as the root notification (might be null). +- IBinder rootNotificationToken = (IBinder) parcel.getClassCookie(Notification.class); +- parcel.writeStrongBinder(rootNotificationToken); +- } else { +- parcel.writeStrongBinder(mAllowlistToken); +- } ++ // Always use the same token as the root notification (might be null). ++ IBinder rootNotificationToken = (IBinder) parcel.getClassCookie(Notification.class); ++ parcel.writeStrongBinder(rootNotificationToken); + + parcel.writeLong(when); + parcel.writeLong(creationTime); +diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java +index b4f2d6e2d389..31bc4ed3a1ed 100644 +--- a/services/core/java/com/android/server/notification/NotificationManagerService.java ++++ b/services/core/java/com/android/server/notification/NotificationManagerService.java +@@ -7374,16 +7374,14 @@ public class NotificationManagerService extends SystemService { + + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId); + } + +- if (android.app.Flags.secureAllowlistToken()) { +- IBinder allowlistToken = notification.getAllowlistToken(); +- if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) { +- throw new SecurityException( +- "Unexpected allowlist token received from " + callingUid); +- } +- // allowlistToken is populated by unparceling, so it can be null if the notification was +- // posted from inside system_server. Ensure it's the expected value. +- notification.overrideAllowlistToken(ALLOWLIST_TOKEN); ++ IBinder allowlistToken = notification.getAllowlistToken(); ++ if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) { ++ throw new SecurityException( ++ "Unexpected allowlist token received from " + callingUid); + } ++ // allowlistToken is populated by unparceling, so it can be null if the notification was ++ // posted from inside system_server. Ensure it's the expected value. ++ notification.overrideAllowlistToken(ALLOWLIST_TOKEN); + + checkRestrictedCategories(notification); + +@@ -8523,12 +8521,10 @@ public class NotificationManagerService extends SystemService { + */ + private boolean enqueueNotification() { + synchronized (mNotificationLock) { +- if (android.app.Flags.secureAllowlistToken()) { +- // allowlistToken is populated by unparceling, so it will be absent if the +- // EnqueueNotificationRunnable is created directly by NMS (as we do for group +- // summaries) instead of via notify(). Fix that. +- r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN); +- } ++ // allowlistToken is populated by unparceling, so it will be absent if the ++ // EnqueueNotificationRunnable is created directly by NMS (as we do for group ++ // summaries) instead of via notify(). Fix that. ++ r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN); + + final long snoozeAt = + mSnoozeHelper.getSnoozeTimeForUnpostedNotification( +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index 5381b45cbd8c..fda54a46b4c8 100644 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -14295,7 +14295,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + } + + @Test +- @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) + public void enqueueNotification_acceptsCorrectToken() throws RemoteException { + Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setContentIntent(createPendingIntent("content")) +@@ -14314,7 +14313,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + } + + @Test +- @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) + public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException { + Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setContentIntent(createPendingIntent("content")) +@@ -14331,7 +14329,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + } + + @Test +- @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) + public void enqueueNotification_directlyThroughRunnable_populatesAllowlistToken() { + Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setContentIntent(createPendingIntent("content")) +@@ -14354,7 +14351,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + } + + @Test +- @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) + public void enqueueNotification_rejectsOtherToken() throws RemoteException { + Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setContentIntent(createPendingIntent("content")) +@@ -14372,7 +14368,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + } + + @Test +- @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) + public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents() + throws RemoteException { + Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) +@@ -14578,7 +14573,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + + @Test + @SuppressWarnings("unchecked") +- @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) + public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException { + Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setContentIntent(createPendingIntent("content")) +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/base/0016-Update-checkKeyIntent.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0016-Update-checkKeyIntent.bulletin.patch new file mode 100644 index 0000000000..f08b95d5b6 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0016-Update-checkKeyIntent.bulletin.patch @@ -0,0 +1,54 @@ +From 5018e2273cb3156dee81cf372d221ba49d65d1e7 Mon Sep 17 00:00:00 2001 +From: Dmitry Dementyev +Date: Tue, 1 Oct 2024 14:57:44 -0700 +Subject: [PATCH] Update checkKeyIntent + +1) Explicityly set component after target activity check. +2) Update Intent subclass check. + +Bug: 360846772 +Test: manual +Flag: EXEMPT bugfix +(cherry picked from commit cde345a7ee06db716e613e12a2c218ce248ad1c4) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0397dd35e6cc696b0ea3949c5d29f90b42a0ce59) +Merged-In: Ied7961c73299681aa5b523cf3f00fd905893116f +Change-Id: Ied7961c73299681aa5b523cf3f00fd905893116f +--- + .../android/server/accounts/AccountManagerService.java | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java +index 458749d93e0a..71f99adc8bb9 100644 +--- a/services/core/java/com/android/server/accounts/AccountManagerService.java ++++ b/services/core/java/com/android/server/accounts/AccountManagerService.java +@@ -5067,6 +5067,8 @@ public class AccountManagerService + Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType)); + return false; + } ++ intent.setComponent(targetActivityInfo.getComponentName()); ++ bundle.putParcelable(AccountManager.KEY_INTENT, intent); + return true; + } finally { + Binder.restoreCallingIdentity(bid); +@@ -5088,14 +5090,15 @@ public class AccountManagerService + Bundle simulateBundle = p.readBundle(); + p.recycle(); + Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class); +- if (intent != null && intent.getClass() != Intent.class) { +- return false; +- } + Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT, + Intent.class); + if (intent == null) { + return (simulateIntent == null); + } ++ if (intent.getClass() != Intent.class || simulateIntent.getClass() != Intent.class) { ++ return false; ++ } ++ + if (!intent.filterEquals(simulateIntent)) { + return false; + } +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/base/0017-Limit-the-size-of-vibration-effects-stored-on-a-NotificationChan.patch b/aosp_diff/preliminary/frameworks/base/0017-Limit-the-size-of-vibration-effects-stored-on-a-NotificationChan.patch new file mode 100644 index 0000000000..9e0a0f3320 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0017-Limit-the-size-of-vibration-effects-stored-on-a-NotificationChan.patch @@ -0,0 +1,63 @@ +From 8949e1ea261a8ffe7d5c736808b1e3fa36ee3731 Mon Sep 17 00:00:00 2001 +From: Yuri Lin +Date: Thu, 22 Aug 2024 18:18:43 -0400 +Subject: [PATCH] Limit the size of vibration effects stored on a + NotificationChannel + +This change adds a cropToLengthOrNull() @hide method to the VibrationEffect interface, implemented only by compositions, to provide a best-effort crop of the number of segments involved in a vibration effect. + +For notification channels, changes the max vibration length to 500 from 1000. We probably don't need that much space, and serializing vibration effects means that the data ends up taking up a lot more space than just the array for the vibration pattern. + +Adds android.app.notif_channel_crop_vibration_effects bugfix flag that limits when we attempt to crop the vibration effects. + +Bug: 345881518 +Test: manual with flag on/off; NotificationChannelTest; VibrationEffectTest +Flag: android.app.notif_channel_crop_vibration_effects (inlined for security backport) +(cherry picked from commit 1181fd1b6769e6f093cd409e2b9f7aa0f91d7ed9) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:dd6c8b4b334af950f7c26d7b8be2e052b2667ea6) +Merged-In: I885f733112af89fe9f255db626fcdc297b1a18c8 +Change-Id: I885f733112af89fe9f255db626fcdc297b1a18c8 +--- + .../android/app/NotificationChannelTest.java | 26 +++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/core/tests/coretests/src/android/app/NotificationChannelTest.java b/core/tests/coretests/src/android/app/NotificationChannelTest.java +index e19f887c1284..87b22e089ef0 100644 +--- a/core/tests/coretests/src/android/app/NotificationChannelTest.java ++++ b/core/tests/coretests/src/android/app/NotificationChannelTest.java +@@ -279,6 +279,32 @@ public class NotificationChannelTest { + .isEqualTo(result.getVibrationPattern()); + } + ++ @Test ++ @EnableFlags(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) ++ public void testLongVibrationFields_canWriteToXml() throws Exception { ++ NotificationChannel channel = new NotificationChannel("id", "name", 3); ++ // populate pattern with contents ++ long[] pattern = new long[65550 / 2]; ++ for (int i = 0; i < pattern.length; i++) { ++ pattern[i] = 100; ++ } ++ channel.setVibrationPattern(pattern); // with flag on, also sets effect ++ ++ // Send it through parceling & unparceling to simulate being passed through a binder call ++ NotificationChannel fromParcel = writeToAndReadFromParcel(channel); ++ assertThat(fromParcel.getVibrationPattern().length).isEqualTo( ++ NotificationChannel.MAX_VIBRATION_LENGTH); ++ ++ // Confirm that this also survives writing to & restoring from XML ++ NotificationChannel result = backUpAndRestore(fromParcel); ++ assertThat(result.getVibrationPattern().length).isEqualTo( ++ NotificationChannel.MAX_VIBRATION_LENGTH); ++ assertThat(result.getVibrationEffect()).isNotNull(); ++ assertThat(result.getVibrationEffect() ++ .computeCreateWaveformOffOnTimingsOrNull()) ++ .isEqualTo(result.getVibrationPattern()); ++ } ++ + @Test + public void testRestoreSoundUri_customLookup() throws Exception { + Uri uriToBeRestoredUncanonicalized = Uri.parse("content://media/1"); +-- +2.34.1 + diff --git a/aosp_diff/preliminary/frameworks/base/0018-Pass-SafeActivityOptions-with-actual-caller-for-startActivityInT.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0018-Pass-SafeActivityOptions-with-actual-caller-for-startActivityInT.bulletin.patch new file mode 100644 index 0000000000..31ef16375c --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0018-Pass-SafeActivityOptions-with-actual-caller-for-startActivityInT.bulletin.patch @@ -0,0 +1,71 @@ +From 4b2a235c895c0ea593d21d0b057a502879ecd449 Mon Sep 17 00:00:00 2001 +From: Chris Li +Date: Wed, 9 Oct 2024 01:50:57 +0000 +Subject: [PATCH] Pass SafeActivityOptions with actual caller for + startActivityInTF + +We clearCallingUid before apply the WCT, but SafeActivityOptions will +query the Binder Uid when construct. Update to pass in the actual +caller. + +Flag: EXEMPT bug fix +Bug: 369103643 +Test: atest WmTests:WindowOrganizerTests# + testStartActivityInTaskFragment_checkCallerPermission +(cherry picked from commit 20c568e77eae5d469cd5e594b644d8645d830dbd) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:31d655813075ed45f934080d1743231c3b75a0d2) +Merged-In: I873ae576de0bc4a7402c2f522b45853bce48a0c5 +Change-Id: I873ae576de0bc4a7402c2f522b45853bce48a0c5 +--- + .../java/com/android/server/wm/ActivityStartController.java | 5 ++--- + .../com/android/server/wm/WindowOrganizerController.java | 4 +++- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java +index 0e401ebc94b5..c4d06acdce48 100644 +--- a/services/core/java/com/android/server/wm/ActivityStartController.java ++++ b/services/core/java/com/android/server/wm/ActivityStartController.java +@@ -43,7 +43,6 @@ import android.content.pm.ApplicationInfo; + import android.content.pm.PackageManager; + import android.content.pm.ResolveInfo; + import android.os.Binder; +-import android.os.Bundle; + import android.os.IBinder; + import android.os.Trace; + import android.os.UserHandle; +@@ -550,14 +549,14 @@ public class ActivityStartController { + * Starts an activity in the TaskFragment. + * @param taskFragment TaskFragment {@link TaskFragment} to start the activity in. + * @param activityIntent intent to start the activity. +- * @param activityOptions ActivityOptions to start the activity with. ++ * @param activityOptions SafeActivityOptions to start the activity with. + * @param resultTo the caller activity + * @param callingUid the caller uid + * @param callingPid the caller pid + * @return the start result. + */ + int startActivityInTaskFragment(@NonNull TaskFragment taskFragment, +- @NonNull Intent activityIntent, @Nullable Bundle activityOptions, ++ @NonNull Intent activityIntent, @Nullable SafeActivityOptions activityOptions, + @Nullable IBinder resultTo, int callingUid, int callingPid, + @Nullable IBinder errorCallbackToken) { + final ActivityRecord caller = +diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java +index edab5605ab8f..a3b6dae29b33 100644 +--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java ++++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java +@@ -1403,8 +1403,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + final IBinder callerActivityToken = operation.getActivityToken(); + final Intent activityIntent = operation.getActivityIntent(); + final Bundle activityOptions = operation.getBundle(); ++ final SafeActivityOptions safeOptions = ++ SafeActivityOptions.fromBundle(activityOptions, caller.mPid, caller.mUid); + final int result = waitAsyncStart(() -> mService.getActivityStartController() +- .startActivityInTaskFragment(taskFragment, activityIntent, activityOptions, ++ .startActivityInTaskFragment(taskFragment, activityIntent, safeOptions, + callerActivityToken, caller.mUid, caller.mPid, + errorCallbackToken)); + if (!isStartResultSuccessful(result)) { +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/base/0019-CDM-Check-if-it-s-system-UID-for-hidden-Perm-Sync-APIs.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0019-CDM-Check-if-it-s-system-UID-for-hidden-Perm-Sync-APIs.bulletin.patch new file mode 100644 index 0000000000..ef1c16c7db --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0019-CDM-Check-if-it-s-system-UID-for-hidden-Perm-Sync-APIs.bulletin.patch @@ -0,0 +1,48 @@ +From 076a97aa32492cc44e863f7ab75494dc0b3bf5ef Mon Sep 17 00:00:00 2001 +From: Guojing Yuan +Date: Tue, 22 Oct 2024 17:06:48 +0000 +Subject: [PATCH] [CDM] Check if it's system UID for hidden Perm Sync APIs + +Bug: 371975420 +Test: Manual test +Flag: EXEMPT bugfix +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:08f57da9e39869f696de4225197530aa2b9187e8) +Merged-In: I9771ce38728d40b026d94cb6785d55f144c66790 +Change-Id: I9771ce38728d40b026d94cb6785d55f144c66790 +--- + .../server/companion/CompanionDeviceManagerService.java | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +index 0ab6bbc3e0d3..57eadf65f2a0 100644 +--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java ++++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +@@ -628,16 +628,25 @@ public class CompanionDeviceManagerService extends SystemService { + + @Override + public void enablePermissionsSync(int associationId) { ++ if (getCallingUid() != SYSTEM_UID) { ++ throw new SecurityException("Caller must be system UID"); ++ } + mSystemDataTransferProcessor.enablePermissionsSync(associationId); + } + + @Override + public void disablePermissionsSync(int associationId) { ++ if (getCallingUid() != SYSTEM_UID) { ++ throw new SecurityException("Caller must be system UID"); ++ } + mSystemDataTransferProcessor.disablePermissionsSync(associationId); + } + + @Override + public PermissionSyncRequest getPermissionSyncRequest(int associationId) { ++ if (getCallingUid() != SYSTEM_UID) { ++ throw new SecurityException("Caller must be system UID"); ++ } + return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + } + +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/base/0020-Always-show-all-approved-apps.bulletin.patch b/aosp_diff/preliminary/frameworks/base/0020-Always-show-all-approved-apps.bulletin.patch new file mode 100644 index 0000000000..5bc3e0da31 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/0020-Always-show-all-approved-apps.bulletin.patch @@ -0,0 +1,201 @@ +From 3b2be226f1b944faad1fb7bf2ecda55fa4ac8c50 Mon Sep 17 00:00:00 2001 +From: Julia Reynolds +Date: Mon, 7 Oct 2024 11:10:31 -0400 +Subject: [PATCH] Always show all approved apps + +Regardless of what the current criteria is in order to be approved, +show everything that's currently approved, since the criteria might +have been more lax when it was approved + +Test: manual +Test: ServiceListingTest +Flag: EXEMPT bug fix +Bug: 365738306 +(cherry picked from commit 234c5e843ca427b1dd47e91e3969f3309dd787bf) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3c44dd35fd99b87e8754a2c67f29b221ef3f69a5) +Merged-In: I6c19d3dbff6ecabc74729a7f021f293e26601944 +Change-Id: I6c19d3dbff6ecabc74729a7f021f293e26601944 +--- + .../applications/ServiceListing.java | 32 ++++++--- + .../applications/ServiceListingTest.java | 66 ++++++++++++++++++- + 2 files changed, 88 insertions(+), 10 deletions(-) + +diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java +index c8bcabff1094..261c722e517c 100644 +--- a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java ++++ b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java +@@ -138,23 +138,37 @@ public class ServiceListing { + } + + final PackageManager pmWrapper = mContext.getPackageManager(); ++ // Add requesting apps, with full validation + List installedServices = pmWrapper.queryIntentServicesAsUser( + new Intent(mIntentAction), flags, user); + for (ResolveInfo resolveInfo : installedServices) { + ServiceInfo info = resolveInfo.serviceInfo; + +- if (!mPermission.equals(info.permission)) { +- Slog.w(mTag, "Skipping " + mNoun + " service " +- + info.packageName + "/" + info.name +- + ": it does not require the permission " +- + mPermission); +- continue; ++ if (!mEnabledServices.contains(info.getComponentName())) { ++ if (!mPermission.equals(info.permission)) { ++ Slog.w(mTag, "Skipping " + mNoun + " service " ++ + info.packageName + "/" + info.name ++ + ": it does not require the permission " ++ + mPermission); ++ continue; ++ } ++ if (mValidator != null && !mValidator.test(info)) { ++ continue; ++ } ++ mServices.add(info); + } +- if (mValidator != null && !mValidator.test(info)) { +- continue; ++ } ++ ++ // Add all apps with access, in case prior approval was granted without full validation ++ for (ComponentName cn : mEnabledServices) { ++ List enabledServices = pmWrapper.queryIntentServicesAsUser( ++ new Intent().setComponent(cn), flags, user); ++ for (ResolveInfo resolveInfo : enabledServices) { ++ ServiceInfo info = resolveInfo.serviceInfo; ++ mServices.add(info); + } +- mServices.add(info); + } ++ + for (Callback callback : mCallbacks) { + callback.onServicesReloaded(mServices); + } +diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java +index 7ff0988c494d..feef559dfe26 100644 +--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java ++++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java +@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; + import static org.mockito.ArgumentMatchers.anyInt; + import static org.mockito.ArgumentMatchers.anyList; ++import static org.mockito.ArgumentMatchers.argThat; + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.spy; + import static org.mockito.Mockito.times; +@@ -29,6 +30,7 @@ import static org.mockito.Mockito.when; + + import android.content.ComponentName; + import android.content.Context; ++import android.content.Intent; + import android.content.pm.PackageManager; + import android.content.pm.ResolveInfo; + import android.content.pm.ServiceInfo; +@@ -42,6 +44,7 @@ import org.junit.Before; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.mockito.ArgumentCaptor; ++import org.mockito.ArgumentMatcher; + import org.robolectric.RobolectricTestRunner; + import org.robolectric.RuntimeEnvironment; + +@@ -72,19 +75,26 @@ public class ServiceListingTest { + .build(); + } + ++ private ArgumentMatcher filterEquals(Intent intent) { ++ return (test) -> { ++ return intent.filterEquals(test); ++ }; ++ } ++ + @Test + public void testValidator() { + ServiceInfo s1 = new ServiceInfo(); + s1.permission = "testPermission"; + s1.packageName = "pkg"; ++ s1.name = "Service1"; + ServiceInfo s2 = new ServiceInfo(); + s2.permission = "testPermission"; + s2.packageName = "pkg2"; ++ s2.name = "service2"; + ResolveInfo r1 = new ResolveInfo(); + r1.serviceInfo = s1; + ResolveInfo r2 = new ResolveInfo(); + r2.serviceInfo = s2; +- + when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn( + ImmutableList.of(r1, r2)); + +@@ -118,9 +128,11 @@ public class ServiceListingTest { + ServiceInfo s1 = new ServiceInfo(); + s1.permission = "testPermission"; + s1.packageName = "pkg"; ++ s1.name = "Service1"; + ServiceInfo s2 = new ServiceInfo(); + s2.permission = "testPermission"; + s2.packageName = "pkg2"; ++ s2.name = "service2"; + ResolveInfo r1 = new ResolveInfo(); + r1.serviceInfo = s1; + ResolveInfo r2 = new ResolveInfo(); +@@ -193,4 +205,56 @@ public class ServiceListingTest { + assertThat(Settings.Secure.getString(RuntimeEnvironment.application.getContentResolver(), + TEST_SETTING)).contains(testComponent2.flattenToString()); + } ++ ++ @Test ++ public void testHasPermissionWithoutMeetingCurrentRegs() { ++ ServiceInfo s1 = new ServiceInfo(); ++ s1.permission = "testPermission"; ++ s1.packageName = "pkg"; ++ s1.name = "Service1"; ++ ServiceInfo s2 = new ServiceInfo(); ++ s2.permission = "testPermission"; ++ s2.packageName = "pkg2"; ++ s2.name = "service2"; ++ ResolveInfo r1 = new ResolveInfo(); ++ r1.serviceInfo = s1; ++ ResolveInfo r2 = new ResolveInfo(); ++ r2.serviceInfo = s2; ++ ++ ComponentName approvedComponent = new ComponentName(s2.packageName, s2.name); ++ ++ Settings.Secure.putString( ++ mContext.getContentResolver(), TEST_SETTING, approvedComponent.flattenToString()); ++ ++ when(mPm.queryIntentServicesAsUser(argThat( ++ filterEquals(new Intent(TEST_INTENT))), anyInt(), anyInt())) ++ .thenReturn(ImmutableList.of(r1)); ++ when(mPm.queryIntentServicesAsUser(argThat( ++ filterEquals(new Intent().setComponent(approvedComponent))), ++ anyInt(), anyInt())) ++ .thenReturn(ImmutableList.of(r2)); ++ ++ mServiceListing = new ServiceListing.Builder(mContext) ++ .setTag("testTag") ++ .setSetting(TEST_SETTING) ++ .setNoun("testNoun") ++ .setIntentAction(TEST_INTENT) ++ .setValidator(info -> { ++ if (info.packageName.equals("pkg")) { ++ return true; ++ } ++ return false; ++ }) ++ .setPermission("testPermission") ++ .build(); ++ ServiceListing.Callback callback = mock(ServiceListing.Callback.class); ++ mServiceListing.addCallback(callback); ++ mServiceListing.reload(); ++ ++ verify(mPm, times(2)).queryIntentServicesAsUser(any(), anyInt(), anyInt()); ++ ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); ++ verify(callback, times(1)).onServicesReloaded(captor.capture()); ++ ++ assertThat(captor.getValue()).containsExactlyElementsIn(ImmutableList.of(s2, s1)); ++ } + } +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/native/01_0001-Use-BRGA-as-default-format-for-software-rendering.patch b/aosp_diff/preliminary/frameworks/native/0001-Use-BRGA-as-default-format-for-software-rendering.patch similarity index 100% rename from aosp_diff/preliminary/frameworks/native/01_0001-Use-BRGA-as-default-format-for-software-rendering.patch rename to aosp_diff/preliminary/frameworks/native/0001-Use-BRGA-as-default-format-for-software-rendering.patch diff --git a/aosp_diff/preliminary/frameworks/native/03_0003-InputDevice-Use-location-for-idc-file.patch b/aosp_diff/preliminary/frameworks/native/0002-InputDevice-Use-location-for-idc-file.patch similarity index 100% rename from aosp_diff/preliminary/frameworks/native/03_0003-InputDevice-Use-location-for-idc-file.patch rename to aosp_diff/preliminary/frameworks/native/0002-InputDevice-Use-location-for-idc-file.patch diff --git a/aosp_diff/preliminary/frameworks/native/0003-binder-fix-FD-handling-in-continueWrite.bulletin.patch b/aosp_diff/preliminary/frameworks/native/0003-binder-fix-FD-handling-in-continueWrite.bulletin.patch new file mode 100644 index 0000000000..605dee129b --- /dev/null +++ b/aosp_diff/preliminary/frameworks/native/0003-binder-fix-FD-handling-in-continueWrite.bulletin.patch @@ -0,0 +1,389 @@ +From b3cdb06ab9137a67e4ee212ae6655de383fdaaaa Mon Sep 17 00:00:00 2001 +From: Frederick Mayle +Date: Mon, 30 Sep 2024 17:42:45 -0700 +Subject: [PATCH] binder: fix FD handling in continueWrite + +Only close FDs within the truncated part of the parcel. + +This change also fixes a bug where a parcel truncated into the middle of +an object would not properly free that object. That could have resulted +in an OOB access in `Parcel::truncateRpcObjects`, so more bounds +checking is added. + +The new tests show how to reproduce the bug by appending to or partially +truncating Parcels owned by the kernel. Two cases are disabled because +of a bug in the Parcel fdsan code (b/370824489). + +Flag: EXEMPT bugfix +Ignore-AOSP-First: security fix +Bug: 239222407, 359179312 +Test: atest binderLibTest +(cherry picked from commit f2163b846228ded7187358048efb20681614779e) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:43b5be7f2e1ef4fb6ddaaf5081d4102a5eab2a43) +Merged-In: Iadf7e2e98e3eb97c56ec2fed2b49d1e6492af9a3 +Change-Id: Iadf7e2e98e3eb97c56ec2fed2b49d1e6492af9a3 +--- + libs/binder/Parcel.cpp | 66 ++++++++++-- + libs/binder/include/binder/Parcel.h | 6 +- + libs/binder/tests/binderLibTest.cpp | 155 ++++++++++++++++++++++++++++ + 3 files changed, 213 insertions(+), 14 deletions(-) + +diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp +index 3f70e8c104..564f81e6e0 100644 +--- a/libs/binder/Parcel.cpp ++++ b/libs/binder/Parcel.cpp +@@ -2671,14 +2671,14 @@ const flat_binder_object* Parcel::readObject(bool nullMetaData) const + } + #endif // BINDER_WITH_KERNEL_IPC + +-void Parcel::closeFileDescriptors() { ++void Parcel::closeFileDescriptors(size_t newObjectsSize) { + if (auto* kernelFields = maybeKernelFields()) { + #ifdef BINDER_WITH_KERNEL_IPC + size_t i = kernelFields->mObjectsSize; + if (i > 0) { + // ALOGI("Closing file descriptors for %zu objects...", i); + } +- while (i > 0) { ++ while (i > newObjectsSize) { + i--; + const flat_binder_object* flat = + reinterpret_cast(mData + kernelFields->mObjects[i]); +@@ -2689,6 +2689,7 @@ void Parcel::closeFileDescriptors() { + } + } + #else // BINDER_WITH_KERNEL_IPC ++ (void)newObjectsSize; + LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); + #endif // BINDER_WITH_KERNEL_IPC + } else if (auto* rpcFields = maybeRpcFields()) { +@@ -2913,7 +2914,7 @@ void Parcel::freeDataNoInit() + //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); + auto* kernelFields = maybeKernelFields(); + // Close FDs before freeing, otherwise they will leak for kernel binder. +- closeFileDescriptors(); ++ closeFileDescriptors(/*newObjectsSize=*/0); + mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, + kernelFields ? kernelFields->mObjectsSize : 0); + } else { +@@ -3042,13 +3043,38 @@ status_t Parcel::continueWrite(size_t desired) + objectsSize = 0; + } else { + if (kernelFields) { ++#ifdef BINDER_WITH_KERNEL_IPC ++ validateReadData(mDataSize); // hack to sort the objects + while (objectsSize > 0) { +- if (kernelFields->mObjects[objectsSize - 1] < desired) break; ++ if (kernelFields->mObjects[objectsSize - 1] + sizeof(flat_binder_object) <= ++ desired) ++ break; + objectsSize--; + } ++#endif // BINDER_WITH_KERNEL_IPC + } else { + while (objectsSize > 0) { +- if (rpcFields->mObjectPositions[objectsSize - 1] < desired) break; ++ // Object size varies by type. ++ uint32_t pos = rpcFields->mObjectPositions[objectsSize - 1]; ++ size_t size = sizeof(RpcFields::ObjectType); ++ uint32_t minObjectEnd; ++ if (__builtin_add_overflow(pos, sizeof(RpcFields::ObjectType), &minObjectEnd) || ++ minObjectEnd > mDataSize) { ++ return BAD_VALUE; ++ } ++ const auto type = *reinterpret_cast(mData + pos); ++ switch (type) { ++ case RpcFields::TYPE_BINDER_NULL: ++ break; ++ case RpcFields::TYPE_BINDER: ++ size += sizeof(uint64_t); // address ++ break; ++ case RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR: ++ size += sizeof(int32_t); // fd index ++ break; ++ } ++ ++ if (pos + size <= desired) break; + objectsSize--; + } + } +@@ -3097,15 +3123,24 @@ status_t Parcel::continueWrite(size_t desired) + if (mData) { + memcpy(data, mData, mDataSize < desired ? mDataSize : desired); + } ++#ifdef BINDER_WITH_KERNEL_IPC + if (objects && kernelFields && kernelFields->mObjects) { + memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t)); ++ // All FDs are owned when `mOwner`, even when `cookie == 0`. When ++ // we switch to `!mOwner`, we need to explicitly mark the FDs as ++ // owned. ++ for (size_t i = 0; i < objectsSize; i++) { ++ flat_binder_object* flat = reinterpret_cast(data + objects[i]); ++ if (flat->hdr.type == BINDER_TYPE_FD) { ++ flat->cookie = 1; ++ } ++ } + } + // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); + if (kernelFields) { +- // TODO(b/239222407): This seems wrong. We should only free FDs when +- // they are in a truncated section of the parcel. +- closeFileDescriptors(); ++ closeFileDescriptors(objectsSize); + } ++#endif // BINDER_WITH_KERNEL_IPC + mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, + kernelFields ? kernelFields->mObjectsSize : 0); + mOwner = nullptr; +@@ -3232,11 +3267,19 @@ status_t Parcel::truncateRpcObjects(size_t newObjectsSize) { + } + while (rpcFields->mObjectPositions.size() > newObjectsSize) { + uint32_t pos = rpcFields->mObjectPositions.back(); +- rpcFields->mObjectPositions.pop_back(); ++ uint32_t minObjectEnd; ++ if (__builtin_add_overflow(pos, sizeof(RpcFields::ObjectType), &minObjectEnd) || ++ minObjectEnd > mDataSize) { ++ return BAD_VALUE; ++ } + const auto type = *reinterpret_cast(mData + pos); + if (type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) { +- const auto fdIndex = +- *reinterpret_cast(mData + pos + sizeof(RpcFields::ObjectType)); ++ uint32_t objectEnd; ++ if (__builtin_add_overflow(minObjectEnd, sizeof(int32_t), &objectEnd) || ++ objectEnd > mDataSize) { ++ return BAD_VALUE; ++ } ++ const auto fdIndex = *reinterpret_cast(mData + minObjectEnd); + if (rpcFields->mFds == nullptr || fdIndex < 0 || + static_cast(fdIndex) >= rpcFields->mFds->size()) { + ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu", +@@ -3246,6 +3289,7 @@ status_t Parcel::truncateRpcObjects(size_t newObjectsSize) { + // In practice, this always removes the last element. + rpcFields->mFds->erase(rpcFields->mFds->begin() + fdIndex); + } ++ rpcFields->mObjectPositions.pop_back(); + } + return OK; + } +diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h +index 5cc0830c88..68c620c369 100644 +--- a/libs/binder/include/binder/Parcel.h ++++ b/libs/binder/include/binder/Parcel.h +@@ -637,9 +637,6 @@ public: + + LIBBINDER_EXPORTED const flat_binder_object* readObject(bool nullMetaData) const; + +- // Explicitly close all file descriptors in the parcel. +- LIBBINDER_EXPORTED void closeFileDescriptors(); +- + // Debugging: get metrics on current allocations. + LIBBINDER_EXPORTED static size_t getGlobalAllocSize(); + LIBBINDER_EXPORTED static size_t getGlobalAllocCount(); +@@ -652,6 +649,9 @@ public: + LIBBINDER_EXPORTED void print(std::ostream& to, uint32_t flags = 0) const; + + private: ++ // Close all file descriptors in the parcel at object positions >= newObjectsSize. ++ void closeFileDescriptors(size_t newObjectsSize); ++ + // `objects` and `objectsSize` always 0 for RPC Parcels. + typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects, + size_t objectsSize); +diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp +index 00406edcf2..509e905c7f 100644 +--- a/libs/binder/tests/binderLibTest.cpp ++++ b/libs/binder/tests/binderLibTest.cpp +@@ -44,6 +44,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -109,6 +110,8 @@ enum BinderLibTestTranscationCode { + BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, + BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, + BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION, ++ BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_OWNED_TRANSACTION, ++ BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_UNOWNED_TRANSACTION, + BINDER_LIB_TEST_EXIT_TRANSACTION, + BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION, + BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, +@@ -452,6 +455,30 @@ class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestE + }; + }; + ++ssize_t countFds() { ++ return std::distance(std::filesystem::directory_iterator("/proc/self/fd"), ++ std::filesystem::directory_iterator{}); ++} ++ ++struct FdLeakDetector { ++ int startCount; ++ ++ FdLeakDetector() { ++ // This log statement is load bearing. We have to log something before ++ // counting FDs to make sure the logging system is initialized, otherwise ++ // the sockets it opens will look like a leak. ++ ALOGW("FdLeakDetector counting FDs."); ++ startCount = countFds(); ++ } ++ ~FdLeakDetector() { ++ int endCount = countFds(); ++ if (startCount != endCount) { ++ ADD_FAILURE() << "fd count changed (" << startCount << " -> " << endCount ++ << ") fd leak?"; ++ } ++ } ++}; ++ + TEST_F(BinderLibTest, CannotUseBinderAfterFork) { + // EXPECT_DEATH works by forking the process + EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork"); +@@ -909,6 +936,100 @@ TEST_F(BinderLibTest, PassParcelFileDescriptor) { + EXPECT_EQ(0, read(read_end.get(), readbuf.data(), datasize)); + } + ++TEST_F(BinderLibTest, RecvOwnedFileDescriptors) { ++ FdLeakDetector fd_leak_detector; ++ ++ Parcel data; ++ Parcel reply; ++ EXPECT_EQ(NO_ERROR, ++ m_server->transact(BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_OWNED_TRANSACTION, data, ++ &reply)); ++ unique_fd a, b; ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&a)); ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&b)); ++} ++ ++// Used to trigger fdsan error (b/239222407). ++TEST_F(BinderLibTest, RecvOwnedFileDescriptorsAndWriteInt) { ++ GTEST_SKIP() << "triggers fdsan false positive: b/370824489"; ++ ++ FdLeakDetector fd_leak_detector; ++ ++ Parcel data; ++ Parcel reply; ++ EXPECT_EQ(NO_ERROR, ++ m_server->transact(BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_OWNED_TRANSACTION, data, ++ &reply)); ++ reply.setDataPosition(reply.dataSize()); ++ reply.writeInt32(0); ++ reply.setDataPosition(0); ++ unique_fd a, b; ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&a)); ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&b)); ++} ++ ++// Used to trigger fdsan error (b/239222407). ++TEST_F(BinderLibTest, RecvOwnedFileDescriptorsAndTruncate) { ++ GTEST_SKIP() << "triggers fdsan false positive: b/370824489"; ++ ++ FdLeakDetector fd_leak_detector; ++ ++ Parcel data; ++ Parcel reply; ++ EXPECT_EQ(NO_ERROR, ++ m_server->transact(BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_OWNED_TRANSACTION, data, ++ &reply)); ++ reply.setDataSize(reply.dataSize() - sizeof(flat_binder_object)); ++ unique_fd a, b; ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&a)); ++ EXPECT_EQ(BAD_TYPE, reply.readUniqueFileDescriptor(&b)); ++} ++ ++TEST_F(BinderLibTest, RecvUnownedFileDescriptors) { ++ FdLeakDetector fd_leak_detector; ++ ++ Parcel data; ++ Parcel reply; ++ EXPECT_EQ(NO_ERROR, ++ m_server->transact(BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_UNOWNED_TRANSACTION, data, ++ &reply)); ++ unique_fd a, b; ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&a)); ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&b)); ++} ++ ++// Used to trigger fdsan error (b/239222407). ++TEST_F(BinderLibTest, RecvUnownedFileDescriptorsAndWriteInt) { ++ FdLeakDetector fd_leak_detector; ++ ++ Parcel data; ++ Parcel reply; ++ EXPECT_EQ(NO_ERROR, ++ m_server->transact(BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_UNOWNED_TRANSACTION, data, ++ &reply)); ++ reply.setDataPosition(reply.dataSize()); ++ reply.writeInt32(0); ++ reply.setDataPosition(0); ++ unique_fd a, b; ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&a)); ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&b)); ++} ++ ++// Used to trigger fdsan error (b/239222407). ++TEST_F(BinderLibTest, RecvUnownedFileDescriptorsAndTruncate) { ++ FdLeakDetector fd_leak_detector; ++ ++ Parcel data; ++ Parcel reply; ++ EXPECT_EQ(NO_ERROR, ++ m_server->transact(BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_UNOWNED_TRANSACTION, data, ++ &reply)); ++ reply.setDataSize(reply.dataSize() - sizeof(flat_binder_object)); ++ unique_fd a, b; ++ EXPECT_EQ(OK, reply.readUniqueFileDescriptor(&a)); ++ EXPECT_EQ(BAD_TYPE, reply.readUniqueFileDescriptor(&b)); ++} ++ + TEST_F(BinderLibTest, PromoteLocal) { + sp strong = new BBinder(); + wp weak = strong; +@@ -1958,6 +2079,40 @@ public: + if (ret != size) return UNKNOWN_ERROR; + return NO_ERROR; + } ++ case BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_OWNED_TRANSACTION: { ++ unique_fd fd1(memfd_create("memfd1", MFD_CLOEXEC)); ++ if (!fd1.ok()) { ++ PLOGE("memfd_create failed"); ++ return UNKNOWN_ERROR; ++ } ++ unique_fd fd2(memfd_create("memfd2", MFD_CLOEXEC)); ++ if (!fd2.ok()) { ++ PLOGE("memfd_create failed"); ++ return UNKNOWN_ERROR; ++ } ++ status_t ret; ++ ret = reply->writeFileDescriptor(fd1.release(), true); ++ if (ret != NO_ERROR) { ++ return ret; ++ } ++ ret = reply->writeFileDescriptor(fd2.release(), true); ++ if (ret != NO_ERROR) { ++ return ret; ++ } ++ return NO_ERROR; ++ } ++ case BINDER_LIB_TEST_GET_FILE_DESCRIPTORS_UNOWNED_TRANSACTION: { ++ status_t ret; ++ ret = reply->writeFileDescriptor(STDOUT_FILENO, false); ++ if (ret != NO_ERROR) { ++ return ret; ++ } ++ ret = reply->writeFileDescriptor(STDERR_FILENO, false); ++ if (ret != NO_ERROR) { ++ return ret; ++ } ++ return NO_ERROR; ++ } + case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION: + alarm(10); + return NO_ERROR; +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/native/0004-libbinder-Parcel-grow-rejects-large-data-pos.bulletin.patch b/aosp_diff/preliminary/frameworks/native/0004-libbinder-Parcel-grow-rejects-large-data-pos.bulletin.patch new file mode 100644 index 0000000000..20dcdfa021 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/native/0004-libbinder-Parcel-grow-rejects-large-data-pos.bulletin.patch @@ -0,0 +1,41 @@ +From df99a3903097c70f58ffca2a6e8d815ffeeee2c3 Mon Sep 17 00:00:00 2001 +From: Steven Moreland +Date: Wed, 2 Oct 2024 01:00:23 +0000 +Subject: [PATCH] libbinder: Parcel: grow rejects large data pos + +This is unexpected behavior so throw an error. +Allocating this much memory may cause OOM or +other issues. + +Bug: 370831157 +Test: fuzzer +(cherry picked from commit 608524d462278c2c9f6716cd94f126c85e9f2e91) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:94e777ab39848540f9ef9d47229338d8996709d6) +Merged-In: Iea0884ca61b08e52e6a6e9c66693e427cb5536f4 +Change-Id: Iea0884ca61b08e52e6a6e9c66693e427cb5536f4 +--- + libs/binder/Parcel.cpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp +index 564f81e6e0..544b53cae3 100644 +--- a/libs/binder/Parcel.cpp ++++ b/libs/binder/Parcel.cpp +@@ -2942,6 +2942,14 @@ status_t Parcel::growData(size_t len) + return BAD_VALUE; + } + ++ if (mDataPos > mDataSize) { ++ // b/370831157 - this case used to abort. We also don't expect mDataPos < mDataSize, but ++ // this would only waste a bit of memory, so it's okay. ++ ALOGE("growData only expected at the end of a Parcel. pos: %zu, size: %zu, capacity: %zu", ++ mDataPos, len, mDataCapacity); ++ return BAD_VALUE; ++ } ++ + if (len > SIZE_MAX - mDataSize) return NO_MEMORY; // overflow + if (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflow + size_t newSize = ((mDataSize+len)*3)/2; +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/frameworks/native/0005-libbinder-Parcel-validate-read-data-before-write.bulletin.patch b/aosp_diff/preliminary/frameworks/native/0005-libbinder-Parcel-validate-read-data-before-write.bulletin.patch new file mode 100644 index 0000000000..6c5ca3714b --- /dev/null +++ b/aosp_diff/preliminary/frameworks/native/0005-libbinder-Parcel-validate-read-data-before-write.bulletin.patch @@ -0,0 +1,59 @@ +From 49eb0ea0816e1fc45101f8b2847d731fc192576f Mon Sep 17 00:00:00 2001 +From: Steven Moreland +Date: Wed, 2 Oct 2024 00:37:59 +0000 +Subject: [PATCH] libbinder: Parcel: validate read data before write + +This is slow, but it's required to prevent memory +corruption. + +Ignore-AOSP-First: security +Bug: 370840874 +Test: fuzzer +(cherry picked from commit c54dad65317f851ce9d016bd90ec6a7a04da09fc) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:43feae49c343b948a38b15d5e12c78916bafee61) +Merged-In: Ibc5566ade0389221690dc90324f93394cf7fc9a5 +Change-Id: Ibc5566ade0389221690dc90324f93394cf7fc9a5 +--- + libs/binder/Parcel.cpp | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp +index 544b53cae3..bbcac5414e 100644 +--- a/libs/binder/Parcel.cpp ++++ b/libs/binder/Parcel.cpp +@@ -1211,6 +1211,10 @@ restart_write: + //printf("Writing %ld bytes, padded to %ld\n", len, padded); + uint8_t* const data = mData+mDataPos; + ++ if (status_t status = validateReadData(mDataPos + padded); status != OK) { ++ return nullptr; // drops status ++ } ++ + // Need to pad at end? + if (padded != len) { + #if BYTE_ORDER == BIG_ENDIAN +@@ -1792,6 +1796,10 @@ status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) + const bool enoughObjects = kernelFields->mObjectsSize < kernelFields->mObjectsCapacity; + if (enoughData && enoughObjects) { + restart_write: ++ if (status_t status = validateReadData(mDataPos + sizeof(val)); status != OK) { ++ return status; ++ } ++ + *reinterpret_cast(mData+mDataPos) = val; + + // remember if it's a file descriptor +@@ -2035,6 +2043,10 @@ status_t Parcel::writeAligned(T val) { + + if ((mDataPos+sizeof(val)) <= mDataCapacity) { + restart_write: ++ if (status_t status = validateReadData(mDataPos + sizeof(val)); status != OK) { ++ return status; ++ } ++ + memcpy(mData + mDataPos, &val, sizeof(val)); + return finishWrite(sizeof(val)); + } +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/packages/apps/DocumentsUI/0001-Prevent-clickjacking-attack-in-DocsUi-.bulletin.patch b/aosp_diff/preliminary/packages/apps/DocumentsUI/0001-Prevent-clickjacking-attack-in-DocsUi-.bulletin.patch new file mode 100644 index 0000000000..5ec6cb2136 --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/DocumentsUI/0001-Prevent-clickjacking-attack-in-DocsUi-.bulletin.patch @@ -0,0 +1,76 @@ +From c8e21a60d78414aca4115403fe63fc732a9cd5aa Mon Sep 17 00:00:00 2001 +From: Aditya Singh +Date: Mon, 9 Sep 2024 15:11:53 +0000 +Subject: [PATCH] Prevent clickjacking attack in DocsUi. + +* Added permission `HIDE_OVERLAY_WINDOWS` in the Manifest. +* Set the flag to hide overlay windows to true in BaseActivity and + ConfirmFragment. + +Bug: 233605527 +Test: Manually, see http://b/233605527#comment4 +Flag: EXEMPT bugfix +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5178a952e18ee66f1b3c14796708d0d60058a157) +Merged-In: I511730856be58cad3e13fa50bfac1e1ee2f5fee0 +Change-Id: I511730856be58cad3e13fa50bfac1e1ee2f5fee0 +--- + AndroidManifest.xml | 1 + + src/com/android/documentsui/BaseActivity.java | 4 ++++ + src/com/android/documentsui/picker/ConfirmFragment.java | 7 ++++++- + 3 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/AndroidManifest.xml b/AndroidManifest.xml +index 76802342e..be98d1d08 100644 +--- a/AndroidManifest.xml ++++ b/AndroidManifest.xml +@@ -33,6 +33,7 @@ + + + ++ + + + +diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java +index a1dc0b99b..15439e28c 100644 +--- a/src/com/android/documentsui/BaseActivity.java ++++ b/src/com/android/documentsui/BaseActivity.java +@@ -172,6 +172,10 @@ public abstract class BaseActivity + // Record the time when onCreate is invoked for metric. + mStartTime = new Date().getTime(); + ++ if (SdkLevel.isAtLeastS()) { ++ getWindow().setHideOverlayWindows(true); ++ } ++ + // ToDo Create tool to check resource version before applyStyle for the theme + // If version code is not match, we should reset overlay package to default, + // in case Activity continueusly encounter resource not found exception +diff --git a/src/com/android/documentsui/picker/ConfirmFragment.java b/src/com/android/documentsui/picker/ConfirmFragment.java +index 94015e930..e1af281bc 100644 +--- a/src/com/android/documentsui/picker/ConfirmFragment.java ++++ b/src/com/android/documentsui/picker/ConfirmFragment.java +@@ -32,6 +32,7 @@ import com.android.documentsui.BaseActivity; + import com.android.documentsui.R; + import com.android.documentsui.base.DocumentInfo; + import com.android.documentsui.base.Shared; ++import com.android.modules.utils.build.SdkLevel; + + import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +@@ -102,7 +103,11 @@ public class ConfirmFragment extends DialogFragment { + builder.setNegativeButton(android.R.string.cancel, + (DialogInterface dialog, int id) -> pickResult.increaseActionCount()); + +- return builder.create(); ++ Dialog dialog = builder.create(); ++ if (SdkLevel.isAtLeastS()) { ++ dialog.getWindow().setHideOverlayWindows(true); ++ } ++ return dialog; + } + + @Override +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/packages/apps/Settings/0001-CDM-NLS-Check-if-the-NLS-service-has-an-intent-filter.bulletin.patch b/aosp_diff/preliminary/packages/apps/Settings/0001-CDM-NLS-Check-if-the-NLS-service-has-an-intent-filter.bulletin.patch new file mode 100644 index 0000000000..a705affc4a --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/Settings/0001-CDM-NLS-Check-if-the-NLS-service-has-an-intent-filter.bulletin.patch @@ -0,0 +1,147 @@ +From 334323abd5714ef7b52db06bfc60ace5d857323f Mon Sep 17 00:00:00 2001 +From: Guojing Yuan +Date: Tue, 1 Oct 2024 21:59:31 +0000 +Subject: [PATCH] [CDM][NLS] Check if the NLS service has an intent-filter + +Bug: 363248394 +Test: CTS +Flag: EXEMPT bugfix +(cherry picked from commit 7ae59a42eb13f643d842525208619037c074371a) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2b3a057d23dc929e7d4b593550974368ea4f83ef) +Merged-In: Ib79c219cde8d73a218ceb7911f4552d43e384d8e +Change-Id: Ib79c219cde8d73a218ceb7911f4552d43e384d8e +--- + ...otificationAccessConfirmationActivity.java | 50 +++++++++++-------- + ...icationAccessConfirmationActivityTest.java | 9 ++-- + 2 files changed, 33 insertions(+), 26 deletions(-) + +diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java +index 3f300c0fce..1adeb64415 100644 +--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java ++++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java +@@ -30,13 +30,15 @@ import android.app.admin.DevicePolicyManager; + import android.content.ComponentName; + import android.content.Context; + import android.content.DialogInterface; ++import android.content.Intent; + import android.content.pm.ApplicationInfo; + import android.content.pm.PackageItemInfo; + import android.content.pm.PackageManager; +-import android.content.pm.ServiceInfo; ++import android.content.pm.ResolveInfo; + import android.os.Bundle; + import android.os.UserHandle; + import android.os.UserManager; ++import android.service.notification.NotificationListenerService; + import android.text.TextUtils; + import android.util.Slog; + import android.view.WindowManager; +@@ -49,6 +51,8 @@ import com.android.internal.app.AlertActivity; + import com.android.internal.app.AlertController; + import com.android.settings.R; + ++import java.util.List; ++ + /** @hide */ + public class NotificationAccessConfirmationActivity extends Activity + implements DialogInterface { +@@ -113,6 +117,31 @@ public class NotificationAccessConfirmationActivity extends Activity + return; + } + ++ // Check NLS service info. ++ String requiredPermission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; ++ Intent NLSIntent = new Intent(NotificationListenerService.SERVICE_INTERFACE); ++ List matchedServiceList = getPackageManager().queryIntentServicesAsUser( ++ NLSIntent, /* flags */ 0, mUserId); ++ boolean hasNLSIntentFilter = false; ++ for (ResolveInfo service : matchedServiceList) { ++ if (service.serviceInfo.packageName.equals(mComponentName.getPackageName())) { ++ if (!requiredPermission.equals(service.serviceInfo.permission)) { ++ Slog.e(LOG_TAG, "Service " + mComponentName + " lacks permission " ++ + requiredPermission); ++ finish(); ++ return; ++ } ++ hasNLSIntentFilter = true; ++ break; ++ } ++ } ++ if (!hasNLSIntentFilter) { ++ Slog.e(LOG_TAG, "Service " + mComponentName + " lacks an intent-filter action " ++ + "for android.service.notification.NotificationListenerService."); ++ finish(); ++ return; ++ } ++ + AlertController.AlertParams p = new AlertController.AlertParams(this); + p.mTitle = getString( + R.string.notification_listener_security_warning_title, +@@ -147,19 +176,6 @@ public class NotificationAccessConfirmationActivity extends Activity + } + + private void onAllow() { +- String requiredPermission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; +- try { +- ServiceInfo serviceInfo = getPackageManager().getServiceInfo(mComponentName, 0); +- if (!requiredPermission.equals(serviceInfo.permission)) { +- Slog.e(LOG_TAG, +- "Service " + mComponentName + " lacks permission " + requiredPermission); +- return; +- } +- } catch (PackageManager.NameNotFoundException e) { +- Slog.e(LOG_TAG, "Failed to get service info for " + mComponentName, e); +- return; +- } +- + mNm.setNotificationListenerAccessGranted(mComponentName, true); + + finish(); +@@ -170,12 +186,6 @@ public class NotificationAccessConfirmationActivity extends Activity + return AlertActivity.dispatchPopulateAccessibilityEvent(this, event); + } + +- @Override +- public void onBackPressed() { +- // Suppress finishing the activity on back button press, +- // consistently with the permission dialog behavior +- } +- + @Override + public void cancel() { + finish(); +diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java +index 9b510fb43e..0a953615ab 100644 +--- a/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java ++++ b/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java +@@ -31,8 +31,6 @@ import android.widget.TextView; + + import androidx.annotation.Nullable; + +-import com.android.settings.R; +- + import com.google.common.base.Strings; + + import org.junit.Test; +@@ -45,15 +43,14 @@ import org.robolectric.RuntimeEnvironment; + public class NotificationAccessConfirmationActivityTest { + + @Test +- public void start_showsDialog() { ++ public void start_withMissingIntentFilter_finishes() { + ComponentName cn = new ComponentName("com.example", "com.example.SomeService"); + installPackage(cn.getPackageName(), "X"); + + NotificationAccessConfirmationActivity activity = startActivityWithIntent(cn); + +- assertThat(activity.isFinishing()).isFalse(); +- assertThat(getDialogText(activity)).isEqualTo( +- activity.getString(R.string.notification_listener_security_warning_summary, "X")); ++ assertThat(getDialogText(activity)).isNull(); ++ assertThat(activity.isFinishing()).isTrue(); + } + + @Test +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/packages/modules/Permission/0001-Fix-Dynamic-Permission-group-auto-grant-behaivor.bulletin.patch b/aosp_diff/preliminary/packages/modules/Permission/0001-Fix-Dynamic-Permission-group-auto-grant-behaivor.bulletin.patch new file mode 100644 index 0000000000..3fafc49e15 --- /dev/null +++ b/aosp_diff/preliminary/packages/modules/Permission/0001-Fix-Dynamic-Permission-group-auto-grant-behaivor.bulletin.patch @@ -0,0 +1,897 @@ +From f677d33568d944dfe43a713dc148bd68a5472931 Mon Sep 17 00:00:00 2001 +From: Yi-an Chen +Date: Wed, 17 Jul 2024 00:43:30 +0000 +Subject: [PATCH] Fix Dynamic Permission group auto grant behaivor + +Fix the Dynamic Permission group auto grant behaivor so that a +permission group is only considered granted when (1) all permissions +were auto-granted or (2) a platform permission in the same group is +granted. + +Bug: 340480881 +Test: DynamicPermissionsTest +(cherry picked from commit 46abb4e1fd365a88efdfe3f2b1f87da4d255b41b) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:111cac570a0f596cdca1b1d512dfbef17751e1a5) +Merged-In: Ie7de1b9826df72c708df02a4b73707c8fcffac86 +Change-Id: Ie7de1b9826df72c708df02a4b73707c8fcffac86 +--- + .../permission/data/LightPermInfoLiveData.kt | 2 +- + .../permission/data/PermGroupLiveData.kt | 45 ++++++++++--------- + .../model/livedatatypes/LightAppPermGroup.kt | 30 +++++++++---- + .../model/livedatatypes/LightPackageInfo.kt | 4 +- + .../model/livedatatypes/LightPermInfo.kt | 10 +++-- + .../model/livedatatypes/LightPermission.kt | 19 +++++--- + .../service/AutoRevokePermissions.kt | 2 +- + .../RuntimePermissionsUpgradeController.kt | 6 +-- + .../handheld/ReviewPermissionsFragment.java | 4 +- + .../ui/model/AppPermissionViewModel.kt | 24 +++++----- + .../ui/model/GrantPermissionsViewModel.kt | 28 +++++++----- + .../ui/model/ReviewPermissionsViewModel.kt | 2 +- + .../BackgroundGrantBehavior.kt | 9 ++-- + .../model/grantPermissions/GrantBehavior.kt | 2 +- + .../grantPermissions/HealthGrantBehavior.kt | 2 +- + .../grantPermissions/LocationGrantBehavior.kt | 7 ++- + .../grantPermissions/StorageGrantBehavior.kt | 10 ++--- + .../permission/utils/KotlinUtils.kt | 30 ++++++------- + .../permission/utils/SafetyNetLogger.java | 2 +- + .../model/ReviewPermissionsViewModelTest.kt | 2 +- + .../permission/utils/GrantRevokeTests.kt | 6 ++- + 21 files changed, 138 insertions(+), 108 deletions(-) + +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt +index 091c45b92..68aa55e14 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt +@@ -67,7 +67,7 @@ private constructor(private val app: Application, private val permissionName: St + + val newValue = + try { +- LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0)) ++ LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0), null) + } catch (e: PackageManager.NameNotFoundException) { + Log.w(LOG_TAG, "Permission \"$permissionName\" not found") + invalidateSingle(permissionName) +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt +index d44fea233..e923746d7 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupLiveData.kt +@@ -17,6 +17,7 @@ + package com.android.permissioncontroller.permission.data + + import android.app.Application ++import android.content.pm.ApplicationInfo + import android.content.pm.PackageItemInfo + import android.content.pm.PackageManager + import android.content.pm.PermissionGroupInfo +@@ -64,7 +65,6 @@ private constructor(private val app: Application, private val groupName: String) + */ + override fun onUpdate() { + val permissionInfos = mutableMapOf() +- + groupInfo = + Utils.getGroupInfo(groupName, context) + ?: run { +@@ -73,28 +73,25 @@ private constructor(private val app: Application, private val groupName: String) + value = null + return + } +- ++ val permInfos = mutableListOf() + when (groupInfo) { + is PermissionGroupInfo -> { +- val permInfos = +- try { ++ try { ++ permInfos.addAll( + Utils.getInstalledRuntimePermissionInfosForGroup( + context.packageManager, + groupName + ) +- } catch (e: PackageManager.NameNotFoundException) { +- Log.e(LOG_TAG, "Invalid permission group $groupName") +- invalidateSingle(groupName) +- value = null +- return +- } +- +- for (permInfo in permInfos) { +- permissionInfos[permInfo.name] = LightPermInfo(permInfo) ++ ) ++ } catch (e: PackageManager.NameNotFoundException) { ++ Log.e(LOG_TAG, "Invalid permission group $groupName") ++ invalidateSingle(groupName) ++ value = null ++ return + } + } + is PermissionInfo -> { +- permissionInfos[groupInfo.name] = LightPermInfo(groupInfo as PermissionInfo) ++ permInfos.add(groupInfo as PermissionInfo) + } + else -> { + value = null +@@ -102,19 +99,25 @@ private constructor(private val app: Application, private val groupName: String) + } + } + +- val permGroup = PermGroup(LightPermGroupInfo(groupInfo), permissionInfos) +- +- value = permGroup +- +- val packageNames = +- permissionInfos.values.map { permInfo -> permInfo.packageName }.toMutableSet() ++ val packageNames = permInfos.map { permInfo -> permInfo.packageName }.toMutableSet() + packageNames.add(groupInfo.packageName) +- + // TODO ntmyren: What if the package isn't installed for the system user? + val getLiveData = { packageName: String -> + LightPackageInfoLiveData[packageName, UserHandle.SYSTEM] + } + setSourcesToDifference(packageNames, packageLiveDatas, getLiveData) ++ if (!packageLiveDatas.all { it.value.isInitialized }) { ++ return ++ } ++ for (permInfo in permInfos) { ++ val lightPackageInfo = packageLiveDatas[permInfo.packageName]?.value ++ val isSystem = ++ lightPackageInfo?.let { it.appFlags and ApplicationInfo.FLAG_SYSTEM != 0 } ++ permissionInfos[permInfo.name] = LightPermInfo(permInfo, isSystem) ++ } ++ ++ val permGroup = PermGroup(LightPermGroupInfo(groupInfo), permissionInfos) ++ value = permGroup + } + + override fun onInactive() { +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt +index a5736ca83..61a604de8 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt +@@ -20,6 +20,7 @@ import android.Manifest + import android.Manifest.permission.ACCESS_COARSE_LOCATION + import android.os.Build + import android.os.UserHandle ++import com.android.permissioncontroller.permission.utils.Utils + + /** + * A lightweight version of the AppPermissionGroup data structure. Represents information about a +@@ -75,10 +76,13 @@ data class LightAppPermGroup( + get() = + permissions.mapNotNull { (name, _) -> if (name !in backgroundPermNames) name else null } + ++ val isPlatformPermissionGroup = permGroupInfo.packageName == Utils.OS_PKG ++ + val foreground = + AppPermSubGroup( + permissions.filter { it.key in foregroundPermNames }, + packageInfo, ++ isPlatformPermissionGroup, + specialLocationGrant + ) + +@@ -86,6 +90,7 @@ data class LightAppPermGroup( + AppPermSubGroup( + permissions.filter { it.key in backgroundPermNames }, + packageInfo, ++ isPlatformPermissionGroup, + specialLocationGrant + ) + +@@ -123,7 +128,7 @@ data class LightAppPermGroup( + val isOneTime = + (permGroupName != Manifest.permission_group.LOCATION && + permissions.any { it.value.isOneTime } && +- permissions.none { !it.value.isOneTime && it.value.isGrantedIncludingAppOp }) || ++ permissions.none { !it.value.isOneTime && it.value.isGranted }) || + (permGroupName == Manifest.permission_group.LOCATION && + permissions[ACCESS_COARSE_LOCATION]?.isOneTime == true) + +@@ -160,16 +165,24 @@ data class LightAppPermGroup( + * + * @param permissions The permissions contained within this subgroup, a subset of those + * contained in the full group ++ * @param isPlatformPermissionGroup Whether this is a platform permission group + * @param specialLocationGrant Whether this is a special location package + */ + data class AppPermSubGroup + internal constructor( + private val permissions: Map, + private val packageInfo: LightPackageInfo, ++ private val isPlatformPermissionGroup: Boolean, + private val specialLocationGrant: Boolean? + ) { + /** Whether any of this App Permission SubGroup's permissions are granted */ +- val isGranted = specialLocationGrant ?: permissions.any { it.value.isGrantedIncludingAppOp } ++ val isGranted = ++ specialLocationGrant ++ ?: permissions.any { ++ val mayGrantByPlatformOrSystem = ++ !isPlatformPermissionGroup || it.value.isPlatformOrSystem ++ it.value.isGranted && mayGrantByPlatformOrSystem ++ } + + /** + * Whether this App Permission SubGroup should be treated as granted. This means either: +@@ -178,14 +191,13 @@ data class LightAppPermGroup( + * 2) All permissions were auto-granted (all permissions are all granted and all + * RevokeWhenRequested.) + */ +- val isGrantedExcludingRWROrAllRWR = ++ val allowFullGroupGrant = + specialLocationGrant + ?: (permissions.any { +- it.value.isGrantedIncludingAppOp && !it.value.isRevokeWhenRequested +- } || +- permissions.all { +- it.value.isGrantedIncludingAppOp && it.value.isRevokeWhenRequested +- }) ++ val mayGrantByPlatformOrSystem = ++ !isPlatformPermissionGroup || it.value.isPlatformOrSystem ++ it.value.allowFullGroupGrant && mayGrantByPlatformOrSystem ++ } || permissions.all { it.value.isGranted && it.value.isRevokeWhenRequested }) + + /** Whether any of this App Permission SubGroup's permissions are granted by default */ + val isGrantedByDefault = permissions.any { it.value.isGrantedByDefault } +@@ -196,7 +208,7 @@ data class LightAppPermGroup( + */ + val isOneTime = + permissions.any { it.value.isOneTime } && +- permissions.none { it.value.isGrantedIncludingAppOp && !it.value.isOneTime } ++ permissions.none { it.value.isGranted && !it.value.isOneTime } + + /** + * Whether any of this App Permission Subgroup's foreground permissions are fixed by policy +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt +index ab8afae08..32bc3c526 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt +@@ -61,7 +61,9 @@ data class LightPackageInfo( + pI: PackageInfo + ) : this( + pI.packageName, +- pI.permissions?.map { perm -> LightPermInfo(perm) } ?: emptyList(), ++ pI.permissions?.map { perm -> ++ LightPermInfo(perm, pI.applicationInfo!!.flags and ApplicationInfo.FLAG_SYSTEM != 0) ++ } ?: emptyList(), + pI.requestedPermissions?.toList() ?: emptyList(), + pI.requestedPermissionsFlags?.toList() ?: emptyList(), + pI.applicationInfo!!.uid, +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt +index c1d271098..a25dcc24b 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermInfo.kt +@@ -30,6 +30,7 @@ import android.content.pm.PermissionInfo + * @param protection The protection level of this permission + * @param protection Extra information about the protection of this permission + * @param flags The system flags of this permission ++ * @param isSystem Whether this permission is defined by a system app + */ + data class LightPermInfo( + val name: String, +@@ -38,10 +39,12 @@ data class LightPermInfo( + val backgroundPermission: String?, + val protection: Int, + val protectionFlags: Int, +- val flags: Int ++ val flags: Int, ++ val isSystem: Boolean?, + ) { + constructor( +- permInfo: PermissionInfo ++ permInfo: PermissionInfo, ++ isSystem: Boolean? + ) : this( + permInfo.name, + permInfo.packageName, +@@ -49,7 +52,8 @@ data class LightPermInfo( + permInfo.backgroundPermission, + permInfo.protection, + permInfo.protectionFlags, +- permInfo.flags ++ permInfo.flags, ++ isSystem + ) + + /** +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt +index 7492ea6e0..66a076551 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt +@@ -28,8 +28,8 @@ import com.android.permissioncontroller.permission.utils.Utils + * + * @param pkgInfo The package requesting the permission + * @param permInfo The permissionInfo this represents +- * @param isGrantedIncludingAppOp Whether or not this permission is functionally granted. A +- * non-granted app op but granted permission is counted as not granted ++ * @param isGranted Whether or not this permission is functionally granted. A non-granted app op but ++ * granted permission is counted as not granted + * @param flags The PermissionController flags for this permission + * @param foregroundPerms The foreground permission names corresponding to this permission, if this + * permission is a background permission +@@ -37,7 +37,7 @@ import com.android.permissioncontroller.permission.utils.Utils + data class LightPermission( + val pkgInfo: LightPackageInfo, + val permInfo: LightPermInfo, +- val isGrantedIncludingAppOp: Boolean, ++ val isGranted: Boolean, + val flags: Int, + val foregroundPerms: List? + ) { +@@ -98,9 +98,9 @@ data class LightPermission( + /** Whether this permission is user sensitive in its current grant state */ + val isUserSensitive = + !isRuntimePlatformPermission(permInfo.name) || +- (isGrantedIncludingAppOp && ++ (isGranted && + (flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0) || +- (!isGrantedIncludingAppOp && ++ (!isGranted && + (flags and PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) != 0) + /** Whether the permission is restricted */ + val isRestricted = +@@ -122,10 +122,17 @@ data class LightPermission( + */ + val isSelectedLocationAccuracy = + flags and PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY != 0 ++ /** Whether this permission is defined by platform or a system app */ ++ val isPlatformOrSystem = permInfo.packageName == Utils.OS_PKG || permInfo.isSystem == true ++ /** ++ * Whether this permission is granted including app op and does not hold the ++ * PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED flag. ++ */ ++ val allowFullGroupGrant = isGranted && !isRevokeWhenRequested + + override fun toString() = buildString { + append(name) +- if (isGrantedIncludingAppOp) append(", Granted") else append(", NotGranted") ++ if (isGranted) append(", Granted") else append(", NotGranted") + if (isPolicyFixed) append(", PolicyFixed") + if (isSystemFixed) append(", SystemFixed") + if (isUserFixed) append(", UserFixed") +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt +index cfe753019..aae2aa212 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt +@@ -132,7 +132,7 @@ suspend fun revokeAppPermissions( + val fixed = group.isBackgroundFixed || group.isForegroundFixed + val granted = + group.permissions.any { (_, perm) -> +- perm.isGrantedIncludingAppOp && perm.name !in AUTO_REVOKE_EXEMPT_PERMISSIONS ++ perm.isGranted && perm.name !in AUTO_REVOKE_EXEMPT_PERMISSIONS + } + if ( + !fixed && +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt +index af3b60702..2734116dd 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt +@@ -492,7 +492,7 @@ object RuntimePermissionsUpgradeController { + LightPermission( + perm.pkgInfo, + perm.permInfo, +- perm.isGrantedIncludingAppOp, ++ perm.isGranted, + perm.flags or FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, + perm.foregroundPerms + ) +@@ -569,7 +569,7 @@ object RuntimePermissionsUpgradeController { + !perm.isUserSet && + !perm.isSystemFixed && + !perm.isPolicyFixed && +- !perm.isGrantedIncludingAppOp ++ !perm.isGranted + ) { + grants.add( + Grant(false, appPermGroup, listOf(permission.ACCESS_MEDIA_LOCATION)) +@@ -670,7 +670,7 @@ object RuntimePermissionsUpgradeController { + LightPermission( + perm.pkgInfo, + perm.permInfo, +- perm.isGrantedIncludingAppOp, ++ perm.isGranted, + perm.flags or FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, + perm.foregroundPerms + ) +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java +index 5a7c3f2b5..14f349777 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java +@@ -267,11 +267,11 @@ public final class ReviewPermissionsFragment extends PreferenceFragmentCompat + PermissionControllerStatsLog.write(REVIEW_PERMISSIONS_FRAGMENT_RESULT_REPORTED, + changeId, mViewModel.getPackageInfo().applicationInfo.uid, + group.getPackageName(), +- permission.getName(), permission.isGrantedIncludingAppOp()); ++ permission.getName(), permission.isGranted()); + Log.i(LOG_TAG, "Permission grant via permission review changeId=" + changeId + " uid=" + + mViewModel.getPackageInfo().applicationInfo.uid + " packageName=" + + group.getPackageName() + " permission=" +- + permission.getName() + " granted=" + permission.isGrantedIncludingAppOp()); ++ + permission.getName() + " granted=" + permission.isGranted()); + } + } + +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt +index 5b6d8b8db..1f0a41c59 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt +@@ -325,6 +325,7 @@ class AppPermissionViewModel( + + private val mainLocListener = { isEnabled: Boolean -> checkAndUpdateStatus(!isEnabled) } + private val locBypassListener = { _: Boolean -> checkAndUpdateStatus() } ++ + override fun onUpdate() { + checkAndUpdateStatus() + } +@@ -692,8 +693,7 @@ class AppPermissionViewModel( + app, + packageName, + permGroupName +- ) +- ?: return ++ ) ?: return + fragment.startActivity(restrictionIntent) + } + +@@ -726,10 +726,8 @@ class AppPermissionViewModel( + // 2. Else if FINE or COARSE have the isSelectedLocationAccuracy flag set, then return + // true if FINE isSelectedLocationAccuracy is set. + // 3. Else, return default precision from device config. +- return if ( +- fineLocation.isGrantedIncludingAppOp || coarseLocation.isGrantedIncludingAppOp +- ) { +- fineLocation.isGrantedIncludingAppOp ++ return if (fineLocation.isGranted || coarseLocation.isGranted) { ++ fineLocation.isGranted + } else if ( + fineLocation.isSelectedLocationAccuracy || coarseLocation.isSelectedLocationAccuracy + ) { +@@ -1381,9 +1379,7 @@ class AppPermissionViewModel( + } + + private fun getIndividualPermissionDetailResId(group: LightAppPermGroup): Pair { +- return when ( +- val numRevoked = group.permissions.filter { !it.value.isGrantedIncludingAppOp }.size +- ) { ++ return when (val numRevoked = group.permissions.filter { !it.value.isGranted }.size) { + 0 -> R.string.permission_revoked_none to numRevoked + group.permissions.size -> R.string.permission_revoked_all to numRevoked + else -> R.string.permission_revoked_count to numRevoked +@@ -1454,7 +1450,7 @@ class AppPermissionViewModel( + val newPermission = newGroup.permissions[permName] ?: continue + + if ( +- permission.isGrantedIncludingAppOp != newPermission.isGrantedIncludingAppOp || ++ permission.isGranted != newPermission.isGranted || + permission.flags != newPermission.flags + ) { + logAppPermissionFragmentActionReported(changeId, newPermission, buttonPressed) +@@ -1462,7 +1458,7 @@ class AppPermissionViewModel( + app.applicationContext, + packageName, + permGroupName, +- newPermission.isGrantedIncludingAppOp ++ newPermission.isGranted + ) + PermissionChangeStorageImpl.recordPermissionChange(packageName) + } +@@ -1492,7 +1488,7 @@ class AppPermissionViewModel( + uid, + packageName, + permission.permInfo.name, +- permission.isGrantedIncludingAppOp, ++ permission.isGranted, + permission.flags, + buttonPressed + ) +@@ -1502,7 +1498,7 @@ class AppPermissionViewModel( + "$changeId uid=$uid packageName=$packageName permission=" + + permission.permInfo.name + + " isGranted=" + +- permission.isGrantedIncludingAppOp + ++ permission.isGranted + + " permissionFlags=" + + permission.flags + + " buttonPressed=$buttonPressed" +@@ -1544,7 +1540,7 @@ class AppPermissionViewModel( + + return group.isGranted && + group.permissions.values.all { +- it.name in partialPerms || (it.name !in partialPerms && !it.isGrantedIncludingAppOp) ++ it.name in partialPerms || (it.name !in partialPerms && !it.isGranted) + } + } + } +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt +index b5df6f410..0a01929e6 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt +@@ -338,7 +338,7 @@ class GrantPermissionsViewModel( + if (state != null) { + val allAffectedGranted = + state.affectedPermissions.all { perm -> +- appPermGroup.permissions[perm]?.isGrantedIncludingAppOp == true && ++ appPermGroup.permissions[perm]?.isGranted == true && + appPermGroup.permissions[perm]?.isRevokeWhenRequested == false + } + if (allAffectedGranted) { +@@ -592,7 +592,7 @@ class GrantPermissionsViewModel( + + val behavior = getGrantBehavior(group) + return if (behavior.isGroupFullyGranted(group, groupRequestedPermissions)) { +- if (group.permissions[perm]?.isGrantedIncludingAppOp == false) { ++ if (group.permissions[perm]?.isGranted == false) { + if (isBackground) { + grantBackgroundRuntimePermissions(app, group, listOf(perm)) + } else { +@@ -864,18 +864,15 @@ class GrantPermissionsViewModel( + } else { + PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED + } ++ var affectedPermissions: Collection = groupState.affectedPermissions + if (shouldAffectBackgroundPermissions) { +- grantBackgroundRuntimePermissions( +- app, +- groupState.group, +- groupState.affectedPermissions +- ) ++ grantBackgroundRuntimePermissions(app, groupState.group, affectedPermissions) + } else if (shouldAffectForegroundPermssions) { + if (affectedForegroundPermissions == null) { + grantForegroundRuntimePermissions( + app, + groupState.group, +- groupState.affectedPermissions, ++ affectedPermissions, + isOneTime + ) + // This prevents weird flag state when app targetSDK switches from S+ to R- +@@ -883,11 +880,12 @@ class GrantPermissionsViewModel( + KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, groupState.group, true) + } + } else { ++ affectedPermissions = affectedForegroundPermissions + val newGroup = + grantForegroundRuntimePermissions( + app, + groupState.group, +- affectedForegroundPermissions, ++ affectedPermissions, + isOneTime + ) + if (!isOneTime || newGroup.isOneTime) { +@@ -899,7 +897,17 @@ class GrantPermissionsViewModel( + } + } + } +- groupState.state = STATE_GRANTED ++ val shouldDenyFullGroupGrant = ++ groupState.group.isPlatformPermissionGroup && ++ affectedPermissions.none { ++ groupState.group.permissions[it]?.isPlatformOrSystem == true ++ } ++ groupState.state = ++ if (shouldDenyFullGroupGrant) { ++ STATE_UNKNOWN ++ } else { ++ STATE_GRANTED ++ } + } else { + if (shouldAffectBackgroundPermissions) { + revokeBackgroundRuntimePermissions( +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt +index 8613d1cae..ecb551ffc 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt +@@ -133,7 +133,7 @@ class ReviewPermissionsViewModel(val app: Application, val packageInfo: PackageI + val lightPerms = permGroup.allPermissions.values.toList() + val permissionCount = lightPerms.size + for (i in 0 until permissionCount) { +- if (!lightPerms[i].isGrantedIncludingAppOp) { ++ if (!lightPerms[i].isGranted) { + revokedCount++ + } + } +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt +index 6234b2755..7112d180f 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/BackgroundGrantBehavior.kt +@@ -57,7 +57,7 @@ object BackgroundGrantBehavior : GrantBehavior() { + val requestsBg = hasBgPerms(group, requestedPerms) + val requestsFg = requestedPerms.any { it !in group.backgroundPermNames } + val isOneTimeGroup = PermissionMapping.supportsOneTimeGrant(group.permGroupName) +- val isFgGranted = group.foreground.isGrantedExcludingRWROrAllRWR ++ val isFgGranted = group.foreground.allowFullGroupGrant + val isFgOneTime = group.foreground.isOneTime + val splitSdk = getSdkGroupWasSplitToBg(requestedPerms) + val isAppIsOlderThanSplitToBg = group.packageInfo.targetSdkVersion < splitSdk +@@ -171,16 +171,15 @@ object BackgroundGrantBehavior : GrantBehavior() { + group: LightAppPermGroup, + requestedPerms: Set + ): Boolean { +- return (!hasBgPerms(group, requestedPerms) || +- group.background.isGrantedExcludingRWROrAllRWR) && +- group.foreground.isGrantedExcludingRWROrAllRWR ++ return (!hasBgPerms(group, requestedPerms) || group.background.allowFullGroupGrant) && ++ group.foreground.allowFullGroupGrant + } + + override fun isForegroundFullyGranted( + group: LightAppPermGroup, + requestedPerms: Set + ): Boolean { +- return group.foreground.isGrantedExcludingRWROrAllRWR ++ return group.foreground.allowFullGroupGrant + } + + override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean { +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt +index 3b3619084..54d6dc0f3 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/GrantBehavior.kt +@@ -58,7 +58,7 @@ abstract class GrantBehavior { + * group not already granted will be granted. + */ + open fun isGroupFullyGranted(group: LightAppPermGroup, requestedPerms: Set): Boolean { +- return group.foreground.isGrantedExcludingRWROrAllRWR ++ return group.foreground.allowFullGroupGrant + } + + /** +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt +index 8e540701a..4f5def312 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/HealthGrantBehavior.kt +@@ -47,7 +47,7 @@ object HealthGrantBehavior : GrantBehavior() { + group: LightAppPermGroup, + requestedPerms: Set + ): Boolean { +- return requestedPerms.all { group.permissions[it]?.isGrantedIncludingAppOp != false } ++ return requestedPerms.all { group.permissions[it]?.isGranted != false } + } + + override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean { +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt +index 2c5e2b732..31ac04cab 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/LocationGrantBehavior.kt +@@ -37,8 +37,7 @@ object LocationGrantBehavior : GrantBehavior() { + ): Prompt { + val backgroundPrompt = BackgroundGrantBehavior.getPrompt(group, requestedPerms) + val requestsBackground = requestedPerms.any { it in group.backgroundPermNames } +- val coarseGranted = +- group.permissions[ACCESS_COARSE_LOCATION]?.isGrantedIncludingAppOp == true ++ val coarseGranted = group.permissions[ACCESS_COARSE_LOCATION]?.isGranted == true + return if (!supportsLocationAccuracy(group) || requestsBackground) { + backgroundPrompt + } else if (requestedPerms.contains(ACCESS_FINE_LOCATION)) { +@@ -84,10 +83,10 @@ object LocationGrantBehavior : GrantBehavior() { + } + + if (requestedPerms.contains(ACCESS_FINE_LOCATION)) { +- return group.permissions[ACCESS_FINE_LOCATION]?.isGrantedIncludingAppOp == true ++ return group.permissions[ACCESS_FINE_LOCATION]?.isGranted == true + } + +- return group.foreground.isGrantedExcludingRWROrAllRWR ++ return group.foreground.allowFullGroupGrant + } + + override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean { +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt +index a690f5f59..9dd87674a 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/grantPermissions/StorageGrantBehavior.kt +@@ -66,11 +66,11 @@ object StorageGrantBehavior : GrantBehavior() { + } + + val userSelectedPerm = group.permissions[READ_MEDIA_VISUAL_USER_SELECTED] +- if (userSelectedPerm?.isUserFixed == true && userSelectedPerm.isGrantedIncludingAppOp) { ++ if (userSelectedPerm?.isUserFixed == true && userSelectedPerm.isGranted) { + return Prompt.NO_UI_PHOTO_PICKER_REDIRECT + } + +- if (userSelectedPerm?.isGrantedIncludingAppOp == true) { ++ if (userSelectedPerm?.isGranted == true) { + return Prompt.SELECT_MORE_PHOTOS + } else { + return Prompt.SELECT_PHOTOS +@@ -97,16 +97,14 @@ object StorageGrantBehavior : GrantBehavior() { + } + + return group.permissions.values.any { +- it.name !in getPartialGrantPermissions(group) && it.isGrantedIncludingAppOp ++ it.name !in getPartialGrantPermissions(group) && it.isGranted + } + } + + override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean { + val userSelectedPerm = group.permissions[READ_MEDIA_VISUAL_USER_SELECTED] + if ( +- userSelectedPerm != null && +- userSelectedPerm.isGrantedIncludingAppOp && +- userSelectedPerm.isUserFixed ++ userSelectedPerm != null && userSelectedPerm.isGranted && userSelectedPerm.isUserFixed + ) { + // If the user selected permission is fixed and granted, we immediately show the + // photo picker, rather than filtering +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt +index b822aa541..93c30939d 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt ++++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt +@@ -771,7 +771,7 @@ object KotlinUtils { + LightPermission( + group.packageInfo, + perm.permInfo, +- perm.isGrantedIncludingAppOp, ++ perm.isGranted, + perm.flags or flagsToSet, + perm.foregroundPerms + ) +@@ -904,7 +904,7 @@ object KotlinUtils { + group.specialLocationGrant + ) + // If any permission in the group is one time granted, start one time permission session. +- if (newGroup.permissions.any { it.value.isOneTime && it.value.isGrantedIncludingAppOp }) { ++ if (newGroup.permissions.any { it.value.isOneTime && it.value.isGranted }) { + if (SdkLevel.isAtLeastT()) { + context + .getSystemService(PermissionManager::class.java)!! +@@ -966,7 +966,7 @@ object KotlinUtils { + + var newFlags = perm.flags + var oldFlags = perm.flags +- var isGranted = perm.isGrantedIncludingAppOp ++ var isGranted = perm.isGranted + var shouldKill = false + + // Create a new context with the given deviceId so that permission updates will be bound +@@ -974,7 +974,7 @@ object KotlinUtils { + val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId) + + // Grant the permission if needed. +- if (!perm.isGrantedIncludingAppOp) { ++ if (!perm.isGranted) { + val affectsAppOp = permissionToOp(perm.name) != null || perm.isBackgroundPermission + + // TODO 195016052: investigate adding split permission handling +@@ -1043,14 +1043,14 @@ object KotlinUtils { + + // If we newly grant background access to the fine location, double-guess the user some + // time later if this was really the right choice. +- if (!perm.isGrantedIncludingAppOp && isGranted) { ++ if (!perm.isGranted && isGranted) { + var triggerLocationAccessCheck = false + if (perm.name == ACCESS_FINE_LOCATION) { + val bgPerm = group.permissions[perm.backgroundPermission] +- triggerLocationAccessCheck = bgPerm?.isGrantedIncludingAppOp == true ++ triggerLocationAccessCheck = bgPerm?.isGranted == true + } else if (perm.name == ACCESS_BACKGROUND_LOCATION) { + val fgPerm = group.permissions[ACCESS_FINE_LOCATION] +- triggerLocationAccessCheck = fgPerm?.isGrantedIncludingAppOp == true ++ triggerLocationAccessCheck = fgPerm?.isGranted == true + } + if (triggerLocationAccessCheck) { + // trigger location access check +@@ -1289,7 +1289,7 @@ object KotlinUtils { + val user = UserHandle.getUserHandleForUid(group.packageInfo.uid) + var newFlags = perm.flags + val deviceId = group.deviceId +- var isGranted = perm.isGrantedIncludingAppOp ++ var isGranted = perm.isGranted + val supportsRuntime = group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.M + var shouldKill = false + +@@ -1299,7 +1299,7 @@ object KotlinUtils { + // to the device + val context = ContextCompat.createDeviceContext(app.applicationContext, deviceId) + +- if (perm.isGrantedIncludingAppOp || (perm.isCompatRevoked && forceRemoveRevokedCompat)) { ++ if (perm.isGranted || (perm.isCompatRevoked && forceRemoveRevokedCompat)) { + if ( + supportsRuntime && + !isPermissionSplitFromNonRuntime( +@@ -1363,14 +1363,14 @@ object KotlinUtils { + + // If we revoke background access to the fine location, we trigger a check to remove + // notification warning about background location access +- if (perm.isGrantedIncludingAppOp && !isGranted) { ++ if (perm.isGranted && !isGranted) { + var cancelLocationAccessWarning = false + if (perm.name == ACCESS_FINE_LOCATION) { + val bgPerm = group.permissions[perm.backgroundPermission] +- cancelLocationAccessWarning = bgPerm?.isGrantedIncludingAppOp == true ++ cancelLocationAccessWarning = bgPerm?.isGranted == true + } else if (perm.name == ACCESS_BACKGROUND_LOCATION) { + val fgPerm = group.permissions[ACCESS_FINE_LOCATION] +- cancelLocationAccessWarning = fgPerm?.isGrantedIncludingAppOp == true ++ cancelLocationAccessWarning = fgPerm?.isGranted == true + } + if (cancelLocationAccessWarning) { + // cancel location access warning notification +@@ -1430,7 +1430,7 @@ object KotlinUtils { + val fgPerm = group.permissions[foregroundPermName] + val appOpName = permissionToOp(foregroundPermName) ?: continue + +- if (fgPerm != null && fgPerm.isGrantedIncludingAppOp) { ++ if (fgPerm != null && fgPerm.isGranted) { + wasChanged = + setOpMode(appOpName, uid, packageName, MODE_ALLOWED, appOpsManager) || + wasChanged +@@ -1443,7 +1443,7 @@ object KotlinUtils { + if (group.permissions.containsKey(perm.backgroundPermission)) { + val bgPerm = group.permissions[perm.backgroundPermission] + val mode = +- if (bgPerm != null && bgPerm.isGrantedIncludingAppOp) MODE_ALLOWED ++ if (bgPerm != null && bgPerm.isGranted) MODE_ALLOWED + else MODE_FOREGROUND + + setOpMode(appOpName, uid, packageName, mode, appOpsManager) +@@ -1490,7 +1490,7 @@ object KotlinUtils { + if (perm.isBackgroundPermission && perm.foregroundPerms != null) { + for (foregroundPermName in perm.foregroundPerms) { + val fgPerm = group.permissions[foregroundPermName] +- if (fgPerm != null && fgPerm.isGrantedIncludingAppOp) { ++ if (fgPerm != null && fgPerm.isGranted) { + val appOpName = permissionToOp(foregroundPermName) ?: return false + wasChanged = + wasChanged || +diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java +index 828857cc6..c9b023c44 100644 +--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java ++++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java +@@ -95,7 +95,7 @@ public final class SafetyNetLogger { + } + + builder.append(permission.getName()).append('|'); +- builder.append(permission.isGrantedIncludingAppOp()).append('|'); ++ builder.append(permission.isGranted()).append('|'); + builder.append(permission.getFlags()); + } + } +diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt +index 899a026c4..0e8890df5 100644 +--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt ++++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt +@@ -104,7 +104,7 @@ class ReviewPermissionsViewModelTest { + permissionsMap["mockedPermission1"] = permission2 + + whenever(permGroup.allPermissions).thenReturn(permissionsMap) +- whenever(permission1.isGrantedIncludingAppOp).thenReturn(true) ++ whenever(permission1.isGranted).thenReturn(true) + + val summary = model.getSummaryForIndividuallyControlledPermGroup(permGroup) + assertEquals( +diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt +index 8bd61ebe6..28f69b136 100644 +--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt ++++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt +@@ -25,6 +25,7 @@ import android.app.AppOpsManager.MODE_IGNORED + import android.app.AppOpsManager.permissionToOp + import android.app.Application + import android.content.Context ++import android.content.pm.ApplicationInfo + import android.content.pm.PackageManager + import android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED + import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME +@@ -216,7 +217,8 @@ class GrantRevokeTests { + backgroundPerm, + PermissionInfo.PROTECTION_DANGEROUS, + permInfoProtectionFlags, +- 0 ++ 0, ++ pkgInfo.appFlags and ApplicationInfo.FLAG_SYSTEM != 0 + ) + return LightPermission( + pkgInfo, +@@ -292,7 +294,7 @@ class GrantRevokeTests { + val flags = state.second + + assertWithMessage("permission $permName grant state incorrect") +- .that(perms[permName]?.isGrantedIncludingAppOp) ++ .that(perms[permName]?.isGranted) + .isEqualTo(granted) + + val actualFlags = perms[permName]!!.flags +-- +2.46.1.824.gd892dcdcdd-goog + diff --git a/aosp_diff/preliminary/packages/services/Telephony/03_0003-Fix-for-android.security.cts.CVE_2023_20913-failure.patch b/aosp_diff/preliminary/packages/services/Telephony/0001-Fix-for-android.security.cts.CVE_2023_20913-failure.patch similarity index 100% rename from aosp_diff/preliminary/packages/services/Telephony/03_0003-Fix-for-android.security.cts.CVE_2023_20913-failure.patch rename to aosp_diff/preliminary/packages/services/Telephony/0001-Fix-for-android.security.cts.CVE_2023_20913-failure.patch diff --git a/aosp_diff/preliminary/packages/services/Telephony/0002-enforce-the-calling-package-is-the-default-dialer-for-VisualVoic.bulletin.patch b/aosp_diff/preliminary/packages/services/Telephony/0002-enforce-the-calling-package-is-the-default-dialer-for-VisualVoic.bulletin.patch new file mode 100644 index 0000000000..b2a76653d8 --- /dev/null +++ b/aosp_diff/preliminary/packages/services/Telephony/0002-enforce-the-calling-package-is-the-default-dialer-for-VisualVoic.bulletin.patch @@ -0,0 +1,52 @@ +From b1ab472f0f56146387d3822318394cb2525ad34c Mon Sep 17 00:00:00 2001 +From: Thomas Stuart +Date: Thu, 6 Jun 2024 22:34:33 +0000 +Subject: [PATCH] enforce the calling package is the default dialer for + VisualVoicemail + +In the docs for setVisualVoicemailSmsFilterSettings, they state that +the callingPackage needs to be the default dialer. However, server side, +there is no enforcement for this. Now, every client is verified to be +the default dialer, system dialer, or carrier visual voicemail app +before changing the settings for visual voicemail. + +Bug: 308932906 +Test: CTS +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c27f06d3401d8a0caf93ee539d67e687ff429f3b) +Merged-In: I951d7783f5c425c03768efb7aee7a38e299e6536 +Change-Id: I951d7783f5c425c03768efb7aee7a38e299e6536 +--- + src/com/android/phone/PhoneInterfaceManager.java | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java +index dc4290d4a..2accf86ae 100644 +--- a/src/com/android/phone/PhoneInterfaceManager.java ++++ b/src/com/android/phone/PhoneInterfaceManager.java +@@ -4276,10 +4276,9 @@ public class PhoneInterfaceManager extends ITelephony.Stub { + public void enableVisualVoicemailSmsFilter(String callingPackage, int subId, + VisualVoicemailSmsFilterSettings settings) { + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); +- + enforceTelephonyFeatureWithException(callingPackage, + PackageManager.FEATURE_TELEPHONY_CALLING, "enableVisualVoicemailSmsFilter"); +- ++ enforceVisualVoicemailPackage(callingPackage, subId); + final long identity = Binder.clearCallingIdentity(); + try { + VisualVoicemailSmsFilterConfig.enableVisualVoicemailSmsFilter( +@@ -4292,10 +4291,9 @@ public class PhoneInterfaceManager extends ITelephony.Stub { + @Override + public void disableVisualVoicemailSmsFilter(String callingPackage, int subId) { + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); +- + enforceTelephonyFeatureWithException(callingPackage, + PackageManager.FEATURE_TELEPHONY_CALLING, "disableVisualVoicemailSmsFilter"); +- ++ enforceVisualVoicemailPackage(callingPackage, subId); + final long identity = Binder.clearCallingIdentity(); + try { + VisualVoicemailSmsFilterConfig.disableVisualVoicemailSmsFilter( +-- +2.46.1.824.gd892dcdcdd-goog +