diff --git a/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch b/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch index 178263906d..4e0803d7d7 100644 --- a/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch +++ b/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch @@ -20,7 +20,7 @@ index 47bb92c142..2d0ac256a4 100644 # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. - PLATFORM_SECURITY_PATCH := 2022-02-05 -+ PLATFORM_SECURITY_PATCH := 2023-12-01 ++ PLATFORM_SECURITY_PATCH := 2024-01-01 endif .KATI_READONLY := PLATFORM_SECURITY_PATCH diff --git a/aosp_diff/preliminary/frameworks/av/32_0032-Codec2BufferUtils-Use-cropped-dimensions-in-RGB-to-YUV-conversi.bulletin.patch b/aosp_diff/preliminary/frameworks/av/32_0032-Codec2BufferUtils-Use-cropped-dimensions-in-RGB-to-YUV-conversi.bulletin.patch new file mode 100644 index 0000000000..a4bed3fa25 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/av/32_0032-Codec2BufferUtils-Use-cropped-dimensions-in-RGB-to-YUV-conversi.bulletin.patch @@ -0,0 +1,36 @@ +From 74880c6156ad038bbf0397bffc39504454f3acdd Mon Sep 17 00:00:00 2001 +From: Harish Mahendrakar +Date: Mon, 28 Aug 2023 17:35:56 +0000 +Subject: [PATCH] Codec2BufferUtils: Use cropped dimensions in RGB to YUV + conversion + +Bug: 283099444 +Test: poc in the bug +(cherry picked from https://partner-android-review.googlesource.com/q/commit:3875b858a347e25db94574e6362798a849bf9ebd) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4eba80f6698cb2d7aa48ea4f7728dbdf11f29fd3) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:aaddf2a49d758a55319b88c8331d5b1209858c41) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3ee0378ac5b39fe57fb91f0a8113e0fd18ec1822) +Merged-In: I42c71616c9d50f61c92f461f6a91f5addb1d724a +Change-Id: I42c71616c9d50f61c92f461f6a91f5addb1d724a +--- + media/codec2/sfplugin/utils/Codec2BufferUtils.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp +index 5f87c664af..46c2e1e3bd 100644 +--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp ++++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp +@@ -551,8 +551,8 @@ status_t ConvertRGBToPlanarYUV( + uint8_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 255 : 240; + + #define CLIP3(min,v,max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max))) +- for (size_t y = 0; y < src.height(); ++y) { +- for (size_t x = 0; x < src.width(); ++x) { ++ for (size_t y = 0; y < src.crop().height; ++y) { ++ for (size_t x = 0; x < src.crop().width; ++x) { + uint8_t r = *pRed; + uint8_t g = *pGreen; + uint8_t b = *pBlue; +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/frameworks/av/33_0033-Fix-convertYUV420Planar16ToY410-overflow-issue-for-unsupported-c.bulletin.patch b/aosp_diff/preliminary/frameworks/av/33_0033-Fix-convertYUV420Planar16ToY410-overflow-issue-for-unsupported-c.bulletin.patch new file mode 100644 index 0000000000..af9c3e45c1 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/av/33_0033-Fix-convertYUV420Planar16ToY410-overflow-issue-for-unsupported-c.bulletin.patch @@ -0,0 +1,34 @@ +From 7bf2507adf6fc9acd9818474623c985d0898afc5 Mon Sep 17 00:00:00 2001 +From: Songyue Han +Date: Tue, 3 Oct 2023 22:40:14 +0000 +Subject: [PATCH] Fix convertYUV420Planar16ToY410 overflow issue for + unsupported cropwidth. + +Bug: 300476626 +Test: color_conversion_fuzzer +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:de2ad0fad97d6d97d1e01f0e8d8309536eb268b4) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:745ab99f7343bc236b88b9d63cd7b06ab192f9e9) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:aa8298ec8eb903e1e3dd915fa24f32e1aea1f76c) +Merged-In: I8631426188af3c5f9b6c1ff6a0039254c252f733 +Change-Id: I8631426188af3c5f9b6c1ff6a0039254c252f733 +--- + media/libstagefright/colorconversion/ColorConverter.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp +index c7dc415d8b..9804887144 100644 +--- a/media/libstagefright/colorconversion/ColorConverter.cpp ++++ b/media/libstagefright/colorconversion/ColorConverter.cpp +@@ -648,7 +648,8 @@ status_t ColorConverter::convertYUV420Planar16ToY410( + + uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1; + size_t x = 0; +- for (; x < src.cropWidth() - 3; x += 4) { ++ // x % 4 is always 0 so x + 3 will never overflow. ++ for (; x + 3 < src.cropWidth(); x += 4) { + u01 = *((uint32_t*)ptr_u); ptr_u += 2; + v01 = *((uint32_t*)ptr_v); ptr_v += 2; + +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0224-Add-null-check-for-media-metadata.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0224-Add-null-check-for-media-metadata.bulletin.patch new file mode 100644 index 0000000000..c14b580e1f --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0224-Add-null-check-for-media-metadata.bulletin.patch @@ -0,0 +1,32 @@ +From 7e50754a7c91415bbd8ea5e0519fb815b6418305 Mon Sep 17 00:00:00 2001 +From: Beth Thibodeau +Date: Sat, 28 Oct 2023 00:46:24 +0000 +Subject: [PATCH] Add null check for media metadata + +This check was inadvertently removed in a previous cherry pick and is still necessary. + +Bug: 307983823 +Test: build +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:abc33695709d44d3f23a310601070d496067950a) +Merged-In: I35e89feaf89322babb89fe0a30430606ebdfcdfc +Change-Id: I35e89feaf89322babb89fe0a30430606ebdfcdfc +--- + .../SystemUI/src/com/android/systemui/media/MediaDataManager.kt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +index 70af5b647362..fba7ac037ee8 100644 +--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt ++++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +@@ -574,7 +574,7 @@ class MediaDataManager( + // Song name + var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) + if (song.isNullOrBlank()) { +- song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE) ++ song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) + } + if (song.isNullOrBlank()) { + song = HybridGroupManager.resolveTitle(notif) +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0225-Dismiss-keyguard-when-simpin-auth-d-and-.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0225-Dismiss-keyguard-when-simpin-auth-d-and-.bulletin.patch new file mode 100644 index 0000000000..5d6f72b1c1 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0225-Dismiss-keyguard-when-simpin-auth-d-and-.bulletin.patch @@ -0,0 +1,42 @@ +From 1707468a608a13c3de8cc297ccc7bf717b88acc5 Mon Sep 17 00:00:00 2001 +From: Aaron Liu +Date: Tue, 28 Mar 2023 13:15:04 -0700 +Subject: [PATCH] Dismiss keyguard when simpin auth'd and... + +security method is none. This is mostly to fix the case where we auth +sim pin in the set up wizard and it goes straight to keyguard instead of +the setup wizard activity. + +This works with the prevent bypass keyguard flag because the device +should be noe secure in this case. + +Fixes: 222446076 +Test: turn locked sim on, which opens the sim pin screen. Auth the +screen and observe that keyguard is not shown. +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:48fa9bef3451e4a358c941af5b230f99881c5cb6) +Cherry-picking this CL as a security fix + +Bug: 222446076 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:65ea56f54c059584eb27ec53d486dba8161316ab) +Merged-In: Id302c41f63028bc6dd58ba686e23d73565de9675 +Change-Id: Id302c41f63028bc6dd58ba686e23d73565de9675 +--- + .../android/keyguard/KeyguardSecurityContainerController.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +index fc9c5dddbee5..9a3a6abc3646 100644 +--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java ++++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +@@ -391,7 +391,7 @@ public class KeyguardSecurityContainerController extends ViewController +Date: Fri, 11 Aug 2023 11:02:33 -0700 +Subject: [PATCH] DO NOT MERGE Ensure finish lockscreen when usersetup + incomplete + +Ensure that when the usersetup for the user is not complete, we do not +want to go to lockscreen, even if lockscreen is not disabled. + +Bug: 222446076 +Test: add Unit test, +Test: Wipe device, auth sim pin in setup, observe that lockscreen is +not there. +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:da4c8f81d9bc31ce856069bfe911dc6693b97e98) +Merged-In: I8e33db8eb6e2c917966cab3d6a4f982670473040 +Change-Id: I8e33db8eb6e2c917966cab3d6a4f982670473040 +--- + .../KeyguardSecurityContainerController.java | 21 ++++++++++++++----- + ...yguardSecurityContainerControllerTest.java | 3 ++- + 2 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +index 9a3a6abc3646..b2aec6bae864 100644 +--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java ++++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +@@ -51,6 +51,7 @@ import com.android.settingslib.utils.ThreadUtils; + import com.android.systemui.Gefingerpoken; + import com.android.systemui.shared.system.SysUiStatsLog; + import com.android.systemui.statusbar.policy.ConfigurationController; ++import com.android.systemui.statusbar.policy.DeviceProvisionedController; + import com.android.systemui.statusbar.policy.KeyguardStateController; + import com.android.systemui.util.ViewController; + +@@ -196,6 +197,7 @@ public class KeyguardSecurityContainerController extends ViewController +Date: Tue, 30 May 2023 18:45:47 -0500 +Subject: [PATCH] Add placeholder when media control title is blank + +When an app posts a media control with no available title, show a +placeholder string with the app name instead + +Bug: 274775190 +Test: atest MediaDataManagerTest +(cherry picked from commit 070eff919c85fd83501e380a92e30caf082e9ffc) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0ad65345e93a97edba24349c052f8e001e96ec14) +Merged-In: Ie406c180af48653595e8e222a15b4dda27de2e0e +Change-Id: Ie406c180af48653595e8e222a15b4dda27de2e0e +--- + .../SystemUI/src/com/android/systemui/media/MediaDataManager.kt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +index 096314d1c51a..699a79cbfbad 100644 +--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt ++++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +@@ -579,7 +579,7 @@ class MediaDataManager( + // Song name + var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) + if (song.isNullOrBlank()) { +- song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) ++ song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE) + } + if (song.isNullOrBlank()) { + song = HybridGroupManager.resolveTitle(notif) +-- +2.17.1 + diff --git a/aosp_diff/preliminary/frameworks/base/99_0228--SB-Privacy-Fetch-current-active-appops-on-startup-.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0228--SB-Privacy-Fetch-current-active-appops-on-startup-.bulletin.patch new file mode 100644 index 0000000000..09b4a2915b --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0228--SB-Privacy-Fetch-current-active-appops-on-startup-.bulletin.patch @@ -0,0 +1,350 @@ +From b9323252fabf72e726b8ed41c11a7d205a82cf6e Mon Sep 17 00:00:00 2001 +From: Caitlin Shkuratov +Date: Mon, 28 Aug 2023 21:34:43 +0000 +Subject: [PATCH] [SB][Privacy] Fetch current active appops on startup. + +This also updates SysUI's chip animation scheduler to ignore an +`isTooEarly` check if the chip animation is forced to be visible (which +is true for privacy events). + +Bug: 294104969 +Test: start recording, then kill systemui via adb-> verify privacy chip +reappears after restart. Pull down shade and verify chip is correctly +attributed. Stop recording and verify chip/dot disappears. +Test: open camera, then kill systemui via adb -> verify privacy chip +reappears after restart. Pull down shade and verify chip is correctly +attributed. Close camera and verify chip/dot disappears. +Test: smoke test of privacy chip and dot +Test: atest AppOpsControllerTest SystemStatusAnimationSchedulerImplTest + +(cherry picked from commit 084a7afb4bb41e0cdfdbe67bdd60728d940b4331) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:dac02d61f8cf755f733ef6c2fbd0f939ea13ee23) +Merged-In: I664bb3003a2f6871113406e3257b7118bbdf2ab5 +Change-Id: I664bb3003a2f6871113406e3257b7118bbdf2ab5 +--- + .../systemui/appops/AppOpsControllerImpl.java | 28 +++ + .../events/SystemStatusAnimationScheduler.kt | 5 +- + .../systemui/appops/AppOpsControllerTest.java | 217 ++++++++++++++++++ + 3 files changed, 248 insertions(+), 2 deletions(-) + +diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +index 9676a57b2df9..bcf3de1c0b97 100644 +--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java ++++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +@@ -52,6 +52,7 @@ import java.io.FileDescriptor; + import java.io.PrintWriter; + import java.util.ArrayList; + import java.util.List; ++import java.util.Map; + import java.util.Set; + + import javax.inject.Inject; +@@ -144,6 +145,10 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon + protected void setListening(boolean listening) { + mListening = listening; + if (listening) { ++ // System UI could be restarted while ops are active, so fetch the currently active ops ++ // once System UI starts listening again. ++ fetchCurrentActiveOps(); ++ + mAppOps.startWatchingActive(OPS, this); + mAppOps.startWatchingNoted(OPS, this); + mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler); +@@ -176,6 +181,29 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon + } + } + ++ private void fetchCurrentActiveOps() { ++ List packageOps = mAppOps.getPackagesForOps(OPS); ++ for (AppOpsManager.PackageOps op : packageOps) { ++ for (AppOpsManager.OpEntry entry : op.getOps()) { ++ for (Map.Entry attributedOpEntry : ++ entry.getAttributedOpEntries().entrySet()) { ++ if (attributedOpEntry.getValue().isRunning()) { ++ onOpActiveChanged( ++ entry.getOpStr(), ++ op.getUid(), ++ op.getPackageName(), ++ /* attributionTag= */ attributedOpEntry.getKey(), ++ /* active= */ true, ++ // AppOpsManager doesn't have a way to fetch attribution flags or ++ // chain ID given an op entry, so default them to none. ++ AppOpsManager.ATTRIBUTION_FLAGS_NONE, ++ AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); ++ } ++ } ++ } ++ } ++ } ++ + /** + * Adds a callback that will get notifified when an AppOp of the type the controller tracks + * changes +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt +index dcf8e739a76e..37a7ba58422d 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt +@@ -93,8 +93,9 @@ class SystemStatusAnimationScheduler @Inject constructor( + } + + fun onStatusEvent(event: StatusEvent) { +- // Ignore any updates until the system is up and running +- if (isTooEarly() || !isImmersiveIndicatorEnabled()) { ++ // Ignore any updates until the system is up and running. However, for important events that ++ // request to be force visible (like privacy), ignore whether it's too early. ++ if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) { + return + } + +diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +index 61a651234e0c..e6c36c18342c 100644 +--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java ++++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +@@ -19,6 +19,8 @@ package com.android.systemui.appops; + import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; + import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; + ++import static com.google.common.truth.Truth.assertThat; ++ + import static junit.framework.TestCase.assertFalse; + + import static org.junit.Assert.assertEquals; +@@ -66,6 +68,7 @@ import org.mockito.MockitoAnnotations; + + import java.util.Collections; + import java.util.List; ++import java.util.Map; + + @SmallTest + @RunWith(AndroidTestingRunner.class) +@@ -157,6 +160,204 @@ public class AppOpsControllerTest extends SysuiTestCase { + verify(mSensorPrivacyController, times(1)).removeCallback(mController); + } + ++ @Test ++ public void startListening_fetchesCurrentActive_none() { ++ when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) ++ .thenReturn(List.of()); ++ ++ mController.setListening(true); ++ ++ assertThat(mController.getActiveAppOps()).isEmpty(); ++ } ++ ++ /** Regression test for b/294104969. */ ++ @Test ++ public void startListening_fetchesCurrentActive_oneActive() { ++ AppOpsManager.PackageOps packageOps = createPackageOp( ++ "package.test", ++ /* packageUid= */ 2, ++ AppOpsManager.OPSTR_FINE_LOCATION, ++ /* isRunning= */ true); ++ when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) ++ .thenReturn(List.of(packageOps)); ++ ++ // WHEN we start listening ++ mController.setListening(true); ++ ++ // THEN the active list has the op ++ List list = mController.getActiveAppOps(); ++ assertEquals(1, list.size()); ++ AppOpItem first = list.get(0); ++ assertThat(first.getPackageName()).isEqualTo("package.test"); ++ assertThat(first.getUid()).isEqualTo(2); ++ assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); ++ } ++ ++ @Test ++ public void startListening_fetchesCurrentActive_multiplePackages() { ++ AppOpsManager.PackageOps packageOps1 = createPackageOp( ++ "package.one", ++ /* packageUid= */ 1, ++ AppOpsManager.OPSTR_FINE_LOCATION, ++ /* isRunning= */ true); ++ AppOpsManager.PackageOps packageOps2 = createPackageOp( ++ "package.two", ++ /* packageUid= */ 2, ++ AppOpsManager.OPSTR_FINE_LOCATION, ++ /* isRunning= */ false); ++ AppOpsManager.PackageOps packageOps3 = createPackageOp( ++ "package.three", ++ /* packageUid= */ 3, ++ AppOpsManager.OPSTR_FINE_LOCATION, ++ /* isRunning= */ true); ++ when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) ++ .thenReturn(List.of(packageOps1, packageOps2, packageOps3)); ++ ++ // WHEN we start listening ++ mController.setListening(true); ++ ++ // THEN the active list has the ops ++ List list = mController.getActiveAppOps(); ++ assertEquals(2, list.size()); ++ ++ AppOpItem item0 = list.get(0); ++ assertThat(item0.getPackageName()).isEqualTo("package.one"); ++ assertThat(item0.getUid()).isEqualTo(1); ++ assertThat(item0.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); ++ ++ AppOpItem item1 = list.get(1); ++ assertThat(item1.getPackageName()).isEqualTo("package.three"); ++ assertThat(item1.getUid()).isEqualTo(3); ++ assertThat(item1.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); ++ } ++ ++ @Test ++ public void startListening_fetchesCurrentActive_multipleEntries() { ++ AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); ++ when(packageOps.getUid()).thenReturn(1); ++ when(packageOps.getPackageName()).thenReturn("package.one"); ++ ++ // Entry 1 ++ AppOpsManager.OpEntry entry1 = mock(AppOpsManager.OpEntry.class); ++ when(entry1.getOpStr()).thenReturn(AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE); ++ AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed1.isRunning()).thenReturn(true); ++ when(entry1.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed1)); ++ // Entry 2 ++ AppOpsManager.OpEntry entry2 = mock(AppOpsManager.OpEntry.class); ++ when(entry2.getOpStr()).thenReturn(AppOpsManager.OPSTR_CAMERA); ++ AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed2.isRunning()).thenReturn(true); ++ when(entry2.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed2)); ++ // Entry 3 ++ AppOpsManager.OpEntry entry3 = mock(AppOpsManager.OpEntry.class); ++ when(entry3.getOpStr()).thenReturn(AppOpsManager.OPSTR_FINE_LOCATION); ++ AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed3.isRunning()).thenReturn(false); ++ when(entry3.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed3)); ++ ++ when(packageOps.getOps()).thenReturn(List.of(entry1, entry2, entry3)); ++ when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) ++ .thenReturn(List.of(packageOps)); ++ ++ // WHEN we start listening ++ mController.setListening(true); ++ ++ // THEN the active list has the ops ++ List list = mController.getActiveAppOps(); ++ assertEquals(2, list.size()); ++ ++ AppOpItem first = list.get(0); ++ assertThat(first.getPackageName()).isEqualTo("package.one"); ++ assertThat(first.getUid()).isEqualTo(1); ++ assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_PHONE_CALL_MICROPHONE); ++ ++ AppOpItem second = list.get(1); ++ assertThat(second.getPackageName()).isEqualTo("package.one"); ++ assertThat(second.getUid()).isEqualTo(1); ++ assertThat(second.getCode()).isEqualTo(AppOpsManager.OP_CAMERA); ++ } ++ ++ @Test ++ public void startListening_fetchesCurrentActive_multipleAttributes() { ++ AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); ++ when(packageOps.getUid()).thenReturn(1); ++ when(packageOps.getPackageName()).thenReturn("package.one"); ++ AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class); ++ when(entry.getOpStr()).thenReturn(AppOpsManager.OPSTR_RECORD_AUDIO); ++ ++ AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed1.isRunning()).thenReturn(false); ++ AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed2.isRunning()).thenReturn(true); ++ AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed3.isRunning()).thenReturn(true); ++ when(entry.getAttributedOpEntries()).thenReturn( ++ Map.of("attr1", attributed1, "attr2", attributed2, "attr3", attributed3)); ++ ++ when(packageOps.getOps()).thenReturn(List.of(entry)); ++ when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) ++ .thenReturn(List.of(packageOps)); ++ ++ // WHEN we start listening ++ mController.setListening(true); ++ ++ // THEN the active list has the ops ++ List list = mController.getActiveAppOps(); ++ // Multiple attributes get merged into one entry in the active ops ++ assertEquals(1, list.size()); ++ ++ AppOpItem first = list.get(0); ++ assertThat(first.getPackageName()).isEqualTo("package.one"); ++ assertThat(first.getUid()).isEqualTo(1); ++ assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_RECORD_AUDIO); ++ } ++ ++ /** Regression test for b/294104969. */ ++ @Test ++ public void addCallback_existingCallbacksNotifiedOfCurrentActive() { ++ AppOpsManager.PackageOps packageOps1 = createPackageOp( ++ "package.one", ++ /* packageUid= */ 1, ++ AppOpsManager.OPSTR_FINE_LOCATION, ++ /* isRunning= */ true); ++ AppOpsManager.PackageOps packageOps2 = createPackageOp( ++ "package.two", ++ /* packageUid= */ 2, ++ AppOpsManager.OPSTR_RECORD_AUDIO, ++ /* isRunning= */ true); ++ AppOpsManager.PackageOps packageOps3 = createPackageOp( ++ "package.three", ++ /* packageUid= */ 3, ++ AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, ++ /* isRunning= */ true); ++ when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) ++ .thenReturn(List.of(packageOps1, packageOps2, packageOps3)); ++ ++ // WHEN we start listening ++ mController.addCallback( ++ new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, ++ mCallback); ++ mTestableLooper.processAllMessages(); ++ ++ // THEN the callback is notified of the current active ops it cares about ++ verify(mCallback).onActiveStateChanged( ++ AppOpsManager.OP_FINE_LOCATION, ++ /* uid= */ 1, ++ "package.one", ++ true); ++ verify(mCallback).onActiveStateChanged( ++ AppOpsManager.OP_RECORD_AUDIO, ++ /* uid= */ 2, ++ "package.two", ++ true); ++ verify(mCallback, never()).onActiveStateChanged( ++ AppOpsManager.OP_PHONE_CALL_MICROPHONE, ++ /* uid= */ 3, ++ "package.three", ++ true); ++ } ++ + @Test + public void addCallback_includedCode() { + mController.addCallback( +@@ -673,6 +874,22 @@ public class AppOpsControllerTest extends SysuiTestCase { + assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(cameraIdx).getCode()); + } + ++ private AppOpsManager.PackageOps createPackageOp( ++ String packageName, int packageUid, String opStr, boolean isRunning) { ++ AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); ++ when(packageOps.getPackageName()).thenReturn(packageName); ++ when(packageOps.getUid()).thenReturn(packageUid); ++ AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class); ++ when(entry.getOpStr()).thenReturn(opStr); ++ AppOpsManager.AttributedOpEntry attributed = mock(AppOpsManager.AttributedOpEntry.class); ++ when(attributed.isRunning()).thenReturn(isRunning); ++ ++ when(packageOps.getOps()).thenReturn(Collections.singletonList(entry)); ++ when(entry.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed)); ++ ++ return packageOps; ++ } ++ + private class TestHandler extends AppOpsControllerImpl.H { + TestHandler(Looper looper) { + mController.super(looper); +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0229-Fix-vulnerability-that-allowed-attackers-to-start-arbitary-activ.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0229-Fix-vulnerability-that-allowed-attackers-to-start-arbitary-activ.bulletin.patch new file mode 100644 index 0000000000..f8ba0c8379 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0229-Fix-vulnerability-that-allowed-attackers-to-start-arbitary-activ.bulletin.patch @@ -0,0 +1,43 @@ +From ec851826a32b5173c27f5dd933c45fb4effe0984 Mon Sep 17 00:00:00 2001 +From: Will Leshner +Date: Tue, 31 Oct 2023 13:23:08 -0700 +Subject: [PATCH] Fix vulnerability that allowed attackers to start arbitary + activities + +Test: Flashed device and verified dream settings works as expected +Test: Installed APK from bug and verified the dream didn't allow +launching the inappropriate settings activity. +Fixes: 300090204 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6926fd15fb16c51468dde270bd61ee68772b8c14) +Merged-In: I573040df84bf98a493b39f96c8581e4303206bac +Change-Id: I573040df84bf98a493b39f96c8581e4303206bac +--- + .../com/android/settingslib/dream/DreamBackend.java | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +index ab7b54d98285..beadd821957b 100644 +--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java ++++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +@@ -351,7 +351,17 @@ public class DreamBackend { + if (cn != null && cn.indexOf('/') < 0) { + cn = resolveInfo.serviceInfo.packageName + "/" + cn; + } +- return cn == null ? null : ComponentName.unflattenFromString(cn); ++ // Ensure that the component is from the same package as the dream service. If not, ++ // treat the component as invalid and return null instead. ++ final ComponentName result = cn != null ? ComponentName.unflattenFromString(cn) : null; ++ if (result != null ++ && !result.getPackageName().equals(resolveInfo.serviceInfo.packageName)) { ++ Log.w(TAG, ++ "Inconsistent package name in component: " + result.getPackageName() ++ + ", should be: " + resolveInfo.serviceInfo.packageName); ++ return null; ++ } ++ return result; + } + + private static void logd(String msg, Object... args) { +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0230-DO-NOT-MERGE-Fix-ActivityManager-killBackgroundProcesses-permis.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0230-DO-NOT-MERGE-Fix-ActivityManager-killBackgroundProcesses-permis.bulletin.patch new file mode 100644 index 0000000000..e122e88670 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0230-DO-NOT-MERGE-Fix-ActivityManager-killBackgroundProcesses-permis.bulletin.patch @@ -0,0 +1,72 @@ +From 17d11d7be1d389b0f2dde2c1278d282bb2e0cb32 Mon Sep 17 00:00:00 2001 +From: Jing Ji +Date: Thu, 19 Oct 2023 14:22:58 -0700 +Subject: [PATCH] DO NOT MERGE: Fix ActivityManager#killBackgroundProcesses + permissions + +In the pevious CL, we incorrectly added the permission check in the +killBackgroundProcessesExcept. Now fix this issue. + +Bug: 239423414 +Bug: 223376078 +Test: atest CtsAppTestCases:ActivityManagerTest +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:140fce861944419a375c669010c6c47cd7ff5b37) +Merged-In: I9471a77188ee63ec32cd0c81569193e4ccad885b +Change-Id: I9471a77188ee63ec32cd0c81569193e4ccad885b +--- + .../server/am/ActivityManagerService.java | 32 +++++++++---------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java +index ee255b4223d0..43423e25376a 100644 +--- a/services/core/java/com/android/server/am/ActivityManagerService.java ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java +@@ -3663,6 +3663,22 @@ public class ActivityManagerService extends IActivityManager.Stub + throw new SecurityException(msg); + } + ++ final int callingUid = Binder.getCallingUid(); ++ final int callingPid = Binder.getCallingPid(); ++ ++ ProcessRecord proc; ++ synchronized (mPidsSelfLocked) { ++ proc = mPidsSelfLocked.get(callingPid); ++ } ++ if (callingUid >= FIRST_APPLICATION_UID ++ && (proc == null || !proc.info.isSystemApp())) { ++ final String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" ++ + callingPid + ", uid=" + callingUid + " is not allowed"; ++ Slog.w(TAG, msg); ++ // Silently return to avoid existing apps from crashing. ++ return; ++ } ++ + final long callingId = Binder.clearCallingIdentity(); + try { + synchronized (this) { +@@ -3703,22 +3719,6 @@ public class ActivityManagerService extends IActivityManager.Stub + throw new SecurityException(msg); + } + +- final int callingUid = Binder.getCallingUid(); +- final int callingPid = Binder.getCallingPid(); +- +- ProcessRecord proc; +- synchronized (mPidsSelfLocked) { +- proc = mPidsSelfLocked.get(callingPid); +- } +- if (callingUid >= FIRST_APPLICATION_UID +- && (proc == null || !proc.info.isSystemApp())) { +- final String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" +- + callingPid + ", uid=" + callingUid + " is not allowed"; +- Slog.w(TAG, msg); +- // Silently return to avoid existing apps from crashing. +- return; +- } +- + final long callingId = Binder.clearCallingIdentity(); + try { + synchronized (this) { +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/packages/apps/Camera2/05_0005-Camera2-Do-not-pass-location-info-for-startActivity-case.bulletin.patch b/aosp_diff/preliminary/packages/apps/Camera2/05_0005-Camera2-Do-not-pass-location-info-for-startActivity-case.bulletin.patch new file mode 100644 index 0000000000..24868437d6 --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/Camera2/05_0005-Camera2-Do-not-pass-location-info-for-startActivity-case.bulletin.patch @@ -0,0 +1,39 @@ +From e03a3c52fa50baf5485babb3c92894d83c4be182 Mon Sep 17 00:00:00 2001 +From: Shuzhen Wang +Date: Fri, 27 Oct 2023 16:08:05 -0700 +Subject: [PATCH] Camera2: Do not pass location info for startActivity case + +If the Camera2 activity is started by startActivity, we shouldn't +unconditionally grant location. + +Test: Use Camera2 app both independently and with INTENT +Bug: 285142084 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3c097bb0e516b1d071f00ac99a8f29f4a72579ff) +Merged-In: I3b78840f9b0fefeadea44150ea319886f06c1485 +Change-Id: I3b78840f9b0fefeadea44150ea319886f06c1485 +--- + src/com/android/camera/CameraActivity.java | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java +index 1a8134920..642acbab4 100644 +--- a/src/com/android/camera/CameraActivity.java ++++ b/src/com/android/camera/CameraActivity.java +@@ -1739,8 +1739,12 @@ public class CameraActivity extends QuickActivity + private boolean shouldUseNoOpLocation () { + String callingPackage = getCallingPackage(); + if (callingPackage == null) { +- // Activity not started through startActivityForResult. +- return false; ++ if (isCaptureIntent()) { ++ // Activity not started through startActivityForResult. ++ return true; ++ } else { ++ callingPackage = mAppContext.getPackageName(); ++ } + } + PackageInfo packageInfo = null; + try { +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/packages/apps/Nfc/03_0003-Possible-deadlock-on-the-NfcService-object.bulletin.patch b/aosp_diff/preliminary/packages/apps/Nfc/03_0003-Possible-deadlock-on-the-NfcService-object.bulletin.patch new file mode 100644 index 0000000000..d29726010f --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/Nfc/03_0003-Possible-deadlock-on-the-NfcService-object.bulletin.patch @@ -0,0 +1,33 @@ +From 6f66b111a8da5194d4ef6a974fbbdef960ca0f01 Mon Sep 17 00:00:00 2001 +From: Alisher Alikhodjaev +Date: Tue, 31 Oct 2023 11:13:03 -0700 +Subject: [PATCH] Possible deadlock on the NfcService object + +Bug: 268038643 +Bug: 307489565 +Test: CtsVerifier +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2d8ea70c65831313d73784fb3c78f64ff0cbd627) +Merged-In: I683ae425dafa4e209b9517b62ada7d8a694f84a9 +Change-Id: I683ae425dafa4e209b9517b62ada7d8a694f84a9 +--- + src/com/android/nfc/NfcService.java | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java +index bf988845..d9dde577 100644 +--- a/src/com/android/nfc/NfcService.java ++++ b/src/com/android/nfc/NfcService.java +@@ -1093,9 +1093,7 @@ public class NfcService implements DeviceHostListener { + } + + public boolean isSecureNfcEnabled() { +- synchronized (NfcService.this) { +- return mIsSecureNfcEnabled; +- } ++ return mIsSecureNfcEnabled; + } + + final class NfcAdapterService extends INfcAdapter.Stub { +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/packages/apps/Settings/37_0037-Validate-ringtone-URIs-before-setting.bulletin.patch b/aosp_diff/preliminary/packages/apps/Settings/37_0037-Validate-ringtone-URIs-before-setting.bulletin.patch new file mode 100644 index 0000000000..78f8f82123 --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/Settings/37_0037-Validate-ringtone-URIs-before-setting.bulletin.patch @@ -0,0 +1,318 @@ +From ad8ee349c428c983bfbaa63614967cd1e7d304df Mon Sep 17 00:00:00 2001 +From: Valentin Iftime +Date: Tue, 3 Oct 2023 17:28:34 +0200 +Subject: [PATCH] Validate ringtone URIs before setting + + Add checks URIs for content from other users. + Fail for users that are not profiles of the current user. + +Test: atest DefaultRingtonePreferenceTest +Bug: 299614635 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7ba175eaeb6e8f1ea54e2ec13685d1cf1e9aad1c) +Merged-In: Ib266b285a3a1c6c5265ae2321159e61e08e349f6 +Change-Id: Ib266b285a3a1c6c5265ae2321159e61e08e349f6 +--- + .../settings/DefaultRingtonePreference.java | 11 +-- + .../android/settings/RingtonePreference.java | 82 +++++++++++++++++++ + .../app/NotificationSoundPreference.java | 12 ++- + .../DefaultRingtonePreferenceTest.java | 75 ++++++++++++++++- + 4 files changed, 165 insertions(+), 15 deletions(-) + +diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java +index 9bf626c989..4c65488722 100644 +--- a/src/com/android/settings/DefaultRingtonePreference.java ++++ b/src/com/android/settings/DefaultRingtonePreference.java +@@ -51,16 +51,9 @@ public class DefaultRingtonePreference extends RingtonePreference { + return; + } + +- String mimeType = mUserContext.getContentResolver().getType(ringtoneUri); +- if (mimeType == null) { ++ if (!isValidRingtoneUri(ringtoneUri)) { + Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri +- + " ignored: failure to find mimeType (no access from this context?)"); +- return; +- } +- +- if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) { +- Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri +- + " ignored: associated mimeType:" + mimeType + " is not an audio type"); ++ + " ignored: invalid ringtone Uri"); + return; + } + +diff --git a/src/com/android/settings/RingtonePreference.java b/src/com/android/settings/RingtonePreference.java +index 8f9c618d5e..d283e390fc 100644 +--- a/src/com/android/settings/RingtonePreference.java ++++ b/src/com/android/settings/RingtonePreference.java +@@ -16,6 +16,8 @@ + + package com.android.settings; + ++import android.content.ContentProvider; ++import android.content.ContentResolver; + import android.content.Context; + import android.content.Intent; + import android.content.res.TypedArray; +@@ -23,9 +25,11 @@ import android.media.AudioAttributes; + import android.media.RingtoneManager; + import android.net.Uri; + import android.os.UserHandle; ++import android.os.UserManager; + import android.provider.Settings.System; + import android.text.TextUtils; + import android.util.AttributeSet; ++import android.util.Log; + + import androidx.preference.Preference; + import androidx.preference.PreferenceManager; +@@ -239,4 +243,82 @@ public class RingtonePreference extends Preference { + return true; + } + ++ public boolean isDefaultRingtone(Uri ringtoneUri) { ++ // null URIs are valid (None/silence) ++ return ringtoneUri == null || RingtoneManager.isDefault(ringtoneUri); ++ } ++ ++ protected boolean isValidRingtoneUri(Uri ringtoneUri) { ++ if (isDefaultRingtone(ringtoneUri)) { ++ return true; ++ } ++ ++ // Return early for android resource URIs ++ if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(ringtoneUri.getScheme())) { ++ return true; ++ } ++ ++ String mimeType = mUserContext.getContentResolver().getType(ringtoneUri); ++ if (mimeType == null) { ++ Log.e(TAG, "isValidRingtoneUri for URI:" + ringtoneUri ++ + " failed: failure to find mimeType (no access from this context?)"); ++ return false; ++ } ++ ++ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg") ++ || mimeType.equals("application/x-flac"))) { ++ Log.e(TAG, "isValidRingtoneUri for URI:" + ringtoneUri ++ + " failed: associated mimeType:" + mimeType + " is not an audio type"); ++ return false; ++ } ++ ++ // Validate userId from URIs: content://{userId}@... ++ final int userIdFromUri = ContentProvider.getUserIdFromUri(ringtoneUri, mUserId); ++ if (userIdFromUri != mUserId) { ++ final UserManager userManager = mUserContext.getSystemService(UserManager.class); ++ ++ if (!userManager.isSameProfileGroup(mUserId, userIdFromUri)) { ++ Log.e(TAG, ++ "isValidRingtoneUri for URI:" + ringtoneUri + " failed: user " + userIdFromUri ++ + " and user " + mUserId + " are not in the same profile group"); ++ return false; ++ } ++ ++ final int parentUserId; ++ final int profileUserId; ++ if (userManager.isProfile()) { ++ profileUserId = mUserId; ++ parentUserId = userIdFromUri; ++ } else { ++ parentUserId = mUserId; ++ profileUserId = userIdFromUri; ++ } ++ ++ final UserHandle parent = userManager.getProfileParent(UserHandle.of(profileUserId)); ++ if (parent == null || parent.getIdentifier() != parentUserId) { ++ Log.e(TAG, ++ "isValidRingtoneUri for URI:" + ringtoneUri + " failed: user " + profileUserId ++ + " is not a profile of user " + parentUserId); ++ return false; ++ } ++ ++ // Allow parent <-> managed profile sharing, unless restricted ++ if (userManager.hasUserRestrictionForUser( ++ UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, UserHandle.of(parentUserId))) { ++ Log.e(TAG, ++ "isValidRingtoneUri for URI:" + ringtoneUri + " failed: user " + parentUserId ++ + " has restriction: " + UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); ++ return false; ++ } ++ ++ if (!userManager.isManagedProfile(profileUserId)) { ++ Log.e(TAG, "isValidRingtoneUri for URI:" + ringtoneUri ++ + " failed: user " + profileUserId + " is not a managed profile"); ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ + } +diff --git a/src/com/android/settings/notification/app/NotificationSoundPreference.java b/src/com/android/settings/notification/app/NotificationSoundPreference.java +index 136b21ffd3..b55f9bd7ce 100644 +--- a/src/com/android/settings/notification/app/NotificationSoundPreference.java ++++ b/src/com/android/settings/notification/app/NotificationSoundPreference.java +@@ -25,10 +25,13 @@ import android.net.Uri; + import android.os.AsyncTask; + import android.util.AttributeSet; + ++import android.util.Log; + import com.android.settings.R; + import com.android.settings.RingtonePreference; + + public class NotificationSoundPreference extends RingtonePreference { ++ private static final String TAG = "NotificationSoundPreference"; ++ + private Uri mRingtone; + + public NotificationSoundPreference(Context context, AttributeSet attrs) { +@@ -50,8 +53,13 @@ public class NotificationSoundPreference extends RingtonePreference { + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (data != null) { + Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); +- setRingtone(uri); +- callChangeListener(uri); ++ if (isValidRingtoneUri(uri)) { ++ setRingtone(uri); ++ callChangeListener(uri); ++ } else { ++ Log.e(TAG, "onActivityResult for URI:" + uri ++ + " ignored: invalid ringtone Uri"); ++ } + } + + return true; +diff --git a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java +index 7877684dce..360a8a555b 100644 +--- a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java ++++ b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java +@@ -16,16 +16,19 @@ + + package com.android.settings; + ++import static org.mockito.ArgumentMatchers.any; + import static org.mockito.Mockito.doReturn; + import static org.mockito.Mockito.never; + import static org.mockito.Mockito.spy; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + ++import android.content.ContentInterface; + import android.content.ContentResolver; + import android.content.Context; +-import android.media.RingtoneManager; + import android.net.Uri; ++import android.os.UserHandle; ++import android.os.UserManager; + + import androidx.test.core.app.ApplicationProvider; + import androidx.test.ext.junit.runners.AndroidJUnit4; +@@ -34,17 +37,22 @@ import org.junit.Before; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.mockito.Mock; ++import org.mockito.Mockito; + import org.mockito.MockitoAnnotations; + + /** Unittest for DefaultRingtonePreference. */ + @RunWith(AndroidJUnit4.class) + public class DefaultRingtonePreferenceTest { + ++ private static final int OWNER_USER_ID = 1; ++ private static final int OTHER_USER_ID = 10; ++ private static final int INVALID_RINGTONE_TYPE = 0; + private DefaultRingtonePreference mDefaultRingtonePreference; + + @Mock + private ContentResolver mContentResolver; + @Mock ++ private UserManager mUserManager; + private Uri mRingtoneUri; + + @Before +@@ -52,14 +60,24 @@ public class DefaultRingtonePreferenceTest { + MockitoAnnotations.initMocks(this); + + Context context = spy(ApplicationProvider.getApplicationContext()); +- doReturn(mContentResolver).when(context).getContentResolver(); ++ mContentResolver = ContentResolver.wrap(Mockito.mock(ContentInterface.class)); ++ when(context.getContentResolver()).thenReturn(mContentResolver); + + mDefaultRingtonePreference = spy(new DefaultRingtonePreference(context, null /* attrs */)); + doReturn(context).when(mDefaultRingtonePreference).getContext(); ++ ++ // Use INVALID_RINGTONE_TYPE to return early in RingtoneManager.setActualDefaultRingtoneUri + when(mDefaultRingtonePreference.getRingtoneType()) +- .thenReturn(RingtoneManager.TYPE_RINGTONE); +- mDefaultRingtonePreference.setUserId(1); ++ .thenReturn(INVALID_RINGTONE_TYPE); ++ ++ mDefaultRingtonePreference.setUserId(OWNER_USER_ID); + mDefaultRingtonePreference.mUserContext = context; ++ when(mDefaultRingtonePreference.isDefaultRingtone(any(Uri.class))).thenReturn(false); ++ ++ when(context.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE); ++ when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); ++ ++ mRingtoneUri = Uri.parse("content://none"); + } + + @Test +@@ -79,4 +97,53 @@ public class DefaultRingtonePreferenceTest { + + verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); + } ++ ++ @Test ++ public void onSaveRingtone_notManagedProfile_shouldNotSetRingtone() { ++ mRingtoneUri = Uri.parse("content://" + OTHER_USER_ID + "@ringtone"); ++ when(mContentResolver.getType(mRingtoneUri)).thenReturn("audio/*"); ++ when(mUserManager.isSameProfileGroup(OWNER_USER_ID, OTHER_USER_ID)).thenReturn(true); ++ when(mUserManager.getProfileParent(UserHandle.of(OTHER_USER_ID))).thenReturn( ++ UserHandle.of(OWNER_USER_ID)); ++ when(mUserManager.isManagedProfile(OTHER_USER_ID)).thenReturn(false); ++ ++ mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); ++ ++ verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); ++ } ++ ++ @Test ++ public void onSaveRingtone_notSameUser_shouldNotSetRingtone() { ++ mRingtoneUri = Uri.parse("content://" + OTHER_USER_ID + "@ringtone"); ++ when(mContentResolver.getType(mRingtoneUri)).thenReturn("audio/*"); ++ when(mUserManager.isSameProfileGroup(OWNER_USER_ID, OTHER_USER_ID)).thenReturn(false); ++ ++ mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); ++ ++ verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); ++ } ++ ++ @Test ++ public void onSaveRingtone_isManagedProfile_shouldSetRingtone() { ++ mRingtoneUri = Uri.parse("content://" + OTHER_USER_ID + "@ringtone"); ++ when(mContentResolver.getType(mRingtoneUri)).thenReturn("audio/*"); ++ when(mUserManager.isSameProfileGroup(OWNER_USER_ID, OTHER_USER_ID)).thenReturn(true); ++ when(mUserManager.getProfileParent(UserHandle.of(OTHER_USER_ID))).thenReturn( ++ UserHandle.of(OWNER_USER_ID)); ++ when(mUserManager.isManagedProfile(OTHER_USER_ID)).thenReturn(true); ++ ++ mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); ++ ++ verify(mDefaultRingtonePreference).setActualDefaultRingtoneUri(mRingtoneUri); ++ } ++ ++ @Test ++ public void onSaveRingtone_defaultUri_shouldSetRingtone() { ++ mRingtoneUri = Uri.parse("default_ringtone"); ++ when(mDefaultRingtonePreference.isDefaultRingtone(any(Uri.class))).thenReturn(true); ++ ++ mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); ++ ++ verify(mDefaultRingtonePreference).setActualDefaultRingtoneUri(mRingtoneUri); ++ } + } +-- +2.43.0.rc1.413.gea7ed67945-goog + diff --git a/aosp_diff/preliminary/system/bt/49_0049--conflict-Merge-Fix-some-OOB-errors-in-BTM-parsing-into-rvc-d.bulletin.patch b/aosp_diff/preliminary/system/bt/49_0049--conflict-Merge-Fix-some-OOB-errors-in-BTM-parsing-into-rvc-d.bulletin.patch new file mode 100644 index 0000000000..612118de08 --- /dev/null +++ b/aosp_diff/preliminary/system/bt/49_0049--conflict-Merge-Fix-some-OOB-errors-in-BTM-parsing-into-rvc-d.bulletin.patch @@ -0,0 +1,139 @@ +From b652a67787ebc64374955a696ee7d593be0e935c Mon Sep 17 00:00:00 2001 +From: Brian Delwiche +Date: Tue, 10 Oct 2023 23:46:17 +0000 +Subject: [PATCH] [conflict] Merge "Fix some OOB errors in BTM parsing" into + rvc-dev am: d8ecaf17b4 am: 91f5cb80a3 + +Original change: https://googleplex-android-review.googlesource.com/c/platform/system/bt/+/23399019 + +Bug: 279169188 +Signed-off-by: Automerger Merge Worker +(cherry picked from commit 71b8613d95d78817cda6c49f2a7e849ce4e99339) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:39f169ac20960710c308079236ad3d631e6ef833) +Merged-In: I294455124fbd06f5742b64f8bae5455f09358fe4 +Change-Id: I294455124fbd06f5742b64f8bae5455f09358fe4 +--- + stack/btm/btm_ble_gap.cc | 52 +++++++++++++++++++++++++++++----------- + stack/btu/btu_hcif.cc | 6 +++++ + 2 files changed, 44 insertions(+), 14 deletions(-) + +diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc +index 9f8f7b0b7..ef76910bd 100644 +--- a/stack/btm/btm_ble_gap.cc ++++ b/stack/btm/btm_ble_gap.cc +@@ -1731,20 +1731,27 @@ void btm_ble_process_ext_adv_pkt(uint8_t data_len, uint8_t* data) { + advertising_sid; + int8_t rssi, tx_power; + uint16_t event_type, periodic_adv_int, direct_address_type; ++ size_t bytes_to_process; + + /* Only process the results if the inquiry is still active */ + if (!btm_cb.ble_ctr_cb.is_ble_scan_active()) return; + ++ bytes_to_process = 1; ++ ++ if (data_len < bytes_to_process) { ++ LOG(ERROR) << "Malformed LE extended advertising packet: not enough room " ++ "for num reports"; ++ return; ++ } ++ + /* Extract the number of reports in this event. */ + STREAM_TO_UINT8(num_reports, p); + +- constexpr int extended_report_header_size = 24; + while (num_reports--) { +- if (p + extended_report_header_size > data + data_len) { +- // TODO(jpawlowski): we should crash the stack here +- BTM_TRACE_ERROR( +- "Malformed LE Extended Advertising Report Event from controller - " +- "can't loop the data"); ++ bytes_to_process += 24; ++ if (data_len < bytes_to_process) { ++ LOG(ERROR) << "Malformed LE extended advertising packet: not enough room " ++ "for metadata"; + return; + } + +@@ -1764,8 +1771,11 @@ void btm_ble_process_ext_adv_pkt(uint8_t data_len, uint8_t* data) { + + uint8_t* pkt_data = p; + p += pkt_data_len; /* Advance to the the next packet*/ +- if (p > data + data_len) { +- LOG(ERROR) << "Invalid pkt_data_len: " << +pkt_data_len; ++ ++ bytes_to_process += pkt_data_len; ++ if (data_len < bytes_to_process) { ++ LOG(ERROR) << "Malformed LE extended advertising packet: not enough room " ++ "for packet data"; + return; + } + +@@ -1794,18 +1804,28 @@ void btm_ble_process_adv_pkt(uint8_t data_len, uint8_t* data) { + uint8_t* p = data; + uint8_t legacy_evt_type, addr_type, num_reports, pkt_data_len; + int8_t rssi; ++ size_t bytes_to_process; + + /* Only process the results if the inquiry is still active */ + if (!btm_cb.ble_ctr_cb.is_ble_scan_active()) return; + ++ bytes_to_process = 1; ++ ++ if (data_len < bytes_to_process) { ++ LOG(ERROR) ++ << "Malformed LE advertising packet: not enough room for num reports"; ++ return; ++ } ++ + /* Extract the number of reports in this event. */ + STREAM_TO_UINT8(num_reports, p); + +- constexpr int report_header_size = 10; + while (num_reports--) { +- if (p + report_header_size > data + data_len) { +- // TODO(jpawlowski): we should crash the stack here +- BTM_TRACE_ERROR("Malformed LE Advertising Report Event from controller"); ++ bytes_to_process += 9; ++ ++ if (data_len < bytes_to_process) { ++ LOG(ERROR) ++ << "Malformed LE advertising packet: not enough room for metadata"; + return; + } + +@@ -1817,8 +1837,12 @@ void btm_ble_process_adv_pkt(uint8_t data_len, uint8_t* data) { + + uint8_t* pkt_data = p; + p += pkt_data_len; /* Advance to the the rssi byte */ +- if (p > data + data_len - sizeof(rssi)) { +- LOG(ERROR) << "Invalid pkt_data_len: " << +pkt_data_len; ++ ++ // include rssi for this check ++ bytes_to_process += pkt_data_len + 1; ++ if (data_len < bytes_to_process) { ++ LOG(ERROR) << "Malformed LE advertising packet: not enough room for " ++ "packet data and/or RSSI"; + return; + } + +diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc +index a2d9ef8af..b2a7869a3 100644 +--- a/stack/btu/btu_hcif.cc ++++ b/stack/btu/btu_hcif.cc +@@ -1765,6 +1765,12 @@ static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len) { + return; + } + ++ // 2 bytes each for handle, tx_data_len, TxTimer, rx_data_len ++ if (evt_len < 8) { ++ LOG_ERROR("Event packet too short"); ++ return; ++ } ++ + STREAM_TO_UINT16(handle, p); + STREAM_TO_UINT16(tx_data_len, p); + p += 2; /* Skip the TxTimer */ +-- +2.43.0.rc1.413.gea7ed67945-goog +