From 3e1b4e374b1f6386ccfe5f18789625f833c1afb5 Mon Sep 17 00:00:00 2001 From: "Alam, SahibeX" Date: Fri, 20 Oct 2023 00:53:12 +0530 Subject: [PATCH] ASB - Security Patch integration November 2023 Integrating Security Patches Test done: STS TCs Passed Tracked-On: OAM-112870 Signed-off-by: Alam, SahibeX --- ...4-Update-security_patch_level-string.patch | 2 +- ...sue-flagged-by-fuzzer-test-.bulletin.patch | 82 ++ ...sue-flagged-by-fuzzer-test-.bulletin.patch | 75 ++ ...ffer-to-NULL-in-constructor.bulletin.patch | 35 + ...n-registering-phoneAccounts.bulletin.patch | 77 ++ ...ing-icon-in-Device-Controls.bulletin.patch | 459 ++++++++++ ...-notification-publicVersion.bulletin.patch | 54 ++ ...backupAgentCreated-callback.bulletin.patch | 66 ++ ...-API-of-readParcelableArray.bulletin.patch | 34 + ...e-in-DNS64-discovery-thread.bulletin.patch | 213 +++++ ...eader-thread-a-class-member.bulletin.patch | 106 +++ ...s-mms-db-from-work-profile-.bulletin.patch | 821 ++++++++++++++++++ ...n-registering-phoneAccounts.bulletin.patch | 484 +++++++++++ ...emove-E-Tugra-certificates-.bulletin.patch | 152 ++++ 14 files changed, 2659 insertions(+), 1 deletion(-) create mode 100644 aosp_diff/preliminary/frameworks/av/26_0026-Fix-for-heap-buffer-overflow-issue-flagged-by-fuzzer-test-.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/av/27_0027-Fix-heap-use-after-free-issue-flagged-by-fuzzer-test-.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/av/28_0028-Initialise-VPS-buffer-to-NULL-in-constructor.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0203-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0205-Add-userId-check-before-loading-icon-in-Device-Controls.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0206-DO-NOT-MERGE-Fix-BAL-via-notification-publicVersion.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0207--DO-NOT-MERGE-Check-caller-s-uid-in-backupAgentCreated-callback.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0208-Use-type-safe-API-of-readParcelableArray.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/modules/DnsResolver/0001-Fix-use-after-free-in-DNS64-discovery-thread.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/modules/StatsD/0001-Make-log-reader-thread-a-class-member.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/providers/TelephonyProvider/0003-DO-NOT-MERGE-Block-access-to-sms-mms-db-from-work-profile-.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/services/Telecomm/13_0013-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch create mode 100644 aosp_diff/preliminary/system/ca-certificates/0002-Remove-E-Tugra-certificates-.bulletin.patch 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 40ceb7d09c..afb9ccec64 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-10-01 ++ PLATFORM_SECURITY_PATCH := 2023-11-01 endif .KATI_READONLY := PLATFORM_SECURITY_PATCH diff --git a/aosp_diff/preliminary/frameworks/av/26_0026-Fix-for-heap-buffer-overflow-issue-flagged-by-fuzzer-test-.bulletin.patch b/aosp_diff/preliminary/frameworks/av/26_0026-Fix-for-heap-buffer-overflow-issue-flagged-by-fuzzer-test-.bulletin.patch new file mode 100644 index 0000000000..fceb0e8895 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/av/26_0026-Fix-for-heap-buffer-overflow-issue-flagged-by-fuzzer-test-.bulletin.patch @@ -0,0 +1,82 @@ +From c9558b05adfe11520e8257ebb061ebeffae4f1bb Mon Sep 17 00:00:00 2001 +From: Shruti Bihani +Date: Mon, 10 Jul 2023 08:53:42 +0000 +Subject: [PATCH] Fix for heap buffer overflow issue flagged by fuzzer test. + +OOB write occurs when a value is assigned to a buffer index which is greater than the buffer size. Adding a check on buffer bounds fixes the issue. + +Similar checks have been added wherever applicable on other such methods of the class. + +Bug: 243463593 +Test: Build mtp_packet_fuzzer and run on the target device +(cherry picked from commit a669e34bb8e6f0f7b5d7a35144bd342271a24712) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:38a83caefc4b5fd5aa1071bbabf0c71f49e6ac80) +Merged-In: Icd0f2307803a1a35e655bc08d9d4cca5e2b58a9b +Change-Id: Icd0f2307803a1a35e655bc08d9d4cca5e2b58a9b +--- + media/mtp/MtpPacket.cpp | 40 +++++++++++++++++++++++++++++++--------- + 1 file changed, 31 insertions(+), 9 deletions(-) + +diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp +index f069a83b5f..5faaac2026 100644 +--- a/media/mtp/MtpPacket.cpp ++++ b/media/mtp/MtpPacket.cpp +@@ -92,24 +92,46 @@ void MtpPacket::copyFrom(const MtpPacket& src) { + } + + uint16_t MtpPacket::getUInt16(int offset) const { +- return ((uint16_t)mBuffer[offset + 1] << 8) | (uint16_t)mBuffer[offset]; ++ if ((unsigned long)(offset+2) <= mBufferSize) { ++ return ((uint16_t)mBuffer[offset + 1] << 8) | (uint16_t)mBuffer[offset]; ++ } ++ else { ++ ALOGE("offset for buffer read is greater than buffer size!"); ++ abort(); ++ } + } + + uint32_t MtpPacket::getUInt32(int offset) const { +- return ((uint32_t)mBuffer[offset + 3] << 24) | ((uint32_t)mBuffer[offset + 2] << 16) | +- ((uint32_t)mBuffer[offset + 1] << 8) | (uint32_t)mBuffer[offset]; ++ if ((unsigned long)(offset+4) <= mBufferSize) { ++ return ((uint32_t)mBuffer[offset + 3] << 24) | ((uint32_t)mBuffer[offset + 2] << 16) | ++ ((uint32_t)mBuffer[offset + 1] << 8) | (uint32_t)mBuffer[offset]; ++ } ++ else { ++ ALOGE("offset for buffer read is greater than buffer size!"); ++ abort(); ++ } + } + + void MtpPacket::putUInt16(int offset, uint16_t value) { +- mBuffer[offset++] = (uint8_t)(value & 0xFF); +- mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF); ++ if ((unsigned long)(offset+2) <= mBufferSize) { ++ mBuffer[offset++] = (uint8_t)(value & 0xFF); ++ mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF); ++ } ++ else { ++ ALOGE("offset for buffer write is greater than buffer size!"); ++ } + } + + void MtpPacket::putUInt32(int offset, uint32_t value) { +- mBuffer[offset++] = (uint8_t)(value & 0xFF); +- mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF); +- mBuffer[offset++] = (uint8_t)((value >> 16) & 0xFF); +- mBuffer[offset++] = (uint8_t)((value >> 24) & 0xFF); ++ if ((unsigned long)(offset+4) <= mBufferSize) { ++ mBuffer[offset++] = (uint8_t)(value & 0xFF); ++ mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF); ++ mBuffer[offset++] = (uint8_t)((value >> 16) & 0xFF); ++ mBuffer[offset++] = (uint8_t)((value >> 24) & 0xFF); ++ } ++ else { ++ ALOGE("offset for buffer write is greater than buffer size!"); ++ } + } + + uint16_t MtpPacket::getContainerCode() const { +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/av/27_0027-Fix-heap-use-after-free-issue-flagged-by-fuzzer-test-.bulletin.patch b/aosp_diff/preliminary/frameworks/av/27_0027-Fix-heap-use-after-free-issue-flagged-by-fuzzer-test-.bulletin.patch new file mode 100644 index 0000000000..c0e2b05d62 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/av/27_0027-Fix-heap-use-after-free-issue-flagged-by-fuzzer-test-.bulletin.patch @@ -0,0 +1,75 @@ +From 38888a8b8bbb0008714539ea141c5341d8e35ff5 Mon Sep 17 00:00:00 2001 +From: Shruti Bihani +Date: Thu, 13 Jul 2023 09:19:08 +0000 +Subject: [PATCH] Fix heap-use-after-free issue flagged by fuzzer test. + +A data member of class MtpFfsHandle is being accessed after the class object has been freed in the fuzzer. The method accessing the data member is running in a separate thread that gets detached from its parent. Using a conditional variable with an atomic int predicate in the close() function to ensure the detached thread's execution has completed before freeing the object fixes the issue without blocking the processing mid-way. + +Bug: 243381410 +Test: Build mtp_handle_fuzzer and run on the target device +(cherry picked from commit 50bf46a3f62136386548a9187a749936bda3ee8f) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e376b3dd401339cf736b1f76948b2f2338a647c9) +Merged-In: I41dde165a5eba151c958b81417d9e1065af1b411 +Change-Id: I41dde165a5eba151c958b81417d9e1065af1b411 +--- + media/mtp/MtpFfsHandle.cpp | 14 ++++++++++++++ + media/mtp/MtpFfsHandle.h | 4 ++++ + 2 files changed, 18 insertions(+) + +diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp +index 2ffd7759e0..ef8c9aa789 100644 +--- a/media/mtp/MtpFfsHandle.cpp ++++ b/media/mtp/MtpFfsHandle.cpp +@@ -297,6 +297,10 @@ int MtpFfsHandle::start(bool ptp) { + } + + void MtpFfsHandle::close() { ++ auto timeout = std::chrono::seconds(2); ++ std::unique_lock lk(m); ++ cv.wait_for(lk, timeout ,[this]{return child_threads==0;}); ++ + io_destroy(mCtx); + closeEndpoints(); + closeConfig(); +@@ -669,6 +673,11 @@ int MtpFfsHandle::sendEvent(mtp_event me) { + char *temp = new char[me.length]; + memcpy(temp, me.data, me.length); + me.data = temp; ++ ++ std::unique_lock lk(m); ++ child_threads++; ++ lk.unlock(); ++ + std::thread t([this, me]() { return this->doSendEvent(me); }); + t.detach(); + return 0; +@@ -680,6 +689,11 @@ void MtpFfsHandle::doSendEvent(mtp_event me) { + if (static_cast(ret) != length) + PLOG(ERROR) << "Mtp error sending event thread!"; + delete[] reinterpret_cast(me.data); ++ ++ std::unique_lock lk(m); ++ child_threads--; ++ lk.unlock(); ++ cv.notify_one(); + } + + } // namespace android +diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h +index e552e03bec..51cdef0953 100644 +--- a/media/mtp/MtpFfsHandle.h ++++ b/media/mtp/MtpFfsHandle.h +@@ -60,6 +60,10 @@ protected: + bool mCanceled; + bool mBatchCancel; + ++ std::mutex m; ++ std::condition_variable cv; ++ std::atomic child_threads{0}; ++ + android::base::unique_fd mControl; + // "in" from the host's perspective => sink for mtp server + android::base::unique_fd mBulkIn; +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/av/28_0028-Initialise-VPS-buffer-to-NULL-in-constructor.bulletin.patch b/aosp_diff/preliminary/frameworks/av/28_0028-Initialise-VPS-buffer-to-NULL-in-constructor.bulletin.patch new file mode 100644 index 0000000000..805751feaa --- /dev/null +++ b/aosp_diff/preliminary/frameworks/av/28_0028-Initialise-VPS-buffer-to-NULL-in-constructor.bulletin.patch @@ -0,0 +1,35 @@ +From 911ecf2f0a94045acd4b93185fb911631a15a322 Mon Sep 17 00:00:00 2001 +From: Venkatarama Avadhani +Date: Fri, 11 Aug 2023 15:19:24 +0000 +Subject: [PATCH] Initialise VPS buffer to NULL in constructor + +Missing initialisation of this pointer could lead to an incorrect free +if the ARTWriter object is cleared immeddiately after the constructor +call. + +Bug: 287298721 +Test: rtp_writer_fuzzer +(cherry picked from https://partner-android-review.googlesource.com/q/commit:2710696b001f2e95586151c1ee337a4e3c4da48a) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:900195c1d3589c7cbf9e116f61bebaefc0519101) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0efe2b4d6b739650039c2cab176ef11d5f5ac49c) +Merged-In: I08eacd7a0201bc9a41b821e20cae916d8870147a +Change-Id: I08eacd7a0201bc9a41b821e20cae916d8870147a +--- + media/libstagefright/rtsp/ARTPWriter.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp +index 11c7aeb9fc..1e08606407 100644 +--- a/media/libstagefright/rtsp/ARTPWriter.cpp ++++ b/media/libstagefright/rtsp/ARTPWriter.cpp +@@ -105,6 +105,7 @@ ARTPWriter::ARTPWriter(int fd) + + mRTCPAddr = mRTPAddr; + mRTCPAddr.sin_port = htons(ntohs(mRTPAddr.sin_port) | 1); ++ mVPSBuf = NULL; + mSPSBuf = NULL; + mPPSBuf = NULL; + +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0203-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0203-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch new file mode 100644 index 0000000000..488e10223f --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0203-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch @@ -0,0 +1,77 @@ +From 702cbce9997e4d70c3cb1670bf61e004c909eb23 Mon Sep 17 00:00:00 2001 +From: Thomas Stuart +Date: Mon, 21 Nov 2022 17:38:21 -0800 +Subject: [PATCH] enforce stricter rules when registering phoneAccounts + +- include disable accounts when looking up accounts for a package to + check if the limit is reached (10) +- put a new limit of 10 supported schemes +- put a new limit of 256 characters per scheme +- put a new limit of 256 characters per address +- ensure the Icon can write to memory w/o throwing an exception + +bug: 259064622 +bug: 256819769 +Test: cts + unit +Change-Id: Ia7d8d00d9de0fb6694ded6a80c40bd55d7fdf7a7 +Merged-In: Ia7d8d00d9de0fb6694ded6a80c40bd55d7fdf7a7 +(cherry picked from commit on googleplex-android-review.googlesource.com host: 6a02885f90fa64d88bac31efbcdbc2bfe0a9328f) +Merged-In: Ia7d8d00d9de0fb6694ded6a80c40bd55d7fdf7a7 +--- + .../java/android/telecom/PhoneAccount.java | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java +index e332d3ff2b4d..808d032f5d66 100644 +--- a/telecomm/java/android/telecom/PhoneAccount.java ++++ b/telecomm/java/android/telecom/PhoneAccount.java +@@ -517,6 +517,11 @@ public final class PhoneAccount implements Parcelable { + + /** + * Sets the address. See {@link PhoneAccount#getAddress}. ++ *

++ * Note: The entire URI value is limited to 256 characters. This check is ++ * enforced when registering the PhoneAccount via ++ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an ++ * {@link IllegalArgumentException} to be thrown if URI is over 256. + * + * @param value The address of the phone account. + * @return The builder. +@@ -550,6 +555,10 @@ public final class PhoneAccount implements Parcelable { + + /** + * Sets the icon. See {@link PhoneAccount#getIcon}. ++ *

++ * Note: An {@link IllegalArgumentException} if the Icon cannot be written to memory. ++ * This check is enforced when registering the PhoneAccount via ++ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} + * + * @param icon The icon to set. + */ +@@ -583,6 +592,10 @@ public final class PhoneAccount implements Parcelable { + /** + * Specifies an additional URI scheme supported by the {@link PhoneAccount}. + * ++ *

++ * Each URI scheme is limited to 256 characters. Adding a scheme over 256 characters will ++ * cause an {@link IllegalArgumentException} to be thrown when the account is registered. ++ * + * @param uriScheme The URI scheme. + * @return The builder. + */ +@@ -596,6 +609,12 @@ public final class PhoneAccount implements Parcelable { + /** + * Specifies the URI schemes supported by the {@link PhoneAccount}. + * ++ *

++ * A max of 10 URI schemes can be added per account. Additionally, each URI scheme is ++ * limited to 256 characters. Adding more than 10 URI schemes or 256 characters on any ++ * scheme will cause an {@link IllegalArgumentException} to be thrown when the account ++ * is registered. ++ * + * @param uriSchemes The URI schemes. + * @return The builder. + */ +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0205-Add-userId-check-before-loading-icon-in-Device-Controls.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0205-Add-userId-check-before-loading-icon-in-Device-Controls.bulletin.patch new file mode 100644 index 0000000000..7885ddef67 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0205-Add-userId-check-before-loading-icon-in-Device-Controls.bulletin.patch @@ -0,0 +1,459 @@ +From 3377062c467c02fe135479111f81f07726c77b49 Mon Sep 17 00:00:00 2001 +From: Anton Potapov +Date: Fri, 7 Jul 2023 12:05:10 +0100 +Subject: [PATCH] Add userId check before loading icon in Device Controls + +Test: manual with the steps from the bug +Test: manual with a normal icon +Test: atest CanUseIconPredicate +Test: atest ControlViewHolderTest +Bug: 272025416 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:22f18e021fa884dc504616a5adfb99ea9d2d77c6) +Merged-In: Iba846f19098c71c0519470cd7b8c1fd60d47e70b +Change-Id: Iba846f19098c71c0519470cd7b8c1fd60d47e70b +--- + .../controls/management/ControlAdapter.kt | 11 ++- + .../management/ControlsEditingActivity.kt | 2 +- + .../management/ControlsFavoritingActivity.kt | 5 +- + .../controls/management/StructureAdapter.kt | 11 +-- + .../controls/ui/CanUseIconPredicate.kt | 30 +++++++++ + .../systemui/controls/ui/ControlViewHolder.kt | 54 +++++++-------- + .../controls/ui/ControlsUiControllerImpl.kt | 3 +- + .../controls/ui/TemperatureControlBehavior.kt | 2 +- + .../systemui/controls/ui/ThumbnailBehavior.kt | 11 ++- + .../controls/ui/CanUseIconPredicateTest.kt | 67 +++++++++++++++++++ + .../controls/ui/ControlViewHolderTest.kt | 3 +- + 11 files changed, 157 insertions(+), 42 deletions(-) + create mode 100644 packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt + create mode 100644 packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt + +diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +index 40662536e57e..45916d6e24ab 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +@@ -36,6 +36,7 @@ import androidx.recyclerview.widget.GridLayoutManager + import androidx.recyclerview.widget.RecyclerView + import com.android.systemui.R + import com.android.systemui.controls.ControlInterface ++import com.android.systemui.controls.ui.CanUseIconPredicate + import com.android.systemui.controls.ui.RenderInfo + + private typealias ModelFavoriteChanger = (String, Boolean) -> Unit +@@ -49,7 +50,8 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit + * @property elevation elevation of each control view + */ + class ControlAdapter( +- private val elevation: Float ++ private val elevation: Float, ++ private val currentUserId: Int + ) : RecyclerView.Adapter() { + + companion object { +@@ -84,6 +86,7 @@ class ControlAdapter( + background = parent.context.getDrawable( + R.drawable.control_background_ripple) + }, ++ currentUserId, + model?.moveHelper // Indicates that position information is needed + ) { id, favorite -> + model?.changeFavoriteStatus(id, favorite) +@@ -189,6 +192,7 @@ private class ZoneHolder(view: View) : Holder(view) { + */ + internal class ControlHolder( + view: View, ++ currentUserId: Int, + val moveHelper: ControlsModel.MoveHelper?, + val favoriteCallback: ModelFavoriteChanger + ) : Holder(view) { +@@ -205,6 +209,7 @@ internal class ControlHolder( + visibility = View.VISIBLE + } + ++ private val canUseIconPredicate = CanUseIconPredicate(currentUserId) + private val accessibilityDelegate = ControlHolderAccessibilityDelegate( + this::stateDescription, + this::getLayoutPosition, +@@ -264,7 +269,9 @@ internal class ControlHolder( + val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme()) + + icon.imageTintList = null +- ci.customIcon?.let { ++ ci.customIcon ++ ?.takeIf(canUseIconPredicate) ++ ?.let { + icon.setImageIcon(it) + } ?: run { + icon.setImageDrawable(ri.icon) +diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +index 6f94943472b1..0ecfa3d1dd27 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +@@ -180,7 +180,7 @@ class ControlsEditingActivity @Inject constructor( + val elevation = resources.getFloat(R.dimen.control_card_elevation) + val recyclerView = requireViewById(R.id.list) + recyclerView.alpha = 0.0f +- val adapter = ControlAdapter(elevation).apply { ++ val adapter = ControlAdapter(elevation, currentUserTracker.currentUserId).apply { + registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + var hasAnimated = false + override fun onChanged() { +diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +index dca52a9678b9..ab5bc7c707f4 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +@@ -164,7 +164,8 @@ class ControlsFavoritingActivity @Inject constructor( + } + + executor.execute { +- structurePager.adapter = StructureAdapter(listOfStructures) ++ structurePager.adapter = StructureAdapter(listOfStructures, ++ currentUserTracker.currentUserId) + structurePager.setCurrentItem(structureIndex) + if (error) { + statusText.text = resources.getString(R.string.controls_favorite_load_error, +@@ -210,7 +211,7 @@ class ControlsFavoritingActivity @Inject constructor( + structurePager.alpha = 0.0f + pageIndicator.alpha = 0.0f + structurePager.apply { +- adapter = StructureAdapter(emptyList()) ++ adapter = StructureAdapter(emptyList(), currentUserTracker.currentUserId) + registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) +diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt +index cb67454195ec..7524f1cc2226 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt +@@ -24,13 +24,15 @@ import androidx.recyclerview.widget.RecyclerView + import com.android.systemui.R + + class StructureAdapter( +- private val models: List ++ private val models: List, ++ private val currentUserId: Int + ) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder { + val layoutInflater = LayoutInflater.from(parent.context) + return StructureHolder( +- layoutInflater.inflate(R.layout.controls_structure_page, parent, false) ++ layoutInflater.inflate(R.layout.controls_structure_page, parent, false), ++ currentUserId + ) + } + +@@ -40,7 +42,8 @@ class StructureAdapter( + holder.bind(models[index].model) + } + +- class StructureHolder(view: View) : RecyclerView.ViewHolder(view) { ++ class StructureHolder(view: View, currentUserId: Int) : ++ RecyclerView.ViewHolder(view) { + + private val recyclerView: RecyclerView + private val controlAdapter: ControlAdapter +@@ -48,7 +51,7 @@ class StructureAdapter( + init { + recyclerView = itemView.requireViewById(R.id.listAll) + val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation) +- controlAdapter = ControlAdapter(elevation) ++ controlAdapter = ControlAdapter(elevation, currentUserId) + setUpRecyclerView() + } + +diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt +new file mode 100644 +index 000000000000..61c21237144d +--- /dev/null ++++ b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2023 The Android Open Source Project ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.android.systemui.controls.ui ++ ++import android.content.ContentProvider ++import android.graphics.drawable.Icon ++ ++class CanUseIconPredicate(private val currentUserId: Int) : (Icon) -> Boolean { ++ ++ override fun invoke(icon: Icon): Boolean = ++ if (icon.type == Icon.TYPE_URI || icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) { ++ ContentProvider.getUserIdFromUri(icon.uri, currentUserId) == currentUserId ++ } else { ++ true ++ } ++} +diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +index 47e749cd1185..d79cb7ae8617 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +@@ -54,7 +54,6 @@ import com.android.systemui.animation.Interpolators + import com.android.systemui.controls.ControlsMetricsLogger + import com.android.systemui.controls.controller.ControlsController + import com.android.systemui.util.concurrency.DelayableExecutor +-import kotlin.reflect.KClass + + /** + * Wraps the widgets that make up the UI representation of a {@link Control}. Updates to the view +@@ -68,7 +67,8 @@ class ControlViewHolder( + val bgExecutor: DelayableExecutor, + val controlActionCoordinator: ControlActionCoordinator, + val controlsMetricsLogger: ControlsMetricsLogger, +- val uid: Int ++ val uid: Int, ++ val currentUserId: Int + ) { + + companion object { +@@ -85,27 +85,6 @@ class ControlViewHolder( + private val ATTR_DISABLED = intArrayOf(-android.R.attr.state_enabled) + const val MIN_LEVEL = 0 + const val MAX_LEVEL = 10000 +- +- fun findBehaviorClass( +- status: Int, +- template: ControlTemplate, +- deviceType: Int +- ): KClass { +- return when { +- status != Control.STATUS_OK -> StatusBehavior::class +- template == ControlTemplate.NO_TEMPLATE -> TouchBehavior::class +- template is ThumbnailTemplate -> ThumbnailBehavior::class +- +- // Required for legacy support, or where cameras do not use the new template +- deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class +- template is ToggleTemplate -> ToggleBehavior::class +- template is StatelessTemplate -> TouchBehavior::class +- template is ToggleRangeTemplate -> ToggleRangeBehavior::class +- template is RangeTemplate -> ToggleRangeBehavior::class +- template is TemperatureControlTemplate -> TemperatureControlBehavior::class +- else -> DefaultBehavior::class +- } +- } + } + + private val toggleBackgroundIntensity: Float = layout.context.resources +@@ -146,6 +125,26 @@ class ControlViewHolder( + status.setSelected(true) + } + ++ fun findBehavior( ++ status: Int, ++ template: ControlTemplate, ++ deviceType: Int ++ ): () -> Behavior { ++ return when { ++ status != Control.STATUS_OK -> { { StatusBehavior() } } ++ template == ControlTemplate.NO_TEMPLATE -> { { TouchBehavior() } } ++ template is ThumbnailTemplate -> { { ThumbnailBehavior(currentUserId) } } ++ // Required for legacy support, or where cameras do not use the new template ++ deviceType == DeviceTypes.TYPE_CAMERA -> { { TouchBehavior() } } ++ template is ToggleTemplate -> { { ToggleBehavior() } } ++ template is StatelessTemplate -> { { TouchBehavior() } } ++ template is ToggleRangeTemplate -> { { ToggleRangeBehavior() } } ++ template is RangeTemplate -> { { ToggleRangeBehavior() } } ++ template is TemperatureControlTemplate -> { { TemperatureControlBehavior() } } ++ else -> { { DefaultBehavior() } } ++ } ++ } ++ + fun bindData(cws: ControlWithState, isLocked: Boolean) { + // If an interaction is in progress, the update may visually interfere with the action the + // action the user wants to make. Don't apply the update, and instead assume a new update +@@ -179,7 +178,7 @@ class ControlViewHolder( + val wasLoading = isLoading + isLoading = false + behavior = bindBehavior(behavior, +- findBehaviorClass(controlStatus, controlTemplate, deviceType)) ++ findBehavior(controlStatus, controlTemplate, deviceType)) + updateContentDescription() + + // Only log one event per control, at the moment we have determined that the control +@@ -251,13 +250,14 @@ class ControlViewHolder( + + fun bindBehavior( + existingBehavior: Behavior?, +- clazz: KClass, ++ createBehaviour: () -> Behavior, + offset: Int = 0 + ): Behavior { +- val behavior = if (existingBehavior == null || existingBehavior!!::class != clazz) { ++ val newBehavior = createBehaviour() ++ val behavior = if (existingBehavior == null || ++ existingBehavior::class != newBehavior::class) { + // Behavior changes can signal a change in template from the app or + // first time setup +- val newBehavior = clazz.java.newInstance() + newBehavior.initialize(this) + + // let behaviors define their own, if necessary, and clear any existing ones +diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +index 567d0cb3e6cb..480a7f6e7562 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +@@ -412,7 +412,8 @@ class ControlsUiControllerImpl @Inject constructor ( + bgExecutor, + controlActionCoordinator, + controlsMetricsLogger, +- selected.uid ++ selected.uid, ++ controlsController.get().currentUserId + ) + cvh.bindData(it, false /* isLocked, will be ignored on initial load */) + controlViewsById.put(key, cvh) +diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt +index a7dc09bb17e5..42922441fa30 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt +@@ -63,7 +63,7 @@ class TemperatureControlBehavior : Behavior { + // interactions (touch, range) + subBehavior = cvh.bindBehavior( + subBehavior, +- ControlViewHolder.findBehaviorClass( ++ cvh.findBehavior( + control.status, + subTemplate, + control.deviceType +diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt +index c2168aa8d9d9..5360eea847ee 100644 +--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt ++++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt +@@ -33,7 +33,7 @@ import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL + * Supports display of static images on the background of the tile. When marked active, the title + * and subtitle will not be visible. To be used with {@link Thumbnailtemplate} only. + */ +-class ThumbnailBehavior : Behavior { ++class ThumbnailBehavior(currentUserId: Int) : Behavior { + lateinit var template: ThumbnailTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder +@@ -42,6 +42,7 @@ class ThumbnailBehavior : Behavior { + private var shadowRadius: Float = 0f + private var shadowColor: Int = 0 + ++ private val canUseIconPredicate = CanUseIconPredicate(currentUserId) + private val enabled: Boolean + get() = template.isActive() + +@@ -80,11 +81,15 @@ class ThumbnailBehavior : Behavior { + cvh.status.setShadowLayer(shadowOffsetX, shadowOffsetY, shadowRadius, shadowColor) + + cvh.bgExecutor.execute { +- val drawable = template.getThumbnail().loadDrawable(cvh.context) ++ val drawable = template.thumbnail ++ .takeIf(canUseIconPredicate) ++ ?.loadDrawable(cvh.context) + cvh.uiExecutor.execute { + val radius = cvh.context.getResources() + .getDimensionPixelSize(R.dimen.control_corner_radius).toFloat() +- clipLayer.setDrawable(CornerDrawable(drawable, radius)) ++ drawable?.let { ++ clipLayer.drawable = CornerDrawable(it, radius) ++ } + clipLayer.setColorFilter(BlendModeColorFilter(cvh.context.resources + .getColor(R.color.control_thumbnail_tint), BlendMode.LUMINOSITY)) + cvh.applyRenderInfo(enabled, colorOffset) +diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt +new file mode 100644 +index 000000000000..ed17f179eeb0 +--- /dev/null ++++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (C) 2023 The Android Open Source Project ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.android.systemui.controls.ui ++ ++import android.graphics.Bitmap ++import android.graphics.drawable.Icon ++import android.net.Uri ++import android.testing.AndroidTestingRunner ++import androidx.test.filters.SmallTest ++import com.android.systemui.SysuiTestCase ++import com.google.common.truth.Truth.assertThat ++import org.junit.Test ++import org.junit.runner.RunWith ++ ++@SmallTest ++@RunWith(AndroidTestingRunner::class) ++class CanUseIconPredicateTest : SysuiTestCase() { ++ ++ private companion object { ++ const val USER_ID_1 = 1 ++ const val USER_ID_2 = 2 ++ } ++ ++ val underTest: CanUseIconPredicate = CanUseIconPredicate(USER_ID_1) ++ ++ @Test ++ fun testReturnsFalseForDifferentUser() { ++ val user2Icon = Icon.createWithContentUri("content://$USER_ID_2@test") ++ ++ assertThat(underTest.invoke(user2Icon)).isFalse() ++ } ++ ++ @Test ++ fun testReturnsTrueForCorrectUser() { ++ val user1Icon = Icon.createWithContentUri("content://$USER_ID_1@test") ++ ++ assertThat(underTest.invoke(user1Icon)).isTrue() ++ } ++ ++ @Test ++ fun testReturnsTrueForUriWithoutUser() { ++ val uriIcon = Icon.createWithContentUri(Uri.parse("content://test")) ++ ++ assertThat(underTest.invoke(uriIcon)).isTrue() ++ } ++ ++ @Test ++ fun testReturnsTrueForNonUriIcon() { ++ val bitmapIcon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)) ++ ++ assertThat(underTest.invoke(bitmapIcon)).isTrue() ++ } ++} +diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt +index 47ab17dd7ed0..26095cda5248 100644 +--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt ++++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt +@@ -63,7 +63,8 @@ class ControlViewHolderTest : SysuiTestCase() { + FakeExecutor(clock), + mock(ControlActionCoordinator::class.java), + mock(ControlsMetricsLogger::class.java), +- uid = 100 ++ uid = 100, ++ currentUserId = 0 + ) + + val cws = ControlWithState( +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0206-DO-NOT-MERGE-Fix-BAL-via-notification-publicVersion.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0206-DO-NOT-MERGE-Fix-BAL-via-notification-publicVersion.bulletin.patch new file mode 100644 index 0000000000..7285d36aca --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0206-DO-NOT-MERGE-Fix-BAL-via-notification-publicVersion.bulletin.patch @@ -0,0 +1,54 @@ +From f4f3013318be66a53befb75469df0eabdc062c01 Mon Sep 17 00:00:00 2001 +From: Nan Wu +Date: Fri, 16 Jun 2023 14:42:24 +0000 +Subject: [PATCH] DO NOT MERGE Fix BAL via notification.publicVersion + +We stripped the token that allows app to retrieve their own notification +and fire their own PI to launch activities from background. But we +forgot to strip the token from notification.publicVersion + +Bug: 278558814 +Test: NotificationManagerTest#testActivityStartFromRetrievedNotification_isBlocked +(cherry picked from commit cf851d81a954f0a6dd0c2fd7defa93932539e7f9) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8d839e4985d0acc662e1019390c88fab20bacbd6) +Merged-In: I8f25d7a5e47890a0496af023149717e1df482f98 +Change-Id: I8f25d7a5e47890a0496af023149717e1df482f98 +--- + core/java/android/app/Notification.java | 7 +++++-- + .../server/notification/NotificationManagerService.java | 2 +- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java +index f77d81fb8e7d..cdab7d474161 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -3349,8 +3349,11 @@ public class Notification implements Parcelable + * + * @hide + */ +- public void setAllowlistToken(@Nullable IBinder token) { +- mAllowlistToken = token; ++ public void clearAllowlistToken() { ++ mAllowlistToken = null; ++ if (publicVersion != null) { ++ publicVersion.clearAllowlistToken(); ++ } + } + + /** +diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java +index dea8c52927fe..595f9563aded 100755 +--- a/services/core/java/com/android/server/notification/NotificationManagerService.java ++++ b/services/core/java/com/android/server/notification/NotificationManagerService.java +@@ -4319,7 +4319,7 @@ public class NotificationManagerService extends SystemService { + // Remove background token before returning notification to untrusted app, this + // ensures the app isn't able to perform background operations that are + // associated with notification interactions. +- notification.setAllowlistToken(null); ++ notification.clearAllowlistToken(); + return new StatusBarNotification( + sbn.getPackageName(), + sbn.getOpPkg(), +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0207--DO-NOT-MERGE-Check-caller-s-uid-in-backupAgentCreated-callback.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0207--DO-NOT-MERGE-Check-caller-s-uid-in-backupAgentCreated-callback.bulletin.patch new file mode 100644 index 0000000000..deebff246d --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0207--DO-NOT-MERGE-Check-caller-s-uid-in-backupAgentCreated-callback.bulletin.patch @@ -0,0 +1,66 @@ +From a3fe1c4ae92522e6faca69c513e231ca3cc7c5ee Mon Sep 17 00:00:00 2001 +From: Piyush Mehrotra +Date: Thu, 27 Jul 2023 19:35:14 +0000 +Subject: [PATCH] [DO NOT MERGE] Check caller's uid in backupAgentCreated + callback + +AM.backupAgentCreated() should enforce that caller belongs the package called in the API. + +Bug: 289549315 +Test: atest android.security.cts.ActivityManagerTest#testActivityManager_backupAgentCreated_rejectIfCallerUidNotEqualsPackageUid +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ebdcc72a235d6b2a65e1d1c99d7a9eb89f309357) +Merged-In: I9f3ae5ec0b8f00e020d471cc0eddf8bd8bdbb82d +Change-Id: I9f3ae5ec0b8f00e020d471cc0eddf8bd8bdbb82d +--- + .../server/am/ActivityManagerService.java | 23 +++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java +index 74b66b7d3a2e..27d6a0a2f6d3 100644 +--- a/services/core/java/com/android/server/am/ActivityManagerService.java ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java +@@ -2781,6 +2781,22 @@ public class ActivityManagerService extends IActivityManager.Stub + } + } + ++ /** ++ * Enforces that the uid of the caller matches the uid of the package. ++ * ++ * @param packageName the name of the package to match uid against. ++ * @param callingUid the uid of the caller. ++ * @throws SecurityException if the calling uid doesn't match uid of the package. ++ */ ++ private void enforceCallingPackage(String packageName, int callingUid) { ++ final int userId = UserHandle.getUserId(callingUid); ++ final int packageUid = getPackageManagerInternal().getPackageUid(packageName, ++ /*flags=*/ 0, userId); ++ if (packageUid != callingUid) { ++ throw new SecurityException(packageName + " does not belong to uid " + callingUid); ++ } ++ } ++ + @Override + public void setPackageScreenCompatMode(String packageName, int mode) { + mActivityTaskManager.setPackageScreenCompatMode(packageName, mode); +@@ -12215,13 +12231,16 @@ public class ActivityManagerService extends IActivityManager.Stub + // A backup agent has just come up + @Override + public void backupAgentCreated(String agentPackageName, IBinder agent, int userId) { ++ final int callingUid = Binder.getCallingUid(); ++ enforceCallingPackage(agentPackageName, callingUid); ++ + // Resolve the target user id and enforce permissions. +- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), ++ userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, + userId, /* allowAll */ false, ALLOW_FULL_ONLY, "backupAgentCreated", null); + if (DEBUG_BACKUP) { + Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent + + " callingUserId = " + UserHandle.getCallingUserId() + " userId = " + userId +- + " callingUid = " + Binder.getCallingUid() + " uid = " + Process.myUid()); ++ + " callingUid = " + callingUid + " uid = " + Process.myUid()); + } + + synchronized(this) { +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0208-Use-type-safe-API-of-readParcelableArray.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0208-Use-type-safe-API-of-readParcelableArray.bulletin.patch new file mode 100644 index 0000000000..602c6b28b8 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0208-Use-type-safe-API-of-readParcelableArray.bulletin.patch @@ -0,0 +1,34 @@ +From a65cc9961ed4d5d13ddc99c2ee59fbeecd086fb3 Mon Sep 17 00:00:00 2001 +From: kumarashishg +Date: Thu, 3 Aug 2023 12:01:29 +0000 +Subject: [PATCH] Use type safe API of readParcelableArray + +Bug: 291299076 +Test: Build and flash the device and check if it throws exception for +non UsbInterface object +Test: atest CtsUsbManagerTestCases +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:85d7e6712a9eeeed3bdd68ea3c3862c7e88bfe70) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0362efc06e5e3987270b452f6e2ee8fcd78e2b5a) +Merged-In: I2917c8331b6d56caaa9a6479bcd9a2d089f5f503 +Change-Id: I2917c8331b6d56caaa9a6479bcd9a2d089f5f503 +--- + core/java/android/hardware/usb/UsbConfiguration.java | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java +index 66269cb772f8..b25f47b11532 100644 +--- a/core/java/android/hardware/usb/UsbConfiguration.java ++++ b/core/java/android/hardware/usb/UsbConfiguration.java +@@ -172,7 +172,8 @@ public class UsbConfiguration implements Parcelable { + String name = in.readString(); + int attributes = in.readInt(); + int maxPower = in.readInt(); +- Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); ++ Parcelable[] interfaces = in.readParcelableArray( ++ UsbInterface.class.getClassLoader(), UsbInterface.class); + UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower); + configuration.setInterfaces(interfaces); + return configuration; +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/packages/modules/DnsResolver/0001-Fix-use-after-free-in-DNS64-discovery-thread.bulletin.patch b/aosp_diff/preliminary/packages/modules/DnsResolver/0001-Fix-use-after-free-in-DNS64-discovery-thread.bulletin.patch new file mode 100644 index 0000000000..17fcd3f963 --- /dev/null +++ b/aosp_diff/preliminary/packages/modules/DnsResolver/0001-Fix-use-after-free-in-DNS64-discovery-thread.bulletin.patch @@ -0,0 +1,213 @@ +From a093dd94ef8e6dff02c5aa77db38367900345ad0 Mon Sep 17 00:00:00 2001 +From: Ken Chen +Date: Thu, 15 Jun 2023 17:46:16 +0800 +Subject: [PATCH] Fix use-after-free in DNS64 discovery thread + +DNS64 discovery thread is detached from binder requesting thread. But +the discovery thread references resources not belongs to itself, which +can be destroyed in dnsresolver destruction. + +Holds a strong pointer of Dns64Configuration in DNS64 discovery thread +so that the instance of Dns64Configuration will keep until the DNS64 +thread is force terminated. + +Ignore-AOSP-First: Fix security vulnerability +Bug: 278303745 +Test: m, fuzzing +Fuzzing: mma resolv_service_fuzzer && adb sync data && adb shell /data/fuzz/arm64/resolv_service_fuzzer/resolv_service_fuzzer + +(cherry picked from commit 254115584ff558fb87ee6ec5f5bb043f76219910) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:292b59e1b0ff91cd4b1f1835de7bfb7fb744c9c0) +Merged-In: Id74ea4e6f54a00805d3cc8a9d7e15e58a473b7d3 +Change-Id: Id74ea4e6f54a00805d3cc8a9d7e15e58a473b7d3 +--- + Android.bp | 1 + + Dns64Configuration.cpp | 17 ++++++++++------- + Dns64Configuration.h | 3 ++- + ResolverController.cpp | 15 +++++++-------- + ResolverController.h | 6 +++--- + 5 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/Android.bp b/Android.bp +index 696d721..b46aeff 100644 +--- a/Android.bp ++++ b/Android.bp +@@ -201,6 +201,7 @@ cc_library { + "libstatspush_compat", + "libsysutils", + "netd_event_listener_interface-lateststable-ndk_platform", ++ "libutils", + "server_configurable_flags", + "stats_proto", + ], +diff --git a/Dns64Configuration.cpp b/Dns64Configuration.cpp +index 77a27e7..94abeda 100644 +--- a/Dns64Configuration.cpp ++++ b/Dns64Configuration.cpp +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -38,6 +39,7 @@ namespace android { + + using android::base::StringPrintf; + using android::net::NetworkDnsEventReported; ++using android::sp; + using netdutils::DumpWriter; + using netdutils::IPAddress; + using netdutils::IPPrefix; +@@ -63,8 +65,9 @@ void Dns64Configuration::startPrefixDiscovery(unsigned netId) { + // Emplace a copy of |cfg| in the map. + mDns64Configs.emplace(std::make_pair(netId, cfg)); + ++ const sp thiz = this; + // Note that capturing |cfg| in this lambda creates a copy. +- std::thread discovery_thread([this, cfg, netId] { ++ std::thread discovery_thread([thiz, cfg, netId] { + setThreadName(StringPrintf("Nat64Pfx_%u", netId).c_str()); + + // Make a mutable copy rather than mark the whole lambda mutable. +@@ -77,28 +80,28 @@ void Dns64Configuration::startPrefixDiscovery(unsigned netId) { + .build(); + + while (true) { +- if (!this->shouldContinueDiscovery(evalCfg)) break; ++ if (!thiz->shouldContinueDiscovery(evalCfg)) break; + + android_net_context netcontext{}; +- mGetNetworkContextCallback(evalCfg.netId, 0, &netcontext); ++ thiz->mGetNetworkContextCallback(evalCfg.netId, 0, &netcontext); + + // Prefix discovery must bypass private DNS because in strict mode + // the server generally won't know the NAT64 prefix. + netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS; + if (doRfc7050PrefixDiscovery(netcontext, &evalCfg)) { +- this->recordDns64Config(evalCfg); ++ thiz->recordDns64Config(evalCfg); + break; + } + +- if (!this->shouldContinueDiscovery(evalCfg)) break; ++ if (!thiz->shouldContinueDiscovery(evalCfg)) break; + + if (!backoff.hasNextTimeout()) break; + { +- std::unique_lock cvGuard(mMutex); ++ std::unique_lock cvGuard(thiz->mMutex); + // TODO: Consider some chrono math, combined with wait_until() + // perhaps, to prevent early re-resolves from the removal of + // other netids with IPv6-only nameservers. +- mCv.wait_for(cvGuard, backoff.getNextTimeout()); ++ thiz->mCv.wait_for(cvGuard, backoff.getNextTimeout()); + } + } + }); +diff --git a/Dns64Configuration.h b/Dns64Configuration.h +index 387de78..ebc63db 100644 +--- a/Dns64Configuration.h ++++ b/Dns64Configuration.h +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + struct android_net_context; + +@@ -47,7 +48,7 @@ namespace net { + * Thread-safety: All public methods in this class MUST be thread-safe. + * (In other words: this class handles all its locking privately.) + */ +-class Dns64Configuration { ++class Dns64Configuration : virtual public RefBase { + public: + // Simple data struct for passing back packet NAT64 prefix event information to the + // Dns64PrefixCallback callback. +diff --git a/ResolverController.cpp b/ResolverController.cpp +index 6c7bed4..ae89bcb 100644 +--- a/ResolverController.cpp ++++ b/ResolverController.cpp +@@ -155,17 +155,17 @@ int getDnsInfo(unsigned netId, std::vector* servers, std::vectordump(dw, netId); + const auto privateDnsStatus = PrivateDnsConfiguration::getInstance().getStatus(netId); + dw.println("Private DNS mode: %s", getPrivateDnsModeString(privateDnsStatus.mode)); + if (privateDnsStatus.serversMap.size() == 0) { +diff --git a/ResolverController.h b/ResolverController.h +index e81e1ed..3802e36 100644 +--- a/ResolverController.h ++++ b/ResolverController.h +@@ -55,10 +55,10 @@ class ResolverController { + + // Set or clear a NAT64 prefix discovered by other sources (e.g., RA). + int setPrefix64(unsigned netId, const netdutils::IPPrefix& prefix) { +- return mDns64Configuration.setPrefix64(netId, prefix); ++ return mDns64Configuration->setPrefix64(netId, prefix); + } + +- int clearPrefix64(unsigned netId) { return mDns64Configuration.clearPrefix64(netId); } ++ int clearPrefix64(unsigned netId) { return mDns64Configuration->clearPrefix64(netId); } + + // Return the current NAT64 prefix network, regardless of how it was discovered. + int getPrefix64(unsigned netId, netdutils::IPPrefix* prefix); +@@ -66,7 +66,7 @@ class ResolverController { + void dump(netdutils::DumpWriter& dw, unsigned netId); + + private: +- Dns64Configuration mDns64Configuration; ++ android::sp mDns64Configuration; + }; + } // namespace net + } // namespace android +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/packages/modules/StatsD/0001-Make-log-reader-thread-a-class-member.bulletin.patch b/aosp_diff/preliminary/packages/modules/StatsD/0001-Make-log-reader-thread-a-class-member.bulletin.patch new file mode 100644 index 0000000000..3f1e64ad1b --- /dev/null +++ b/aosp_diff/preliminary/packages/modules/StatsD/0001-Make-log-reader-thread-a-class-member.bulletin.patch @@ -0,0 +1,106 @@ +From d69f0639b9cc057546378bf0c9b481ae393126c4 Mon Sep 17 00:00:00 2001 +From: Pawan Wagh +Date: Wed, 28 Jun 2023 23:11:01 +0000 +Subject: [PATCH] Make log reader thread a class member + +pushedEventThread references class members after detaching. Making +pushedEventThread as class member and joining in statsService +destructor. Adding a method to stop readLogs thread. + +Ignore-AOSP-First: Bug is in still security triage and fuzzer is +crashing on startup. +Test: atest statsd_test +Test: m statsd_service_fuzzer && adb sync data && adb shell +/data/fuzz/arm64/statsd_service_fuzzer/statsd_service_fuzzer -runs=10000 +Bug: 285645039 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3937ea3cdcf531a14cdba4ef176d8aa89d9d6066) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e67695fae80d3164f5cd5237ebf1b7a0dbfed6f4) +Merged-In: I91dadeaf8a14d2e41d272c0ebfac618bff255998 +Change-Id: I91dadeaf8a14d2e41d272c0ebfac618bff255998 +--- + statsd/src/StatsService.cpp | 23 +++++++++++++++++++++-- + statsd/src/StatsService.h | 9 +++++++++ + 2 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/statsd/src/StatsService.cpp b/statsd/src/StatsService.cpp +index 3ecb8532..f17f93bb 100644 +--- a/statsd/src/StatsService.cpp ++++ b/statsd/src/StatsService.cpp +@@ -159,12 +159,15 @@ StatsService::StatsService(const sp& handlerLooper, shared_ptr([this] { readLogs(); }); + } + } + + StatsService::~StatsService() { ++ if (mEventQueue != nullptr) { ++ stopReadingLogs(); ++ mLogsReaderThread->join(); ++ } + } + + /* Runs on a dedicated thread to process pushed events. */ +@@ -173,6 +176,13 @@ void StatsService::readLogs() { + while (1) { + // Block until an event is available. + auto event = mEventQueue->waitPop(); ++ ++ // Below flag will be set when statsd is exiting and log event will be pushed to break ++ // out of waitPop. ++ if (mIsStopRequested) { ++ break; ++ } ++ + // Pass it to StatsLogProcess to all configs/metrics + // At this point, the LogEventQueue is not blocked, so that the socketListener + // can read events from the socket and write to buffer to avoid data drop. +@@ -1315,6 +1325,15 @@ void StatsService::statsCompanionServiceDiedImpl() { + mPullerManager->SetStatsCompanionService(nullptr); + } + ++void StatsService::stopReadingLogs() { ++ mIsStopRequested = true; ++ // Push this event so that readLogs will process and break out of the loop ++ // after the stop is requested. ++ int64_t timeStamp; ++ std::unique_ptr logEvent = std::make_unique(/*uid=*/0, /*pid=*/0); ++ mEventQueue->push(std::move(logEvent), &timeStamp); ++} ++ + } // namespace statsd + } // namespace os + } // namespace android +diff --git a/statsd/src/StatsService.h b/statsd/src/StatsService.h +index 3d5ec2c6..ae23c41e 100644 +--- a/statsd/src/StatsService.h ++++ b/statsd/src/StatsService.h +@@ -338,6 +338,13 @@ private: + */ + void statsCompanionServiceDiedImpl(); + ++ /** ++ * This method is used to stop log reader thread. ++ */ ++ void stopReadingLogs(); ++ ++ std::atomic mIsStopRequested = false; ++ + /** + * Tracks the uid <--> package name mapping. + */ +@@ -381,6 +388,8 @@ private: + mutable mutex mShellSubscriberMutex; + std::shared_ptr mEventQueue; + ++ std::unique_ptr mLogsReaderThread; ++ + MultiConditionTrigger mBootCompleteTrigger; + static const inline string kBootCompleteTag = "BOOT_COMPLETE"; + static const inline string kUidMapReceivedTag = "UID_MAP"; +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/packages/providers/TelephonyProvider/0003-DO-NOT-MERGE-Block-access-to-sms-mms-db-from-work-profile-.bulletin.patch b/aosp_diff/preliminary/packages/providers/TelephonyProvider/0003-DO-NOT-MERGE-Block-access-to-sms-mms-db-from-work-profile-.bulletin.patch new file mode 100644 index 0000000000..f25a3085f2 --- /dev/null +++ b/aosp_diff/preliminary/packages/providers/TelephonyProvider/0003-DO-NOT-MERGE-Block-access-to-sms-mms-db-from-work-profile-.bulletin.patch @@ -0,0 +1,821 @@ +From 5c28b8fa944e623c3fd1f1d130da17a256c2e7a7 Mon Sep 17 00:00:00 2001 +From: Aishwarya Mallampati +Date: Wed, 23 Aug 2023 18:30:46 +0000 +Subject: [PATCH] DO NOT MERGE Block access to sms/mms db from work profile. + +Bug: 289242655 +Test: Manually verified work profile cannot access personal sms by +following steps mentioned in b/289242655#comment26 +- atest SmsProviderTest +- atest MmsProviderTest +- atest SmsBackupRestoreTest +- QA performed regression testing and confirmed fix is working as intended here: b/294459052#comment30 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a6df5b5cae6280c23d63d89c5064b825a515597d) +Merged-In: Ib1c9ec75f77e8412b53df50f5414caa0e5aaa277 +Change-Id: Ib1c9ec75f77e8412b53df50f5414caa0e5aaa277 +--- + .../providers/telephony/MmsProvider.java | 41 ++++- + .../telephony/MmsSmsDatabaseHelper.java | 156 +++++++++------- + .../providers/telephony/MmsSmsProvider.java | 36 ++++ + .../providers/telephony/SmsProvider.java | 35 ++++ + .../providers/telephony/MmsProviderTest.java | 173 ++++++++++++++++++ + .../telephony/MmsProviderTestable.java | 77 ++++++++ + .../providers/telephony/SmsProviderTest.java | 55 ++++++ + 7 files changed, 503 insertions(+), 70 deletions(-) + create mode 100644 tests/src/com/android/providers/telephony/MmsProviderTest.java + create mode 100644 tests/src/com/android/providers/telephony/MmsProviderTestable.java + +diff --git a/src/com/android/providers/telephony/MmsProvider.java b/src/com/android/providers/telephony/MmsProvider.java +index fade7ce..020f315 100644 +--- a/src/com/android/providers/telephony/MmsProvider.java ++++ b/src/com/android/providers/telephony/MmsProvider.java +@@ -25,6 +25,7 @@ import android.content.Context; + import android.content.Intent; + import android.content.UriMatcher; + import android.database.Cursor; ++import android.database.MatrixCursor; + import android.database.sqlite.SQLiteDatabase; + import android.database.sqlite.SQLiteException; + import android.database.sqlite.SQLiteOpenHelper; +@@ -33,6 +34,7 @@ import android.net.Uri; + import android.os.Binder; + import android.os.ParcelFileDescriptor; + import android.os.UserHandle; ++import android.os.UserManager; + import android.provider.BaseColumns; + import android.provider.Telephony; + import android.provider.Telephony.CanonicalAddressesColumns; +@@ -49,6 +51,8 @@ import android.text.TextUtils; + import android.util.EventLog; + import android.util.Log; + ++import com.android.internal.annotations.VisibleForTesting; ++ + import com.google.android.mms.pdu.PduHeaders; + import com.google.android.mms.util.DownloadDrmHelper; + +@@ -93,6 +97,16 @@ public class MmsProvider extends ContentProvider { + @Override + public Cursor query(Uri uri, String[] projection, + String selection, String[] selectionArgs, String sortOrder) { ++ Cursor emptyCursor = new MatrixCursor((projection == null) ? ++ (new String[] {}) : projection); ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to query mms, return empty cursor. ++ Log.e(TAG, "Managed profile is not allowed to query MMS."); ++ return emptyCursor; ++ } ++ + // First check if a restricted view of the "pdu" table should be used based on the + // caller's identity. Only system, phone or the default sms app can have full access + // of mms data. For other apps, we present a restricted view which only contains sent +@@ -306,6 +320,14 @@ public class MmsProvider extends ContentProvider { + + @Override + public Uri insert(Uri uri, ContentValues values) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to insert mms, return null. ++ Log.e(TAG, "Managed profile is not allowed to insert MMS."); ++ return null; ++ } ++ + final int callerUid = Binder.getCallingUid(); + final String callerPkg = getCallingPackage(); + int msgBox = Mms.MESSAGE_BOX_ALL; +@@ -625,6 +647,14 @@ public class MmsProvider extends ContentProvider { + @Override + public int delete(Uri uri, String selection, + String[] selectionArgs) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to delete mms, return 0. ++ Log.e(TAG, "Managed profile is not allowed to delete MMS."); ++ return 0; ++ } ++ + int match = sURLMatcher.match(uri); + if (LOCAL_LOGV) { + Log.v(TAG, "Delete uri=" + uri + ", match=" + match); +@@ -777,6 +807,14 @@ public class MmsProvider extends ContentProvider { + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to update mms, return 0. ++ Log.e(TAG, "Managed profile is not allowed to update MMS."); ++ return 0; ++ } ++ + // The _data column is filled internally in MmsProvider, so this check is just to avoid + // it from being inadvertently set. This is not supposed to be a protection against + // malicious attack, since sql injection could still be attempted to bypass the check. On +@@ -1066,7 +1104,8 @@ public class MmsProvider extends ContentProvider { + sURLMatcher.addURI("mms", "resetFilePerm/*", MMS_PART_RESET_FILE_PERMISSION); + } + +- private SQLiteOpenHelper mOpenHelper; ++ @VisibleForTesting ++ public SQLiteOpenHelper mOpenHelper; + + private static String concatSelections(String selection1, String selection2) { + if (TextUtils.isEmpty(selection1)) { +diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java +index a9494fb..ae9c5ac 100644 +--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java ++++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java +@@ -714,79 +714,97 @@ public class MmsSmsDatabaseHelper extends SQLiteOpenHelper { + } + } + ++ @VisibleForTesting ++ public static String CREATE_ADDR_TABLE_STR = ++ "CREATE TABLE " + MmsProvider.TABLE_ADDR + " (" + ++ Addr._ID + " INTEGER PRIMARY KEY," + ++ Addr.MSG_ID + " INTEGER," + ++ Addr.CONTACT_ID + " INTEGER," + ++ Addr.ADDRESS + " TEXT," + ++ Addr.TYPE + " INTEGER," + ++ Addr.CHARSET + " INTEGER);"; ++ ++ @VisibleForTesting ++ public static String CREATE_PART_TABLE_STR = ++ "CREATE TABLE " + MmsProvider.TABLE_PART + " (" + ++ Part._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + ++ Part.MSG_ID + " INTEGER," + ++ Part.SEQ + " INTEGER DEFAULT 0," + ++ Part.CONTENT_TYPE + " TEXT," + ++ Part.NAME + " TEXT," + ++ Part.CHARSET + " INTEGER," + ++ Part.CONTENT_DISPOSITION + " TEXT," + ++ Part.FILENAME + " TEXT," + ++ Part.CONTENT_ID + " TEXT," + ++ Part.CONTENT_LOCATION + " TEXT," + ++ Part.CT_START + " INTEGER," + ++ Part.CT_TYPE + " TEXT," + ++ Part._DATA + " TEXT," + ++ Part.TEXT + " TEXT);"; ++ ++ public static String CREATE_PDU_TABLE_STR = ++ "CREATE TABLE " + MmsProvider.TABLE_PDU + " (" + ++ Mms._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + ++ Mms.THREAD_ID + " INTEGER," + ++ Mms.DATE + " INTEGER," + ++ Mms.DATE_SENT + " INTEGER DEFAULT 0," + ++ Mms.MESSAGE_BOX + " INTEGER," + ++ Mms.READ + " INTEGER DEFAULT 0," + ++ Mms.MESSAGE_ID + " TEXT," + ++ Mms.SUBJECT + " TEXT," + ++ Mms.SUBJECT_CHARSET + " INTEGER," + ++ Mms.CONTENT_TYPE + " TEXT," + ++ Mms.CONTENT_LOCATION + " TEXT," + ++ Mms.EXPIRY + " INTEGER," + ++ Mms.MESSAGE_CLASS + " TEXT," + ++ Mms.MESSAGE_TYPE + " INTEGER," + ++ Mms.MMS_VERSION + " INTEGER," + ++ Mms.MESSAGE_SIZE + " INTEGER," + ++ Mms.PRIORITY + " INTEGER," + ++ Mms.READ_REPORT + " INTEGER," + ++ Mms.REPORT_ALLOWED + " INTEGER," + ++ Mms.RESPONSE_STATUS + " INTEGER," + ++ Mms.STATUS + " INTEGER," + ++ Mms.TRANSACTION_ID + " TEXT," + ++ Mms.RETRIEVE_STATUS + " INTEGER," + ++ Mms.RETRIEVE_TEXT + " TEXT," + ++ Mms.RETRIEVE_TEXT_CHARSET + " INTEGER," + ++ Mms.READ_STATUS + " INTEGER," + ++ Mms.CONTENT_CLASS + " INTEGER," + ++ Mms.RESPONSE_TEXT + " TEXT," + ++ Mms.DELIVERY_TIME + " INTEGER," + ++ Mms.DELIVERY_REPORT + " INTEGER," + ++ Mms.LOCKED + " INTEGER DEFAULT 0," + ++ Mms.SUBSCRIPTION_ID + " INTEGER DEFAULT " ++ + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " + ++ Mms.SEEN + " INTEGER DEFAULT 0," + ++ Mms.CREATOR + " TEXT," + ++ Mms.TEXT_ONLY + " INTEGER DEFAULT 0);"; ++ ++ @VisibleForTesting ++ public static String CREATE_RATE_TABLE_STR = ++ "CREATE TABLE " + MmsProvider.TABLE_RATE + " (" + ++ Rate.SENT_TIME + " INTEGER);"; ++ ++ @VisibleForTesting ++ public static String CREATE_DRM_TABLE_STR = ++ "CREATE TABLE " + MmsProvider.TABLE_DRM + " (" + ++ BaseColumns._ID + " INTEGER PRIMARY KEY," + ++ "_data TEXT);"; ++ + @VisibleForTesting + void createMmsTables(SQLiteDatabase db) { + // N.B.: Whenever the columns here are changed, the columns in + // {@ref MmsSmsProvider} must be changed to match. +- db.execSQL("CREATE TABLE " + MmsProvider.TABLE_PDU + " (" + +- Mms._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + +- Mms.THREAD_ID + " INTEGER," + +- Mms.DATE + " INTEGER," + +- Mms.DATE_SENT + " INTEGER DEFAULT 0," + +- Mms.MESSAGE_BOX + " INTEGER," + +- Mms.READ + " INTEGER DEFAULT 0," + +- Mms.MESSAGE_ID + " TEXT," + +- Mms.SUBJECT + " TEXT," + +- Mms.SUBJECT_CHARSET + " INTEGER," + +- Mms.CONTENT_TYPE + " TEXT," + +- Mms.CONTENT_LOCATION + " TEXT," + +- Mms.EXPIRY + " INTEGER," + +- Mms.MESSAGE_CLASS + " TEXT," + +- Mms.MESSAGE_TYPE + " INTEGER," + +- Mms.MMS_VERSION + " INTEGER," + +- Mms.MESSAGE_SIZE + " INTEGER," + +- Mms.PRIORITY + " INTEGER," + +- Mms.READ_REPORT + " INTEGER," + +- Mms.REPORT_ALLOWED + " INTEGER," + +- Mms.RESPONSE_STATUS + " INTEGER," + +- Mms.STATUS + " INTEGER," + +- Mms.TRANSACTION_ID + " TEXT," + +- Mms.RETRIEVE_STATUS + " INTEGER," + +- Mms.RETRIEVE_TEXT + " TEXT," + +- Mms.RETRIEVE_TEXT_CHARSET + " INTEGER," + +- Mms.READ_STATUS + " INTEGER," + +- Mms.CONTENT_CLASS + " INTEGER," + +- Mms.RESPONSE_TEXT + " TEXT," + +- Mms.DELIVERY_TIME + " INTEGER," + +- Mms.DELIVERY_REPORT + " INTEGER," + +- Mms.LOCKED + " INTEGER DEFAULT 0," + +- Mms.SUBSCRIPTION_ID + " INTEGER DEFAULT " +- + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " + +- Mms.SEEN + " INTEGER DEFAULT 0," + +- Mms.CREATOR + " TEXT," + +- Mms.TEXT_ONLY + " INTEGER DEFAULT 0" + +- ");"); +- +- db.execSQL("CREATE TABLE " + MmsProvider.TABLE_ADDR + " (" + +- Addr._ID + " INTEGER PRIMARY KEY," + +- Addr.MSG_ID + " INTEGER," + +- Addr.CONTACT_ID + " INTEGER," + +- Addr.ADDRESS + " TEXT," + +- Addr.TYPE + " INTEGER," + +- Addr.CHARSET + " INTEGER);"); +- +- db.execSQL("CREATE TABLE " + MmsProvider.TABLE_PART + " (" + +- Part._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + +- Part.MSG_ID + " INTEGER," + +- Part.SEQ + " INTEGER DEFAULT 0," + +- Part.CONTENT_TYPE + " TEXT," + +- Part.NAME + " TEXT," + +- Part.CHARSET + " INTEGER," + +- Part.CONTENT_DISPOSITION + " TEXT," + +- Part.FILENAME + " TEXT," + +- Part.CONTENT_ID + " TEXT," + +- Part.CONTENT_LOCATION + " TEXT," + +- Part.CT_START + " INTEGER," + +- Part.CT_TYPE + " TEXT," + +- Part._DATA + " TEXT," + +- Part.TEXT + " TEXT);"); +- +- db.execSQL("CREATE TABLE " + MmsProvider.TABLE_RATE + " (" + +- Rate.SENT_TIME + " INTEGER);"); +- +- db.execSQL("CREATE TABLE " + MmsProvider.TABLE_DRM + " (" + +- BaseColumns._ID + " INTEGER PRIMARY KEY," + +- "_data TEXT);"); ++ db.execSQL(CREATE_PDU_TABLE_STR); ++ ++ db.execSQL(CREATE_ADDR_TABLE_STR); ++ ++ db.execSQL(CREATE_PART_TABLE_STR); ++ ++ db.execSQL(CREATE_RATE_TABLE_STR); ++ ++ db.execSQL(CREATE_DRM_TABLE_STR); + + // Restricted view of pdu table, only sent/received messages without wap pushes + db.execSQL("CREATE VIEW " + MmsProvider.VIEW_PDU_RESTRICTED + " AS " + +diff --git a/src/com/android/providers/telephony/MmsSmsProvider.java b/src/com/android/providers/telephony/MmsSmsProvider.java +index 8e01bcc..04875a4 100644 +--- a/src/com/android/providers/telephony/MmsSmsProvider.java ++++ b/src/com/android/providers/telephony/MmsSmsProvider.java +@@ -23,6 +23,7 @@ import android.content.Context; + import android.content.UriMatcher; + import android.database.Cursor; + import android.database.DatabaseUtils; ++import android.database.MatrixCursor; + import android.database.sqlite.SQLiteDatabase; + import android.database.sqlite.SQLiteOpenHelper; + import android.database.sqlite.SQLiteQueryBuilder; +@@ -30,6 +31,7 @@ import android.net.Uri; + import android.os.Binder; + import android.os.Bundle; + import android.os.UserHandle; ++import android.os.UserManager; + import android.provider.BaseColumns; + import android.provider.Telephony; + import android.provider.Telephony.CanonicalAddressesColumns; +@@ -323,6 +325,16 @@ public class MmsSmsProvider extends ContentProvider { + @Override + public Cursor query(Uri uri, String[] projection, + String selection, String[] selectionArgs, String sortOrder) { ++ Cursor emptyCursor = new MatrixCursor((projection == null) ? ++ (new String[] {}) : projection); ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to query mms/sms, return empty cursor. ++ Log.e(LOG_TAG, "Managed profile is not allowed to query MMS/SMS."); ++ return emptyCursor; ++ } ++ + // First check if restricted views of the "sms" and "pdu" tables should be used based on the + // caller's identity. Only system, phone or the default sms app can have full access + // of sms/mms data. For other apps, we present a restricted view which only contains sent +@@ -1233,6 +1245,14 @@ public class MmsSmsProvider extends ContentProvider { + @Override + public int delete(Uri uri, String selection, + String[] selectionArgs) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to delete mms/sms, return 0. ++ Log.e(LOG_TAG, "Managed profile is not allowed to delete MMS/SMS."); ++ return 0; ++ } ++ + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + Context context = getContext(); + int affectedRows = 0; +@@ -1289,6 +1309,14 @@ public class MmsSmsProvider extends ContentProvider { + + @Override + public Uri insert(Uri uri, ContentValues values) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to insert mms/sms, return null. ++ Log.e(LOG_TAG, "Managed profile is not allowed to insert MMS/SMS."); ++ return null; ++ } ++ + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int matchIndex = URI_MATCHER.match(uri); + +@@ -1305,6 +1333,14 @@ public class MmsSmsProvider extends ContentProvider { + @Override + public int update(Uri uri, ContentValues values, + String selection, String[] selectionArgs) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to update mms/sms, return 0. ++ Log.e(LOG_TAG, "Managed profile is not allowed to update MMS/SMS."); ++ return 0; ++ } ++ + final int callerUid = Binder.getCallingUid(); + final String callerPkg = getCallingPackage(); + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); +diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java +index d378c64..b592744 100644 +--- a/src/com/android/providers/telephony/SmsProvider.java ++++ b/src/com/android/providers/telephony/SmsProvider.java +@@ -32,6 +32,7 @@ import android.database.sqlite.SQLiteQueryBuilder; + import android.net.Uri; + import android.os.Binder; + import android.os.UserHandle; ++import android.os.UserManager; + import android.provider.Contacts; + import android.provider.Telephony; + import android.provider.Telephony.MmsSms; +@@ -117,6 +118,16 @@ public class SmsProvider extends ContentProvider { + @Override + public Cursor query(Uri url, String[] projectionIn, String selection, + String[] selectionArgs, String sort) { ++ Cursor emptyCursor = new MatrixCursor((projectionIn == null) ? ++ (new String[] {}) : projectionIn); ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to query sms, return empty cursor. ++ Log.e(TAG, "Managed profile is not allowed to query SMS."); ++ return emptyCursor; ++ } ++ + // First check if a restricted view of the "sms" table should be used based on the + // caller's identity. Only system, phone or the default sms app can have full access + // of sms data. For other apps, we present a restricted view which only contains sent +@@ -557,6 +568,14 @@ public class SmsProvider extends ContentProvider { + } + + private Uri insertInner(Uri url, ContentValues initialValues, int callerUid, String callerPkg) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to insert sms, return null. ++ Log.e(TAG, "Managed profile is not allowed to insert SMS."); ++ return null; ++ } ++ + ContentValues values; + long rowID; + int type = Sms.MESSAGE_TYPE_ALL; +@@ -848,6 +867,14 @@ public class SmsProvider extends ContentProvider { + + @Override + public int delete(Uri url, String where, String[] whereArgs) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to delete sms, return 0. ++ Log.e(TAG, "Managed profile is not allowed to delete SMS."); ++ return 0; ++ } ++ + int count; + int match = sURLMatcher.match(url); + SQLiteDatabase db = getWritableDatabase(match); +@@ -1033,6 +1060,14 @@ public class SmsProvider extends ContentProvider { + + @Override + public int update(Uri url, ContentValues values, String where, String[] whereArgs) { ++ UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); ++ if ((userManager != null) && (userManager.isManagedProfile( ++ Binder.getCallingUserHandle().getIdentifier()))) { ++ // If work profile is trying to update sms, return 0. ++ Log.e(TAG, "Managed profile is not allowed to update SMS."); ++ return 0; ++ } ++ + final int callerUid = Binder.getCallingUid(); + final String callerPkg = getCallingPackage(); + int count = 0; +diff --git a/tests/src/com/android/providers/telephony/MmsProviderTest.java b/tests/src/com/android/providers/telephony/MmsProviderTest.java +new file mode 100644 +index 0000000..e1010e0 +--- /dev/null ++++ b/tests/src/com/android/providers/telephony/MmsProviderTest.java +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (C) 2023 The Android Open Source Project ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.android.providers.telephony; ++ ++import static org.mockito.ArgumentMatchers.anyInt; ++import static org.mockito.ArgumentMatchers.anyString; ++import static org.mockito.ArgumentMatchers.eq; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.when; ++ ++import android.app.AppOpsManager; ++import android.content.ContentValues; ++import android.content.Context; ++import android.content.pm.PackageManager; ++import android.content.pm.ProviderInfo; ++import android.database.ContentObserver; ++import android.database.Cursor; ++import android.net.Uri; ++import android.os.UserManager; ++import android.provider.Telephony; ++import android.telephony.TelephonyManager; ++import android.test.mock.MockContentResolver; ++import android.util.Log; ++ ++import junit.framework.TestCase; ++ ++import org.junit.Test; ++import org.mockito.Mock; ++import org.mockito.MockitoAnnotations; ++ ++public class MmsProviderTest extends TestCase { ++ private static final String TAG = "MmsProviderTest"; ++ ++ @Mock private Context mContext; ++ private MockContentResolver mContentResolver; ++ private MmsProviderTestable mMmsProviderTestable; ++ @Mock private PackageManager mPackageManager; ++ ++ private int notifyChangeCount; ++ private UserManager mUserManager; ++ ++ @Override ++ protected void setUp() throws Exception { ++ super.setUp(); ++ MockitoAnnotations.initMocks(this); ++ mMmsProviderTestable = new MmsProviderTestable(); ++ mUserManager = mock(UserManager.class); ++ ++ // setup mocks ++ when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))) ++ .thenReturn(mock(AppOpsManager.class)); ++ when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE))) ++ .thenReturn(mock(TelephonyManager.class)); ++ when(mContext.getSystemService(eq(Context.USER_SERVICE))) ++ .thenReturn(mUserManager); ++ ++ when(mContext.checkCallingOrSelfPermission(anyString())) ++ .thenReturn(PackageManager.PERMISSION_GRANTED); ++ when(mContext.getUserId()).thenReturn(0); ++ when(mContext.getPackageManager()).thenReturn(mPackageManager); ++ ++ /** ++ * This is used to give the MmsProviderTest a mocked context which takes a ++ * SmsProvider and attaches it to the ContentResolver with telephony authority. ++ * The mocked context also gives WRITE_APN_SETTINGS permissions ++ */ ++ mContentResolver = new MockContentResolver() { ++ @Override ++ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork, ++ int userHandle) { ++ notifyChangeCount++; ++ } ++ }; ++ when(mContext.getContentResolver()).thenReturn(mContentResolver); ++ ++ // Add authority="mms" to given mmsProvider ++ ProviderInfo providerInfo = new ProviderInfo(); ++ providerInfo.authority = "mms"; ++ ++ // Add context to given mmsProvider ++ mMmsProviderTestable.attachInfoForTesting(mContext, providerInfo); ++ Log.d(TAG, "MockContextWithProvider: mmsProvider.getContext(): " ++ + mMmsProviderTestable.getContext()); ++ ++ // Add given MmsProvider to mResolver with authority="mms" so that ++ // mResolver can send queries to mMmsProvider ++ mContentResolver.addProvider("mms", mMmsProviderTestable); ++ Log.d(TAG, "MockContextWithProvider: Add MmsProvider to mResolver"); ++ notifyChangeCount = 0; ++ } ++ ++ @Override ++ protected void tearDown() throws Exception { ++ super.tearDown(); ++ mMmsProviderTestable.closeDatabase(); ++ } ++ ++ @Test ++ public void testInsertMms() { ++ final ContentValues values = new ContentValues(); ++ values.put(Telephony.Mms.READ, 1); ++ values.put(Telephony.Mms.SEEN, 1); ++ values.put(Telephony.Mms.SUBSCRIPTION_ID, 1); ++ values.put(Telephony.Mms.MESSAGE_BOX, Telephony.Mms.MESSAGE_BOX_ALL); ++ values.put(Telephony.Mms.TEXT_ONLY, 1); ++ values.put(Telephony.Mms.THREAD_ID, 1); ++ ++ Uri expected = Uri.parse("content://mms/1"); ++ Uri actual = mContentResolver.insert(Telephony.Mms.CONTENT_URI, values); ++ ++ assertEquals(expected, actual); ++ assertEquals(1, notifyChangeCount); ++ } ++ ++ @Test ++ public void testInsertUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try { ++ assertNull(mContentResolver.insert(Telephony.Mms.CONTENT_URI, null)); ++ } catch (Exception e) { ++ Log.d(TAG, "Error inserting mms: " + e); ++ } ++ } ++ ++ @Test ++ public void testQueryUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try (Cursor cursor = mContentResolver.query(Telephony.Mms.CONTENT_URI, ++ null, null, null, null)) { ++ assertEquals(0, cursor.getCount()); ++ } catch (Exception e) { ++ Log.d(TAG, "Exception in getting count: " + e); ++ } ++ } ++ ++ @Test ++ public void testUpdateUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try { ++ assertEquals(0, mContentResolver.update(Telephony.Mms.CONTENT_URI, null, null, null)); ++ } catch (Exception e) { ++ Log.d(TAG, "Exception in updating mms: " + e); ++ } ++ } ++ ++ @Test ++ public void testDeleteUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try { ++ assertEquals(0, mContentResolver.delete(Telephony.Mms.CONTENT_URI, null, null)); ++ } catch (Exception e) { ++ Log.d(TAG, "Exception in deleting mms: " + e); ++ } ++ } ++} +diff --git a/tests/src/com/android/providers/telephony/MmsProviderTestable.java b/tests/src/com/android/providers/telephony/MmsProviderTestable.java +new file mode 100644 +index 0000000..cea411b +--- /dev/null ++++ b/tests/src/com/android/providers/telephony/MmsProviderTestable.java +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (C) 2023 The Android Open Source Project ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.android.providers.telephony; ++ ++import static com.android.providers.telephony.MmsSmsDatabaseHelper.CREATE_ADDR_TABLE_STR; ++import static com.android.providers.telephony.MmsSmsDatabaseHelper.CREATE_DRM_TABLE_STR; ++import static com.android.providers.telephony.MmsSmsDatabaseHelper.CREATE_PART_TABLE_STR; ++import static com.android.providers.telephony.MmsSmsDatabaseHelper.CREATE_PDU_TABLE_STR; ++import static com.android.providers.telephony.MmsSmsDatabaseHelper.CREATE_RATE_TABLE_STR; ++ ++import android.database.sqlite.SQLiteDatabase; ++import android.database.sqlite.SQLiteOpenHelper; ++import android.util.Log; ++ ++/** ++ * A subclass of MmsProvider used for testing on an in-memory database ++ */ ++public class MmsProviderTestable extends MmsProvider { ++ private static final String TAG = "MmsProviderTestable"; ++ ++ @Override ++ public boolean onCreate() { ++ Log.d(TAG, "onCreate called: mDbHelper = new InMemoryMmsProviderDbHelper()"); ++ mOpenHelper = new InMemoryMmsProviderDbHelper(); ++ return true; ++ } ++ ++ // close mDbHelper database object ++ protected void closeDatabase() { ++ mOpenHelper.close(); ++ } ++ ++ /** ++ * An in memory DB for MmsProviderTestable to use ++ */ ++ public static class InMemoryMmsProviderDbHelper extends SQLiteOpenHelper { ++ ++ ++ public InMemoryMmsProviderDbHelper() { ++ super(null, // no context is needed for in-memory db ++ null, // db file name is null for in-memory db ++ null, // CursorFactory is null by default ++ 1); // db version is no-op for tests ++ Log.d(TAG, "InMemoryMmsProviderDbHelper creating in-memory database"); ++ } ++ ++ @Override ++ public void onCreate(SQLiteDatabase db) { ++ // Set up the mms tables ++ Log.d(TAG, "InMemoryMmsProviderDbHelper onCreate creating the mms tables"); ++ db.execSQL(CREATE_PDU_TABLE_STR); ++ db.execSQL(CREATE_ADDR_TABLE_STR); ++ db.execSQL(CREATE_PART_TABLE_STR); ++ db.execSQL(CREATE_RATE_TABLE_STR); ++ db.execSQL(CREATE_DRM_TABLE_STR); ++ } ++ ++ @Override ++ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { ++ Log.d(TAG, "InMemorySmsProviderDbHelper onUpgrade doing nothing"); ++ } ++ } ++} +diff --git a/tests/src/com/android/providers/telephony/SmsProviderTest.java b/tests/src/com/android/providers/telephony/SmsProviderTest.java +index 2bc5f0f..f86fcd3 100644 +--- a/tests/src/com/android/providers/telephony/SmsProviderTest.java ++++ b/tests/src/com/android/providers/telephony/SmsProviderTest.java +@@ -16,6 +16,10 @@ + + package com.android.providers.telephony; + ++ ++import static org.mockito.ArgumentMatchers.anyInt; ++import static org.mockito.Mockito.when; ++ + import android.app.AppOpsManager; + import android.content.ContentResolver; + import android.content.ContentValues; +@@ -26,6 +30,7 @@ import android.content.res.Resources; + import android.database.ContentObserver; + import android.database.Cursor; + import android.net.Uri; ++import android.os.UserManager; + import android.provider.Telephony; + import android.telephony.TelephonyManager; + import android.test.mock.MockContentResolver; +@@ -57,6 +62,7 @@ public class SmsProviderTest extends TestCase { + private MockContextWithProvider mContext; + private MockContentResolver mContentResolver; + private SmsProviderTestable mSmsProviderTestable; ++ private UserManager mUserManager; + + private int notifyChangeCount; + +@@ -115,6 +121,8 @@ public class SmsProviderTest extends TestCase { + return Mockito.mock(AppOpsManager.class); + case Context.TELEPHONY_SERVICE: + return Mockito.mock(TelephonyManager.class); ++ case Context.USER_SERVICE: ++ return mUserManager; + default: + return null; + } +@@ -148,6 +156,8 @@ public class SmsProviderTest extends TestCase { + mSmsProviderTestable = new SmsProviderTestable(); + mContext = new MockContextWithProvider(mSmsProviderTestable); + mContentResolver = mContext.getContentResolver(); ++ mUserManager = Mockito.mock(UserManager.class); ++ + notifyChangeCount = 0; + } + +@@ -254,6 +264,51 @@ public class SmsProviderTest extends TestCase { + cursor.close(); + } + ++ @Test ++ public void testInsertUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try { ++ assertNull(mContentResolver.insert(Telephony.Sms.CONTENT_URI, null)); ++ } catch (Exception e) { ++ Log.d(TAG, "Error inserting sms: " + e); ++ } ++ } ++ ++ @Test ++ public void testQueryUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try (Cursor cursor = mContentResolver.query(Telephony.Sms.CONTENT_URI, ++ null, null, null, null)) { ++ assertEquals(0, cursor.getCount()); ++ } catch (Exception e) { ++ Log.d(TAG, "Exception in getting count: " + e); ++ } ++ } ++ ++ @Test ++ public void testUpdateUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try { ++ assertEquals(0, mContentResolver.update(Telephony.Sms.CONTENT_URI, null, null, null)); ++ } catch (Exception e) { ++ Log.d(TAG, "Exception in updating sms: " + e); ++ } ++ } ++ ++ @Test ++ public void testDeleteUsingManagedProfile() { ++ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); ++ ++ try { ++ assertEquals(0, mContentResolver.delete(Telephony.Sms.CONTENT_URI, null, null)); ++ } catch (Exception e) { ++ Log.d(TAG, "Exception in deleting sms: " + e); ++ } ++ } ++ + private ContentValues getFakeRawValue() { + ContentValues values = new ContentValues(); + values.put("pdu", mFakePdu); +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/packages/services/Telecomm/13_0013-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch b/aosp_diff/preliminary/packages/services/Telecomm/13_0013-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch new file mode 100644 index 0000000000..4b00539cc0 --- /dev/null +++ b/aosp_diff/preliminary/packages/services/Telecomm/13_0013-enforce-stricter-rules-when-registering-phoneAccounts.bulletin.patch @@ -0,0 +1,484 @@ +From b74f8e21e06abf3e04ad510dd062dd68aea2eade Mon Sep 17 00:00:00 2001 +From: Thomas Stuart +Date: Mon, 21 Nov 2022 17:36:52 -0800 +Subject: [PATCH] enforce stricter rules when registering phoneAccounts + +- include disable accounts when looking up accounts for a package to + check if the limit is reached (10) +- put a new limit of 10 supported schemes +- put a new limit of 256 characters per scheme +- put a new limit of 256 characters per address +- ensure the Icon can write to memory w/o an exception + +bug: 259064622 +bug: 256819769 +Test: cts + unit +Change-Id: I5eb2a127a44d5ec725d0ba39cb0ef478b12013de +Merged-In: I5eb2a127a44d5ec725d0ba39cb0ef478b12013de +(cherry picked from commit on googleplex-android-review.googlesource.com host: 643089ac4946fed8316e4f9c416b3739bb23bc93) +Merged-In: I5eb2a127a44d5ec725d0ba39cb0ef478b12013de +--- + .../server/telecom/PhoneAccountRegistrar.java | 204 ++++++++++++++++-- + .../server/telecom/TelecomServiceImpl.java | 4 +- + .../tests/PhoneAccountRegistrarTest.java | 118 ++++++++++ + .../telecom/tests/TelecomServiceImplTest.java | 2 +- + 4 files changed, 312 insertions(+), 16 deletions(-) + +diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java +index 19949f59..baf79834 100644 +--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java ++++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java +@@ -30,6 +30,7 @@ import android.graphics.Bitmap; + import android.graphics.BitmapFactory; + import android.graphics.drawable.Icon; + import android.net.Uri; ++import android.os.Binder; + import android.os.Bundle; + import android.os.AsyncTask; + import android.os.PersistableBundle; +@@ -133,9 +134,14 @@ public class PhoneAccountRegistrar { + } + + public static final String FILE_NAME = "phone-account-registrar-state.xml"; ++ public static final String ICON_ERROR_MSG = ++ "Icon cannot be written to memory. Try compressing or downsizing"; + @VisibleForTesting + public static final int EXPECTED_STATE_VERSION = 9; + public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10; ++ public static final int MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT = 100; ++ public static final int MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT = 256; ++ public static final int MAX_SCHEMES_PER_ACCOUNT = 10; + + /** Keep in sync with the same in SipSettings.java */ + private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES"; +@@ -753,6 +759,34 @@ public class PhoneAccountRegistrar { + return getPhoneAccountHandles(0, null, packageName, false, userHandle); + } + ++ ++ /** ++ * includes disabled, includes crossUserAccess ++ */ ++ public List getAllPhoneAccountHandlesForPackage(UserHandle userHandle, ++ String packageName) { ++ return getPhoneAccountHandles(0, null, packageName, true /* includeDisabled */, userHandle); ++ } ++ ++ /** ++ * Retrieves a list of all {@link PhoneAccount#CAPABILITY_SELF_MANAGED} phone accounts ++ * registered by a specified package. ++ * ++ * @param packageName The name of the package that registered the phone accounts. ++ * @return The self-managed phone account handles for the given package. ++ */ ++ public List getSelfManagedPhoneAccountsForPackage(String packageName, ++ UserHandle userHandle) { ++ List phoneAccountsHandles = new ArrayList<>(); ++ for (PhoneAccountHandle pah : getPhoneAccountsForPackage(packageName, ++ userHandle)) { ++ if (isSelfManagedPhoneAccount(pah)) { ++ phoneAccountsHandles.add(pah); ++ } ++ } ++ return phoneAccountsHandles; ++ } ++ + /** + * Determines if a {@link PhoneAccountHandle} is for a self-managed {@link ConnectionService}. + * @param handle The handle. +@@ -772,8 +806,11 @@ public class PhoneAccountRegistrar { + * Performs checks before calling addOrReplacePhoneAccount(PhoneAccount) + * + * @param account The {@code PhoneAccount} to add or replace. +- * @throws SecurityException if package does not have BIND_TELECOM_CONNECTION_SERVICE permission ++ * @throws SecurityException if package does not have BIND_TELECOM_CONNECTION_SERVICE ++ * permission + * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached ++ * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT is reached ++ * @throws IllegalArgumentException if writing the Icon to memory will cause an Exception + */ + public void registerPhoneAccount(PhoneAccount account) { + // Enforce the requirement that a connection service for a phone account has the correct +@@ -785,21 +822,157 @@ public class PhoneAccountRegistrar { + throw new SecurityException("PhoneAccount connection service requires " + + "BIND_TELECOM_CONNECTION_SERVICE permission."); + } +- //Enforce an upper bound on the number of PhoneAccount's a package can register. +- // Most apps should only require 1-2. +- if (getPhoneAccountsForPackage( +- account.getAccountHandle().getComponentName().getPackageName(), +- account.getAccountHandle().getUserHandle()).size() ++ ++ enforceCharacterLimit(account); ++ enforceIconSizeLimit(account); ++ enforceMaxPhoneAccountLimit(account); ++ addOrReplacePhoneAccount(account); ++ } ++ ++ /** ++ * Enforce an upper bound on the number of PhoneAccount's a package can register. ++ * Most apps should only require 1-2. * Include disabled accounts. ++ * ++ * @param account to enforce check on ++ * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached ++ */ ++ private void enforceMaxPhoneAccountLimit(@NonNull PhoneAccount account) { ++ final PhoneAccountHandle accountHandle = account.getAccountHandle(); ++ final UserHandle user = accountHandle.getUserHandle(); ++ final ComponentName componentName = accountHandle.getComponentName(); ++ ++ if (getPhoneAccountHandles(0, null, componentName.getPackageName(), ++ true /* includeDisabled */, user).size() + >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { +- Log.w(this, "Phone account %s reached max registration limit for package", +- account.getAccountHandle()); ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceMaxPhoneAccountLimit"); + throw new IllegalArgumentException( + "Error, cannot register phone account " + account.getAccountHandle() + + " because the limit, " + MAX_PHONE_ACCOUNT_REGISTRATIONS + + ", has been reached"); + } ++ } + +- addOrReplacePhoneAccount(account); ++ /** ++ * determine if there will be an issue writing the icon to memory ++ * ++ * @param account to enforce check on ++ * @throws IllegalArgumentException if writing the Icon to memory will cause an Exception ++ */ ++ @VisibleForTesting ++ public void enforceIconSizeLimit(PhoneAccount account) { ++ if (account.getIcon() == null) { ++ return; ++ } ++ String text = ""; ++ // convert the icon into a Base64 String ++ try { ++ text = XmlSerialization.writeIconToBase64String(account.getIcon()); ++ } catch (IOException e) { ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceIconSizeLimit"); ++ throw new IllegalArgumentException(ICON_ERROR_MSG); ++ } ++ } ++ ++ /** ++ * All {@link PhoneAccount} and{@link PhoneAccountHandle} String and Char-Sequence fields ++ * should be restricted to character limit of MAX_PHONE_ACCOUNT_CHAR_LIMIT to prevent exceptions ++ * when writing large character streams to XML-Serializer. ++ * ++ * @param account to enforce character limit checks on ++ * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT reached ++ */ ++ public void enforceCharacterLimit(PhoneAccount account) { ++ if (account == null) { ++ return; ++ } ++ PhoneAccountHandle handle = account.getAccountHandle(); ++ ++ String[] fields = ++ {"Package Name", "Class Name", "PhoneAccountHandle Id", "Label", "ShortDescription", ++ "GroupId", "Address", "SubscriptionAddress"}; ++ CharSequence[] args = {handle.getComponentName().getPackageName(), ++ handle.getComponentName().getClassName(), handle.getId(), account.getLabel(), ++ account.getShortDescription(), account.getGroupId(), ++ (account.getAddress() != null ? account.getAddress().toString() : ""), ++ (account.getSubscriptionAddress() != null ? ++ account.getSubscriptionAddress().toString() : "")}; ++ ++ for (int i = 0; i < fields.length; i++) { ++ if (args[i] != null && args[i].length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceCharacterLimit"); ++ throw new IllegalArgumentException("The PhoneAccount or PhoneAccountHandle [" ++ + fields[i] + "] field has an invalid character count. PhoneAccount and " ++ + "PhoneAccountHandle String and Char-Sequence fields are limited to " ++ + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters."); ++ } ++ } ++ ++ // Enforce limits on the URI Schemes provided ++ enforceLimitsOnSchemes(account); ++ ++ // Enforce limit on the PhoneAccount#mExtras ++ Bundle extras = account.getExtras(); ++ if (extras != null) { ++ if (extras.keySet().size() > MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT) { ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceCharacterLimit"); ++ throw new IllegalArgumentException("The PhoneAccount#mExtras is limited to " + ++ MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT + " (key,value) pairs."); ++ } ++ ++ for (String key : extras.keySet()) { ++ Object value = extras.get(key); ++ ++ if ((key != null && key.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) || ++ (value instanceof String && ++ ((String) value).length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT)) { ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceCharacterLimit"); ++ throw new IllegalArgumentException("The PhoneAccount#mExtras contains a String" ++ + " key or value that has an invalid character count. PhoneAccount and " ++ + "PhoneAccountHandle String and Char-Sequence fields are limited to " ++ + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters."); ++ } ++ } ++ } ++ } ++ ++ /** ++ * Enforce a character limit on all PA and PAH string or char-sequence fields. ++ * ++ * @param account to enforce check on ++ * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT reached ++ */ ++ @VisibleForTesting ++ public void enforceLimitsOnSchemes(@NonNull PhoneAccount account) { ++ List schemes = account.getSupportedUriSchemes(); ++ ++ if (schemes == null) { ++ return; ++ } ++ ++ if (schemes.size() > MAX_SCHEMES_PER_ACCOUNT) { ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceLimitsOnSchemes"); ++ throw new IllegalArgumentException( ++ "Error, cannot register phone account " + account.getAccountHandle() ++ + " because the URI scheme limit of " ++ + MAX_SCHEMES_PER_ACCOUNT + " has been reached"); ++ } ++ ++ for (String scheme : schemes) { ++ if (scheme.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { ++ EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), ++ "enforceLimitsOnSchemes"); ++ throw new IllegalArgumentException( ++ "Error, cannot register phone account " + account.getAccountHandle() ++ + " because the max scheme limit of " ++ + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " has been reached"); ++ } ++ } + } + + /** +@@ -1523,17 +1696,20 @@ public class PhoneAccountRegistrar { + protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer) + throws IOException { + if (value != null) { +- ByteArrayOutputStream stream = new ByteArrayOutputStream(); +- value.writeToStream(stream); +- byte[] iconByteArray = stream.toByteArray(); +- String text = Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0); +- ++ String text = writeIconToBase64String(value); + serializer.startTag(null, tagName); + serializer.text(text); + serializer.endTag(null, tagName); + } + } + ++ public static String writeIconToBase64String(Icon icon) throws IOException { ++ ByteArrayOutputStream stream = new ByteArrayOutputStream(); ++ icon.writeToStream(stream); ++ byte[] iconByteArray = stream.toByteArray(); ++ return Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0); ++ } ++ + protected void writeLong(String tagName, long value, XmlSerializer serializer) + throws IOException { + serializer.startTag(null, tagName); +diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java +index f773308d..e44835c8 100644 +--- a/src/com/android/server/telecom/TelecomServiceImpl.java ++++ b/src/com/android/server/telecom/TelecomServiceImpl.java +@@ -69,7 +69,9 @@ import com.android.server.telecom.settings.BlockedNumbersActivity; + import java.io.FileDescriptor; + import java.io.PrintWriter; + import java.util.Collections; ++import java.util.HashSet; + import java.util.List; ++import java.util.Set; + + // TODO: Needed for move to system service: import com.android.internal.R; + +@@ -309,7 +311,7 @@ public class TelecomServiceImpl { + try { + Log.startSession("TSI.gPAFP"); + return new ParceledListSlice<>(mPhoneAccountRegistrar +- .getPhoneAccountsForPackage(packageName, callingUserHandle)); ++ .getAllPhoneAccountHandlesForPackage(callingUserHandle, packageName)); + } catch (Exception e) { + Log.e(this, e, "getPhoneAccountsForPackage %s", packageName); + throw e; +diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +index a56036a5..0a10ea17 100644 +--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java ++++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +@@ -22,8 +22,18 @@ import static org.junit.Assert.assertNotNull; + import static org.junit.Assert.assertNull; + import static org.junit.Assert.assertTrue; + import static org.junit.Assert.fail; ++import static org.mockito.ArgumentMatchers.any; ++import static org.mockito.ArgumentMatchers.anyObject; ++import static org.mockito.ArgumentMatchers.isA; + import static org.mockito.Matchers.anyInt; + import static org.mockito.Matchers.anyString; ++import static org.mockito.Mockito.clearInvocations; ++import static org.mockito.Mockito.doThrow; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; ++import static org.mockito.Mockito.spy; ++import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + + import android.content.ComponentName; +@@ -70,6 +80,8 @@ import java.io.BufferedOutputStream; + import java.io.ByteArrayInputStream; + import java.io.ByteArrayOutputStream; + import java.io.File; ++import java.io.IOException; ++import java.io.OutputStream; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; +@@ -82,6 +94,7 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { + private static final int MAX_VERSION = Integer.MAX_VALUE; + private static final String FILE_NAME = "phone-account-registrar-test-1223.xml"; + private static final String TEST_LABEL = "right"; ++ private static final String TEST_ID = "123"; + private PhoneAccountRegistrar mRegistrar; + @Mock private TelecomManager mTelecomManager; + @Mock private DefaultDialerCache mDefaultDialerCache; +@@ -1015,6 +1028,111 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { + assertFalse(PhoneAccountHandle.areFromSamePackage(null, d)); + } + ++ ++ /** ++ * Ensure an IllegalArgumentException is thrown when adding more than 10 schemes for a single ++ * account ++ */ ++ @Test ++ public void testLimitOnSchemeCount() { ++ PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID); ++ PhoneAccount.Builder builder = new PhoneAccount.Builder(handle, TEST_LABEL); ++ for (int i = 0; i < PhoneAccountRegistrar.MAX_PHONE_ACCOUNT_REGISTRATIONS + 1; i++) { ++ builder.addSupportedUriScheme(Integer.toString(i)); ++ } ++ try { ++ mRegistrar.enforceLimitsOnSchemes(builder.build()); ++ fail("should have hit exception in enforceLimitOnSchemes"); ++ } catch (IllegalArgumentException e) { ++ // pass test ++ } ++ } ++ ++ /** ++ * Ensure an IllegalArgumentException is thrown when adding more 256 chars for a single ++ * account ++ */ ++ @Test ++ public void testLimitOnSchemeLength() { ++ PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID); ++ PhoneAccount.Builder builder = new PhoneAccount.Builder(handle, TEST_LABEL); ++ builder.addSupportedUriScheme(generateStringOfLen(257)); ++ try { ++ mRegistrar.enforceLimitsOnSchemes(builder.build()); ++ fail("should have hit exception in enforceLimitOnSchemes"); ++ } catch (IllegalArgumentException e) { ++ // pass test ++ } ++ } ++ ++ /** ++ * Ensure an IllegalArgumentException is thrown when adding an address over the limit ++ */ ++ @Test ++ public void testLimitOnAddress() { ++ String text = generateStringOfLen(100); ++ PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID); ++ PhoneAccount.Builder builder = new PhoneAccount.Builder(handle,TEST_LABEL) ++ .setAddress(Uri.fromParts(text, text, text)); ++ try { ++ mRegistrar.enforceCharacterLimit(builder.build()); ++ fail("failed to throw IllegalArgumentException"); ++ } catch (IllegalArgumentException e) { ++ // pass test ++ } ++ finally { ++ mRegistrar.unregisterPhoneAccount(handle); ++ } ++ } ++ ++ /** ++ * Ensure an IllegalArgumentException is thrown when an Icon that throws an IOException is given ++ */ ++ @Test ++ public void testLimitOnIcon() throws Exception { ++ Icon mockIcon = mock(Icon.class); ++ // GIVEN ++ PhoneAccount.Builder builder = new PhoneAccount.Builder( ++ makeQuickAccountHandle(TEST_ID), TEST_LABEL).setIcon(mockIcon); ++ try { ++ // WHEN ++ Mockito.doThrow(new IOException()) ++ .when(mockIcon).writeToStream(any(OutputStream.class)); ++ //THEN ++ mRegistrar.enforceIconSizeLimit(builder.build()); ++ fail("failed to throw IllegalArgumentException"); ++ } catch (IllegalArgumentException e) { ++ // pass test ++ assertTrue(e.getMessage().contains(PhoneAccountRegistrar.ICON_ERROR_MSG)); ++ } ++ } ++ ++ /** ++ * Ensure an IllegalArgumentException is thrown when providing a SubscriptionAddress that ++ * exceeds the PhoneAccountRegistrar limit. ++ */ ++ @Test ++ public void testLimitOnSubscriptionAddress() throws Exception { ++ String text = generateStringOfLen(100); ++ PhoneAccount.Builder builder = new PhoneAccount.Builder(makeQuickAccountHandle(TEST_ID), ++ TEST_LABEL).setSubscriptionAddress(Uri.fromParts(text, text, text)); ++ try { ++ mRegistrar.enforceCharacterLimit(builder.build()); ++ fail("failed to throw IllegalArgumentException"); ++ } catch (IllegalArgumentException e) { ++ // pass test ++ } ++ } ++ ++ private String generateStringOfLen(int len){ ++ StringBuilder sb = new StringBuilder(); ++ for(int i=0; i < len; i++){ ++ sb.append("a"); ++ } ++ return sb.toString(); ++ } ++ ++ + private static ComponentName makeQuickConnectionServiceComponentName() { + return new ComponentName( + "com.android.server.telecom.tests", +diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java +index d6eadbb2..1f29750b 100644 +--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java ++++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java +@@ -452,7 +452,7 @@ public class TelecomServiceImplTest extends TelecomTestCase { + add(SIP_PA_HANDLE_17); + }}; + when(mFakePhoneAccountRegistrar +- .getPhoneAccountsForPackage(anyString(), any(UserHandle.class))) ++ .getAllPhoneAccountHandlesForPackage(any(UserHandle.class), anyString())) + .thenReturn(phoneAccountHandleList); + makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17); + assertEquals(phoneAccountHandleList, +-- +2.42.0.515.g380fc7ccd1-goog + diff --git a/aosp_diff/preliminary/system/ca-certificates/0002-Remove-E-Tugra-certificates-.bulletin.patch b/aosp_diff/preliminary/system/ca-certificates/0002-Remove-E-Tugra-certificates-.bulletin.patch new file mode 100644 index 0000000000..c1321bf404 --- /dev/null +++ b/aosp_diff/preliminary/system/ca-certificates/0002-Remove-E-Tugra-certificates-.bulletin.patch @@ -0,0 +1,152 @@ +From 0342101ec8c86323a2c2995d5ac1d2803fa54405 Mon Sep 17 00:00:00 2001 +From: Miguel +Date: Thu, 25 May 2023 09:19:54 +0000 +Subject: [PATCH] Remove E-Tugra certificates. + +Test: atest CertificateDataTest +Bug: 284262845 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:cfe61c3ca788218b24753229ccacc3d59fab7eea) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:cf6ceba661a1101099c286974e3eb933b2fefeed) +Merged-In: I3534db3b4ca5623b783eb8e601dffd0449f5d925 +Change-Id: I3534db3b4ca5623b783eb8e601dffd0449f5d925 +--- + files/cb156124.0 | 127 ----------------------------------------------- + 1 file changed, 127 deletions(-) + delete mode 100644 files/cb156124.0 + +diff --git a/files/cb156124.0 b/files/cb156124.0 +deleted file mode 100644 +index 27a4727..0000000 +--- a/files/cb156124.0 ++++ /dev/null +@@ -1,127 +0,0 @@ +------BEGIN CERTIFICATE----- +-MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +-BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +-aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +-BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +-Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +-MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +-BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +-em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +-ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +-B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +-D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +-Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +-q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +-k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +-fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +-dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +-ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +-zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +-rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +-U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +-Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +-XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +-Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +-HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +-GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +-77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 +-+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +-vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +-FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +-yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +-AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +-y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +-NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +------END CERTIFICATE----- +-Certificate: +- Data: +- Version: 3 (0x2) +- Serial Number: 7667447206703254355 (0x6a683e9c519bcb53) +- Signature Algorithm: sha256WithRSAEncryption +- Issuer: C=TR, L=Ankara, O=E-Tu\xC4\x9Fra EBG Bili\xC5\x9Fim Teknolojileri ve Hizmetleri A.\xC5\x9E., OU=E-Tugra Sertifikasyon Merkezi, CN=E-Tugra Certification Authority +- Validity +- Not Before: Mar 5 12:09:48 2013 GMT +- Not After : Mar 3 12:09:48 2023 GMT +- Subject: C=TR, L=Ankara, O=E-Tu\xC4\x9Fra EBG Bili\xC5\x9Fim Teknolojileri ve Hizmetleri A.\xC5\x9E., OU=E-Tugra Sertifikasyon Merkezi, CN=E-Tugra Certification Authority +- Subject Public Key Info: +- Public Key Algorithm: rsaEncryption +- RSA Public-Key: (4096 bit) +- Modulus: +- 00:e2:f5:3f:93:05:51:1e:85:62:54:5e:7a:0b:f5: +- 18:07:83:ae:7e:af:7c:f7:d4:8a:6b:a5:63:43:39: +- b9:4b:f7:c3:c6:64:89:3d:94:2e:54:80:52:39:39: +- 07:4b:4b:dd:85:07:76:87:cc:bf:2f:95:4c:cc:7d: +- a7:3d:bc:47:0f:98:70:f8:8c:85:1e:74:8e:92:6d: +- 1b:40:d1:99:0d:bb:75:6e:c8:a9:6b:9a:c0:84:31: +- af:ca:43:cb:eb:2b:34:e8:8f:97:6b:01:9b:d5:0e: +- 4a:08:aa:5b:92:74:85:43:d3:80:ae:a1:88:5b:ae: +- b3:ea:5e:cb:16:9a:77:44:c8:a1:f6:54:68:ce:de: +- 8f:97:2b:ba:5b:40:02:0c:64:17:c0:b5:93:cd:e1: +- f1:13:66:ce:0c:79:ef:d1:91:28:ab:5f:a0:12:52: +- 30:73:19:8e:8f:e1:8c:07:a2:c3:bb:4a:f0:ea:1f: +- 15:a8:ee:25:cc:a4:46:f8:1b:22:ef:b3:0e:43:ba: +- 2c:24:b8:c5:2c:5c:d4:1c:f8:5d:64:bd:c3:93:5e: +- 28:a7:3f:27:f1:8e:1e:d3:2a:50:05:a3:55:d9:cb: +- e7:39:53:c0:98:9e:8c:54:62:8b:26:b0:f7:7d:8d: +- 7c:e4:c6:9e:66:42:55:82:47:e7:b2:58:8d:66:f7: +- 07:7c:2e:36:e6:50:1c:3f:db:43:24:c5:bf:86:47: +- 79:b3:79:1c:f7:5a:f4:13:ec:6c:f8:3f:e2:59:1f: +- 95:ee:42:3e:b9:ad:a8:32:85:49:97:46:fe:4b:31: +- 8f:5a:cb:ad:74:47:1f:e9:91:b7:df:28:04:22:a0: +- d4:0f:5d:e2:79:4f:ea:6c:85:86:bd:a8:a6:ce:e4: +- fa:c3:e1:b3:ae:de:3c:51:ee:cb:13:7c:01:7f:84: +- 0e:5d:51:94:9e:13:0c:b6:2e:a5:4c:f9:39:70:36: +- 6f:96:ca:2e:0c:44:55:c5:ca:fa:5d:02:a3:df:d6: +- 64:8c:5a:b3:01:0a:a9:b5:0a:47:17:ff:ef:91:40: +- 2a:8e:a1:46:3a:31:98:e5:11:fc:cc:bb:49:56:8a: +- fc:b9:d0:61:9a:6f:65:6c:e6:c3:cb:3e:75:49:fe: +- 8f:a7:e2:89:c5:67:d7:9d:46:13:4e:31:76:3b:24: +- b3:9e:11:65:86:ab:7f:ef:1d:d4:f8:bc:e7:ac:5a: +- 5c:b7:5a:47:5c:55:ce:55:b4:22:71:5b:5b:0b:f0: +- cf:dc:a0:61:64:ea:a9:d7:68:0a:63:a7:e0:0d:3f: +- a0:af:d3:aa:d2:7e:ef:51:a0:e6:51:2b:55:92:15: +- 17:53:cb:b7:66:0e:66:4c:f8:f9:75:4c:90:e7:12: +- 70:c7:45 +- Exponent: 65537 (0x10001) +- X509v3 extensions: +- X509v3 Subject Key Identifier: +- 2E:E3:DB:B2:49:D0:9C:54:79:5C:FA:27:2A:FE:CC:4E:D2:E8:4E:54 +- X509v3 Basic Constraints: critical +- CA:TRUE +- X509v3 Authority Key Identifier: +- keyid:2E:E3:DB:B2:49:D0:9C:54:79:5C:FA:27:2A:FE:CC:4E:D2:E8:4E:54 +- +- X509v3 Key Usage: critical +- Certificate Sign, CRL Sign +- Signature Algorithm: sha256WithRSAEncryption +- 05:37:3a:f4:4d:b7:45:e2:45:75:24:8f:b6:77:52:e8:1c:d8: +- 10:93:65:f3:f2:59:06:a4:3e:1e:29:ec:5d:d1:d0:ab:7c:e0: +- 0a:90:48:78:ed:4e:98:03:99:fe:28:60:91:1d:30:1d:b8:63: +- 7c:a8:e6:35:b5:fa:d3:61:76:e6:d6:07:4b:ca:69:9a:b2:84: +- 7a:77:93:45:17:15:9f:24:d0:98:13:12:ff:bb:a0:2e:fd:4e: +- 4c:87:f8:ce:5c:aa:98:1b:05:e0:00:46:4a:82:80:a5:33:8b: +- 28:dc:ed:38:d3:df:e5:3e:e9:fe:fb:59:dd:61:84:4f:d2:54: +- 96:13:61:13:3e:8f:80:69:be:93:47:b5:35:43:d2:5a:bb:3d: +- 5c:ef:b3:42:47:cd:3b:55:13:06:b0:09:db:fd:63:f6:3a:88: +- 0a:99:6f:7e:e1:ce:1b:53:6a:44:66:23:51:08:7b:bc:5b:52: +- a2:fd:06:37:38:40:61:8f:4a:96:b8:90:37:f8:66:c7:78:90: +- 00:15:2e:8b:ad:51:35:53:07:a8:6b:68:ae:f9:4e:3c:07:26: +- cd:08:05:70:cc:39:3f:76:bd:a5:d3:67:26:01:86:a6:53:d2: +- 60:3b:7c:43:7f:55:8a:bc:95:1a:c1:28:39:4c:1f:43:d2:91: +- f4:72:59:8a:b9:56:fc:3f:b4:9d:da:70:9c:76:5a:8c:43:50: +- ee:8e:30:72:4d:df:ff:49:f7:c6:a9:67:d9:6d:ac:02:11:e2: +- 3a:16:25:a7:58:08:cb:6f:53:41:9c:48:38:47:68:33:d1:d7: +- c7:8f:d4:74:21:d4:c3:05:90:7a:ff:ce:96:88:b1:15:29:5d: +- 23:ab:d0:60:a1:12:4f:de:f4:17:cd:32:e5:c9:bf:c8:43:ad: +- fd:2e:8e:f1:af:e2:f4:98:fa:12:1f:20:d8:c0:a7:0c:85:c5: +- 90:f4:3b:2d:96:26:b1:2c:be:4c:ab:eb:b1:d2:8a:c9:db:78: +- 13:0f:1e:09:9d:6d:8f:00:9f:02:da:c1:fa:1f:7a:7a:09:c4: +- 4a:e6:88:2a:97:9f:89:8b:fd:37:5f:5f:3a:ce:38:59:86:4b: +- af:71:0b:b4:d8:f2:70:4f:9f:32:13:e3:b0:a7:57:e5:da:da: +- 43:cb:84:34:f2:28:c4:ea:6d:f4:2a:ef:c1:6b:76:da:fb:7e: +- bb:85:3c:d2:53:c2:4d:be:71:e1:45:d1:fd:23:67:0d:13:75: +- fb:cf:65:67:22:9d:ae:b0:09:d1:09:ff:1d:34:bf:fe:23:97: +- 37:d2:39:fa:3d:0d:06:0b:b4:db:3b:a3:ab:6f:5c:1d:b6:7e: +- e8:b3:82:34:ed:06:5c:24 +-SHA1 Fingerprint=51:C6:E7:08:49:06:6E:F3:92:D4:5C:A0:0D:6D:A3:62:8F:C3:52:39 +-- +2.42.0.515.g380fc7ccd1-goog +