diff --git a/Patches/Common/android_external_webp/373948.patch b/Patches/Common/android_external_webp/373948.patch new file mode 100644 index 00000000..0be1b224 --- /dev/null +++ b/Patches/Common/android_external_webp/373948.patch @@ -0,0 +1,214 @@ +From c5803c1b6a680ad1c30f9655508784e07c08be36 Mon Sep 17 00:00:00 2001 +From: James Zern +Date: Sat, 9 Sep 2023 14:02:18 -0700 +Subject: [PATCH] update to v1.1.0-8-g50f60add + +https://chromium.googlesource.com/webm/libwebp/+log/v1.1.0..v1.1.0-8-g50f60add + +50f60add Fix OOB write in BuildHuffmanTable. +5df85e9c EncodeAlphaInternal: clear result->bw on error +89e226a3 GetBackwardReferences: fail on alloc error +4d0964cd BackwardReferencesHashChainDistanceOnly: fix segfault on OOM +5d805f72 VP8LEncodeStream: fix segfault on OOM +b14eba64 alpha_processing_neon.c: fix 0x01... typo +9183ff2e alpha_processing_neon.c: fix Dispatch/ExtractAlpha_NEON +68d52453 Fix lossless encoding for MIPS. + +Bug: 299477569 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c3f928a1d30e48a400ed434130da3609cbfd54ad) +Merged-In: Ia4290d2a5f16a61ae0729b7d55ba144251c2b988 +Change-Id: Ia4290d2a5f16a61ae0729b7d55ba144251c2b988 +--- + README.android | 2 +- + README.version | 4 ++-- + src/dsp/alpha_processing_neon.c | 6 ++++-- + src/dsp/lossless_enc_mips32.c | 8 ++++---- + src/enc/alpha_enc.c | 4 +++- + src/enc/backward_references_cost_enc.c | 2 +- + src/enc/backward_references_enc.c | 13 +++++++------ + src/enc/vp8l_enc.c | 11 ++++++++--- + 8 files changed, 30 insertions(+), 20 deletions(-) + +diff --git a/README.android b/README.android +index 94fd4d4a..93c20140 100644 +--- a/README.android ++++ b/README.android +@@ -1,5 +1,5 @@ + URL: https://chromium.googlesource.com/webm/libwebp +-Version: v1.1.0 ++Version: v1.1.0-8-g50f60add + License: Google BSD like + + Local modifications: +diff --git a/README.version b/README.version +index f94ac059..621b44fa 100644 +--- a/README.version ++++ b/README.version +@@ -1,3 +1,3 @@ +-URL: https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.1.0.tar.gz +-Version: 1.1.0 ++URL: https://chromium.googlesource.com/webm/libwebp/+archive/v1.1.0-8-g50f60add.tar.gz ++Version: v1.1.0-8-g50f60add + BugComponent: 20174 +diff --git a/src/dsp/alpha_processing_neon.c b/src/dsp/alpha_processing_neon.c +index 9d554217..27d71750 100644 +--- a/src/dsp/alpha_processing_neon.c ++++ b/src/dsp/alpha_processing_neon.c +@@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first, + static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint8_t* dst, int dst_stride) { +- uint32_t alpha_mask = 0xffffffffu; ++ uint32_t alpha_mask = 0xffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; +@@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, + dst += dst_stride; + } + vst1_u8((uint8_t*)tmp, mask8); ++ alpha_mask *= 0x01010101; + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask != 0xffffffffu); +@@ -134,7 +135,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride, + static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, + int width, int height, + uint8_t* alpha, int alpha_stride) { +- uint32_t alpha_mask = 0xffffffffu; ++ uint32_t alpha_mask = 0xffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; +@@ -156,6 +157,7 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, + alpha += alpha_stride; + } + vst1_u8((uint8_t*)tmp, mask8); ++ alpha_mask *= 0x01010101; + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask == 0xffffffffu); +diff --git a/src/dsp/lossless_enc_mips32.c b/src/dsp/lossless_enc_mips32.c +index 0412a093..99630517 100644 +--- a/src/dsp/lossless_enc_mips32.c ++++ b/src/dsp/lossless_enc_mips32.c +@@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[], + static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb, + uint32_t* pout, int size) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; +- const uint32_t end = ((size) / 4) * 4; ++ const int end = ((size) / 4) * 4; + const uint32_t* const LoopEnd = pa + end; + int i; + ASM_START + ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) + ASM_END_0 +- for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i]; ++ for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i]; + } + + static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; +- const uint32_t end = ((size) / 4) * 4; ++ const int end = ((size) / 4) * 4; + const uint32_t* const LoopEnd = pa + end; + int i; + ASM_START + ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) + ASM_END_1 +- for (i = end; i < size; ++i) pout[i] += pa[i]; ++ for (i = 0; i < size - end; ++i) pout[i] += pa[i]; + } + + #undef ASM_END_1 +diff --git a/src/enc/alpha_enc.c b/src/enc/alpha_enc.c +index dce9ca95..c786ae59 100644 +--- a/src/enc/alpha_enc.c ++++ b/src/enc/alpha_enc.c +@@ -13,6 +13,7 @@ + + #include + #include ++#include + + #include "src/enc/vp8i_enc.h" + #include "src/dsp/dsp.h" +@@ -148,6 +149,7 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, + } + } else { + VP8LBitWriterWipeOut(&tmp_bw); ++ memset(&result->bw, 0, sizeof(result->bw)); + return 0; + } + } +@@ -162,7 +164,7 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, + header = method | (filter << 2); + if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; + +- VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size); ++ if (!VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size)) ok = 0; + ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN); + ok = ok && VP8BitWriterAppend(&result->bw, output, output_size); + +diff --git a/src/enc/backward_references_cost_enc.c b/src/enc/backward_references_cost_enc.c +index 516abd73..5eb24d44 100644 +--- a/src/enc/backward_references_cost_enc.c ++++ b/src/enc/backward_references_cost_enc.c +@@ -577,7 +577,7 @@ static int BackwardReferencesHashChainDistanceOnly( + (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); + VP8LColorCache hashers; + CostManager* cost_manager = +- (CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager)); ++ (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager)); + int offset_prev = -1, len_prev = -1; + double offset_cost = -1; + int first_offset_is_constant = -1; // initialized with 'impossible' value +diff --git a/src/enc/backward_references_enc.c b/src/enc/backward_references_enc.c +index d445b40f..59809b16 100644 +--- a/src/enc/backward_references_enc.c ++++ b/src/enc/backward_references_enc.c +@@ -912,13 +912,14 @@ static VP8LBackwardRefs* GetBackwardReferences( + quality >= 25) { + const VP8LHashChain* const hash_chain_tmp = + (lz77_type_best == kLZ77Standard) ? hash_chain : &hash_chain_box; +- if (VP8LBackwardReferencesTraceBackwards(width, height, argb, *cache_bits, +- hash_chain_tmp, best, worst)) { +- double bit_cost_trace; +- VP8LHistogramCreate(histo, worst, *cache_bits); +- bit_cost_trace = VP8LHistogramEstimateBits(histo); +- if (bit_cost_trace < bit_cost_best) best = worst; ++ double bit_cost_trace; ++ if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, *cache_bits, ++ hash_chain_tmp, best, worst)) { ++ goto Error; + } ++ VP8LHistogramCreate(histo, worst, *cache_bits); ++ bit_cost_trace = VP8LHistogramEstimateBits(histo); ++ if (bit_cost_trace < bit_cost_best) best = worst; + } + + BackwardReferences2DLocality(width, best); +diff --git a/src/enc/vp8l_enc.c b/src/enc/vp8l_enc.c +index 2efd403f..c9dea0bd 100644 +--- a/src/enc/vp8l_enc.c ++++ b/src/enc/vp8l_enc.c +@@ -1693,11 +1693,16 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, + const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); + int ok_main; + ++ if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) { ++ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); ++ VP8LEncoderDelete(enc_main); ++ return 0; ++ } ++ + // Analyze image (entropy, num_palettes etc) +- if (enc_main == NULL || +- !EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, ++ if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, + &red_and_blue_always_zero) || +- !EncoderInit(enc_main) || !VP8LBitWriterInit(&bw_side, 0)) { ++ !EncoderInit(enc_main)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } diff --git a/Patches/LineageOS-17.1/android_frameworks_av/373949.patch b/Patches/LineageOS-17.1/android_frameworks_av/373949.patch new file mode 100644 index 00000000..5c003478 --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_av/373949.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 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:1401a723899766632363129265b30d433ac69c44) +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 3b298a9bf3..e4467bbfdc 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 { diff --git a/Patches/LineageOS-17.1/android_frameworks_av/373950.patch b/Patches/LineageOS-17.1/android_frameworks_av/373950.patch new file mode 100644 index 00000000..00310b8a --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_av/373950.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 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:73d89318a658ece5f337c5f9c1ec1149c52eb722) +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 bd6a6c679a..09eb96a00d 100644 +--- a/media/mtp/MtpFfsHandle.cpp ++++ b/media/mtp/MtpFfsHandle.cpp +@@ -296,6 +296,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(); +@@ -662,6 +666,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; +@@ -673,6 +682,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 fe343f74f6..ae78db2877 100644 +--- a/media/mtp/MtpFfsHandle.h ++++ b/media/mtp/MtpFfsHandle.h +@@ -58,6 +58,10 @@ protected: + + bool mCanceled; + ++ 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; diff --git a/Patches/LineageOS-17.1/android_frameworks_base/0007-Always_Restict_Serial.patch b/Patches/LineageOS-17.1/android_frameworks_base/0007-Always_Restict_Serial.patch index 88dcc104..02588892 100644 --- a/Patches/LineageOS-17.1/android_frameworks_base/0007-Always_Restict_Serial.patch +++ b/Patches/LineageOS-17.1/android_frameworks_base/0007-Always_Restict_Serial.patch @@ -10,10 +10,10 @@ requiring the READ_PHONE_STATE permission. 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java -index ec8841debb7a..c9d3d44beb02 100644 +index 3e99e594a702..409c546ca624 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java -@@ -5010,12 +5010,7 @@ public class ActivityManagerService extends IActivityManager.Stub +@@ -5026,12 +5026,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } diff --git a/Patches/LineageOS-17.1/android_frameworks_base/368062-backport.patch b/Patches/LineageOS-17.1/android_frameworks_base/368062-backport.patch index 219965c4..7a41e86b 100644 --- a/Patches/LineageOS-17.1/android_frameworks_base/368062-backport.patch +++ b/Patches/LineageOS-17.1/android_frameworks_base/368062-backport.patch @@ -13,7 +13,7 @@ Change-Id: Iecfc1fb962de611cbe3c51a44ba4fded53925a7d 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java -index ec6d7ffaedb0..08658694c5b8 100644 +index ec6d7ffaedb0..818d6576ac02 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -51,6 +51,7 @@ import android.graphics.Color; diff --git a/Patches/LineageOS-17.1/android_frameworks_base/373951.patch b/Patches/LineageOS-17.1/android_frameworks_base/373951.patch new file mode 100644 index 00000000..93a61101 --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_base/373951.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 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:1896c2e7068c9ec1ab8355d863d7e8107d5d5706) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:75fcbb37617246c43c2af34b12c9ae4b4043f9ac) +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 7921a89ca96f..d8eefc3d3be4 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -2987,8 +2987,11 @@ public class Notification implements Parcelable + * + * @hide + */ +- public void setAllowlistToken(@Nullable IBinder token) { +- mWhitelistToken = token; ++ public void clearAllowlistToken() { ++ mWhitelistToken = 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 d056eac37039..e09491867f91 100755 +--- a/services/core/java/com/android/server/notification/NotificationManagerService.java ++++ b/services/core/java/com/android/server/notification/NotificationManagerService.java +@@ -3249,7 +3249,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(), diff --git a/Patches/LineageOS-17.1/android_frameworks_base/373952.patch b/Patches/LineageOS-17.1/android_frameworks_base/373952.patch new file mode 100644 index 00000000..c93cebd7 --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_base/373952.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Piyush Mehrotra +Date: Thu, 27 Jul 2023 19:35:14 +0000 +Subject: [PATCH] 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:52b91363583c4e2b68f1a818b067cefe04809285) +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 ec8841debb7a..3e99e594a702 100644 +--- a/services/core/java/com/android/server/am/ActivityManagerService.java ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java +@@ -3136,6 +3136,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 = getPackageManagerInternalLocked().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); +@@ -14345,13 +14361,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) { diff --git a/Patches/LineageOS-17.1/android_frameworks_base/373953.patch b/Patches/LineageOS-17.1/android_frameworks_base/373953.patch new file mode 100644 index 00000000..b8b60992 --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_base/373953.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 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:60bfbde79f2ffb012abced55d358fdf6380c0bae) +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; diff --git a/Patches/LineageOS-17.1/android_frameworks_base/373954-backport.patch b/Patches/LineageOS-17.1/android_frameworks_base/373954-backport.patch new file mode 100644 index 00000000..361f3ceb --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_base/373954-backport.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vova Sharaienko +Date: Mon, 24 Jul 2023 23:19:34 +0000 +Subject: [PATCH] RESTRICT AUTOMERGE 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:03de4e4f1a0546fdd3b002651851bee9ffe0e11b) +Merged-In: I1e886f9ccb7203714216da061c35e793b2a63d8a +Change-Id: I1e886f9ccb7203714216da061c35e793b2a63d8a +--- + cmds/statsd/src/StatsService.cpp | 23 +++++++++++++++++++++-- + cmds/statsd/src/StatsService.h | 9 +++++++++ + 2 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp +index 64b7aae01619..f158723f16a0 100644 +--- a/cmds/statsd/src/StatsService.cpp ++++ b/cmds/statsd/src/StatsService.cpp +@@ -205,12 +205,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. */ +@@ -219,6 +222,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. +@@ -1605,6 +1615,15 @@ void StatsService::binderDied(const wp & who) { + 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/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h +index 5f1335efc2e0..412f1c30ea4d 100644 +--- a/cmds/statsd/src/StatsService.h ++++ b/cmds/statsd/src/StatsService.h +@@ -397,6 +397,14 @@ private: + */ + void set_config(int uid, const string& name, const StatsdConfig& config); + ++ /* ++ * This method is used to stop log reader thread. ++ */ ++ void stopReadingLogs(); ++ ++ std::atomic mIsStopRequested = false; ++ ++ + /** + * Tracks the uid <--> package name mapping. + */ +@@ -439,6 +447,7 @@ private: + */ + mutable mutex mShellSubscriberMutex; + std::shared_ptr mEventQueue; ++ std::unique_ptr mLogsReaderThread; + + FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart); + FRIEND_TEST(StatsServiceTest, TestAddConfig_simple); diff --git a/Patches/LineageOS-17.1/android_frameworks_base/373955.patch b/Patches/LineageOS-17.1/android_frameworks_base/373955.patch new file mode 100644 index 00000000..aeec780b --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_base/373955.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Songchun Fan +Date: Mon, 14 Aug 2023 15:24:11 -0700 +Subject: [PATCH] verify ringtone URI before setting + +Similar to ag/24422287, but the same URI verification should be done in +SettingsProvider as well, which can be called by apps via +Settings.System API or ContentProvider APIs without using +RingtoneManager. + +BUG: 227201030 +Test: manual with a test app. Will add a CTS test. +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1b234678ec122994ccbfc52ac48aafdad7fdb1ed) +Merged-In: Ic0ffa1db14b5660d02880b632a7f2ad9e6e5d84b +Change-Id: Ic0ffa1db14b5660d02880b632a7f2ad9e6e5d84b +--- + .../providers/settings/SettingsProvider.java | 31 +++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +index 760b0604a604..7cb41275984e 100644 +--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java ++++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +@@ -1734,6 +1734,9 @@ public class SettingsProvider extends ContentProvider { + cacheName = Settings.System.ALARM_ALERT_CACHE; + } + if (cacheName != null) { ++ if (!isValidAudioUri(name, value)) { ++ return false; ++ } + final File cacheFile = new File( + getRingtoneCacheDir(owningUserId), cacheName); + cacheFile.delete(); +@@ -1766,6 +1769,34 @@ public class SettingsProvider extends ContentProvider { + } + } + ++ private boolean isValidAudioUri(String name, String uri) { ++ if (uri != null) { ++ Uri audioUri = Uri.parse(uri); ++ if (Settings.AUTHORITY.equals( ++ ContentProvider.getAuthorityWithoutUserId(audioUri.getAuthority()))) { ++ // Don't accept setting the default uri to self-referential URIs like ++ // Settings.System.DEFAULT_RINGTONE_URI, which is an alias to the value of this ++ // setting. ++ return false; ++ } ++ final String mimeType = getContext().getContentResolver().getType(audioUri); ++ if (mimeType == null) { ++ Slog.e(LOG_TAG, ++ "mutateSystemSetting for setting: " + name + " URI: " + audioUri ++ + " ignored: failure to find mimeType (no access from this context?)"); ++ return false; ++ } ++ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg") ++ || mimeType.equals("application/x-flac"))) { ++ Slog.e(LOG_TAG, ++ "mutateSystemSetting for setting: " + name + " URI: " + audioUri ++ + " ignored: associated mimeType: " + mimeType + " is not an audio type"); ++ return false; ++ } ++ } ++ return true; ++ } ++ + private boolean hasWriteSecureSettingsPermission() { + // Write secure settings is a more protected permission. If caller has it we are good. + if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) diff --git a/Patches/LineageOS-17.1/android_packages_providers_MediaProvider/368071.patch b/Patches/LineageOS-17.1/android_packages_providers_MediaProvider/368071.patch new file mode 100644 index 00000000..a8c37479 --- /dev/null +++ b/Patches/LineageOS-17.1/android_packages_providers_MediaProvider/368071.patch @@ -0,0 +1,267 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sergey Nikolaienkov +Date: Tue, 28 Mar 2023 12:22:31 +0200 +Subject: [PATCH] Fix path traversal vulnerabilities in MediaProvider + +Canonicalize filepath provided by the caller when hanling SCAN_FILE_CALL +method call in MediaProvider. +Additionally, make sure to check access permission in SCAN_FILE_CALL +(using enforceCallingPermissionInternal()). + +Preemptively canonicalize Files provided as an arguments to the public +API methods in ModernMediaScanner (scanFile(), scanDirectory() and +onDirectoryDirty()) to prevent path traversal attacks. + +Bug: 262244882 +Test: atest MediaProviderTests +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5d2808f30c9dbe35ddbefeda4845328557569a93) +Merged-In: I61e77d69ae857984b819fa0ea27bec5c26a34842 +Change-Id: I61e77d69ae857984b819fa0ea27bec5c26a34842 + +Change-Id: Idf0babc3ab4cae14e69ab7448b914510861a47d7 +--- + .../providers/media/MediaProvider.java | 88 +++++++++++++------ + .../media/scan/LegacyMediaScanner.java | 25 +++++- + .../media/scan/ModernMediaScanner.java | 23 ++++- + 3 files changed, 108 insertions(+), 28 deletions(-) + +diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java +index 822d69537..0887bd6ae 100644 +--- a/src/com/android/providers/media/MediaProvider.java ++++ b/src/com/android/providers/media/MediaProvider.java +@@ -2317,18 +2317,25 @@ public class MediaProvider extends ContentProvider { + } + + private static @Nullable String extractRelativePath(@Nullable String data) { +- data = getCanonicalPath(data); + if (data == null) return null; + +- final Matcher matcher = PATTERN_RELATIVE_PATH.matcher(data); ++ final String path; ++ try { ++ path = getCanonicalPath(data); ++ } catch (IOException e) { ++ Log.d(TAG, "Unable to get canonical path from invalid data path: " + data, e); ++ return null; ++ } ++ ++ final Matcher matcher = PATTERN_RELATIVE_PATH.matcher(path); + if (matcher.find()) { +- final int lastSlash = data.lastIndexOf('/'); ++ final int lastSlash = path.lastIndexOf('/'); + if (lastSlash == -1 || lastSlash < matcher.end()) { + // This is a file in the top-level directory, so relative path is "/" + // which is different than null, which means unknown path + return "/"; + } else { +- return data.substring(matcher.end(), lastSlash + 1); ++ return path.substring(matcher.end(), lastSlash + 1); + } + } else { + return null; +@@ -4193,30 +4200,45 @@ public class MediaProvider extends ContentProvider { + @Override + public Bundle call(String method, String arg, Bundle extras) { + switch (method) { +- case MediaStore.SCAN_FILE_CALL: ++ case MediaStore.SCAN_FILE_CALL: { ++ final LocalCallingIdentity token = clearLocalCallingIdentity(); ++ final CallingIdentity providerToken = clearCallingIdentity(); ++ ++ final Uri uri; ++ try { ++ final Uri fileUri = extras.getParcelable(Intent.EXTRA_STREAM); ++ File file; ++ try { ++ file = getCanonicalFile(fileUri.getPath()); ++ } catch (IOException e) { ++ file = null; ++ } ++ ++ uri = file != null ? MediaScanner.instance(getContext()).scanFile(file) : null; ++ } finally { ++ restoreCallingIdentity(providerToken); ++ restoreLocalCallingIdentity(token); ++ } ++ ++ final Bundle res = new Bundle(); ++ res.putParcelable(Intent.EXTRA_STREAM, uri); ++ return res; ++ } + case MediaStore.SCAN_VOLUME_CALL: { + final LocalCallingIdentity token = clearLocalCallingIdentity(); + final CallingIdentity providerToken = clearCallingIdentity(); ++ + try { + final Uri uri = extras.getParcelable(Intent.EXTRA_STREAM); + final File file = new File(uri.getPath()); +- final Bundle res = new Bundle(); +- switch (method) { +- case MediaStore.SCAN_FILE_CALL: +- res.putParcelable(Intent.EXTRA_STREAM, +- MediaScanner.instance(getContext()).scanFile(file)); +- break; +- case MediaStore.SCAN_VOLUME_CALL: +- MediaService.onScanVolume(getContext(), Uri.fromFile(file)); +- break; +- } +- return res; ++ MediaService.onScanVolume(getContext(), Uri.fromFile(file)); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + restoreCallingIdentity(providerToken); + restoreLocalCallingIdentity(token); + } ++ return Bundle.EMPTY; + } + case MediaStore.UNHIDE_CALL: { + throw new UnsupportedOperationException(); +@@ -6705,14 +6727,30 @@ public class MediaProvider extends ContentProvider { + return s.toString(); + } + +- @Nullable +- private static String getCanonicalPath(@Nullable String path) { +- if (path == null) return null; +- try { +- return new File(path).getCanonicalPath(); +- } catch (IOException e) { +- Log.d(TAG, "Unable to get canonical path from invalid data path: " + path, e); +- return null; +- } ++ /** ++ * Returns the canonical {@link File} for the provided abstract pathname. ++ * ++ * @return The canonical pathname string denoting the same file or directory as this abstract ++ * pathname ++ * @see File#getCanonicalFile() ++ */ ++ @NonNull ++ public static File getCanonicalFile(@NonNull String path) throws IOException { ++ Objects.requireNonNull(path); ++ return new File(path).getCanonicalFile(); + } ++ ++ /** ++ * Returns the canonical pathname string of the provided abstract pathname. ++ * ++ * @return The canonical pathname string denoting the same file or directory as this abstract ++ * pathname. ++ * @see File#getCanonicalPath() ++ */ ++ @NonNull ++ public static String getCanonicalPath(@NonNull String path) throws IOException { ++ Objects.requireNonNull(path); ++ return new File(path).getCanonicalPath(); ++ } ++ + } +diff --git a/src/com/android/providers/media/scan/LegacyMediaScanner.java b/src/com/android/providers/media/scan/LegacyMediaScanner.java +index 5041265cb..eb28b5b59 100644 +--- a/src/com/android/providers/media/scan/LegacyMediaScanner.java ++++ b/src/com/android/providers/media/scan/LegacyMediaScanner.java +@@ -16,16 +16,23 @@ + + package com.android.providers.media.scan; + ++import static java.util.Objects.requireNonNull; ++ ++import android.annotation.NonNull; + import android.content.Context; + import android.net.Uri; + import android.os.Trace; + import android.provider.MediaStore; ++import android.util.Log; + + import libcore.net.MimeUtils; + + import java.io.File; ++import java.io.IOException; + + public class LegacyMediaScanner implements MediaScanner { ++ private static final String TAG = "LegacyMediaScanner"; ++ + private final Context mContext; + + public LegacyMediaScanner(Context context) { +@@ -39,6 +46,14 @@ public class LegacyMediaScanner implements MediaScanner { + + @Override + public void scanDirectory(File file) { ++ requireNonNull(file); ++ try { ++ file = file.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize directory to scan" + file, e); ++ return; ++ } ++ + final String path = file.getAbsolutePath(); + final String volumeName = MediaStore.getVolumeName(file); + +@@ -52,7 +67,15 @@ public class LegacyMediaScanner implements MediaScanner { + } + + @Override +- public Uri scanFile(File file) { ++ public Uri scanFile(@NonNull File file) { ++ requireNonNull(file); ++ try { ++ file = file.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize file to scan" + file, e); ++ return null; ++ } ++ + final String path = file.getAbsolutePath(); + final String volumeName = MediaStore.getVolumeName(file); + +diff --git a/src/com/android/providers/media/scan/ModernMediaScanner.java b/src/com/android/providers/media/scan/ModernMediaScanner.java +index fe0e5cf78..f8f29fb4e 100644 +--- a/src/com/android/providers/media/scan/ModernMediaScanner.java ++++ b/src/com/android/providers/media/scan/ModernMediaScanner.java +@@ -39,6 +39,8 @@ import static android.provider.MediaStore.UNKNOWN_STRING; + import static android.text.format.DateUtils.HOUR_IN_MILLIS; + import static android.text.format.DateUtils.MINUTE_IN_MILLIS; + ++import static java.util.Objects.requireNonNull; ++ + import android.annotation.CurrentTimeMillisLong; + import android.annotation.CurrentTimeSecondsLong; + import android.annotation.NonNull; +@@ -161,7 +163,15 @@ public class ModernMediaScanner implements MediaScanner { + } + + @Override +- public void scanDirectory(File file) { ++ public void scanDirectory(@NonNull File file) { ++ requireNonNull(file); ++ try { ++ file = file.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize directory to scan" + file, e); ++ return; ++ } ++ + try (Scan scan = new Scan(file)) { + scan.run(); + } catch (OperationCanceledException ignored) { +@@ -169,7 +179,16 @@ public class ModernMediaScanner implements MediaScanner { + } + + @Override +- public Uri scanFile(File file) { ++ @Nullable ++ public Uri scanFile(@NonNull File file) { ++ requireNonNull(file); ++ try { ++ file = file.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize file to scan" + file, e); ++ return null; ++ } ++ + try (Scan scan = new Scan(file)) { + scan.run(); + return scan.mFirstResult; diff --git a/Patches/LineageOS-17.1/android_packages_providers_TelephonyProvider/373957.patch b/Patches/LineageOS-17.1/android_packages_providers_TelephonyProvider/373957.patch new file mode 100644 index 00000000..d61f8c6c --- /dev/null +++ b/Patches/LineageOS-17.1/android_packages_providers_TelephonyProvider/373957.patch @@ -0,0 +1,818 @@ +From 0000000000000000000000000000000000000000 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:950a7e5a4bf1b38e846fe00642105479efded57d) +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 7546c246..9f58fc33 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; +@@ -34,6 +35,7 @@ import android.os.Binder; + import android.os.FileUtils; + 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; +@@ -50,6 +52,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; + +@@ -94,6 +98,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 +@@ -307,6 +321,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; +@@ -622,6 +644,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); +@@ -774,6 +804,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 +@@ -1062,7 +1100,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 afde117a..13abc8fc 100644 +--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java ++++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java +@@ -721,79 +721,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 dbf85aed..9877a44a 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 +@@ -1226,6 +1238,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; +@@ -1282,6 +1302,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); + +@@ -1298,6 +1326,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 1213c379..85a224bd 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; +@@ -113,6 +114,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 +@@ -468,6 +479,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; +@@ -656,6 +675,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); +@@ -758,6 +785,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 00000000..e1010e01 +--- /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 00000000..cea411be +--- /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 2bc5f0f1..f86fcd34 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); diff --git a/Patches/LineageOS-17.1/android_packages_services_BuiltInPrintService/373958.patch b/Patches/LineageOS-17.1/android_packages_services_BuiltInPrintService/373958.patch new file mode 100644 index 00000000..0d06fabe --- /dev/null +++ b/Patches/LineageOS-17.1/android_packages_services_BuiltInPrintService/373958.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glade Diviney +Date: Sun, 22 Nov 2020 17:42:27 -0800 +Subject: [PATCH] Adjust APIs for CUPS 2.3.3 + +Bug: 168903843 +Test: Build the code, flash the device and run fuzzer +Test: Perform a print job +Signed-off-by: Glade Diviney +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:78aedf410610768bdfd8f6c87a704e82a4fd1526) +Merged-In: I0000b0950bf38e0b09e47a4bdf970b0e2b2684d1 +Change-Id: I0000b0950bf38e0b09e47a4bdf970b0e2b2684d1 +--- + jni/include/lib_wprint.h | 2 ++ + jni/ipphelper/ipp_print.c | 15 ++++++++------- + jni/ipphelper/ipphelper.c | 14 ++++++++------ + 3 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/jni/include/lib_wprint.h b/jni/include/lib_wprint.h +index 0d2fd12..57cf9f3 100644 +--- a/jni/include/lib_wprint.h ++++ b/jni/include/lib_wprint.h +@@ -53,6 +53,8 @@ + #define MAX_ID_STRING_LENGTH (64) + #define MAX_NAME_LENGTH (255) + ++#define HTTP_TIMEOUT_MILLIS 30000 ++ + #ifdef __cplusplus + extern "C" + { +diff --git a/jni/ipphelper/ipp_print.c b/jni/ipphelper/ipp_print.c +index 36b7015..8ea4a20 100644 +--- a/jni/ipphelper/ipp_print.c ++++ b/jni/ipphelper/ipp_print.c +@@ -98,17 +98,20 @@ static status_t _init(const ifc_print_job_t *this_p, const char *printer_address + ipp_scheme = (use_secure_uri) ? IPPS_PREFIX : IPP_PREFIX; + + httpAssembleURIf(HTTP_URI_CODING_ALL, ipp_job->printer_uri, sizeof(ipp_job->printer_uri), +- ipp_scheme, NULL, printer_address, ippPortNumber, printer_uri); ++ ipp_scheme, NULL, printer_address, ippPortNumber, "%s", printer_uri); + getResourceFromURI(ipp_job->printer_uri, ipp_job->http_resource, 1024); + if (use_secure_uri) { +- ipp_job->http = httpConnectEncrypt(printer_address, ippPortNumber, HTTP_ENCRYPTION_ALWAYS); ++ ipp_job->http = httpConnect2(printer_address, ippPortNumber, NULL, AF_UNSPEC, ++ HTTP_ENCRYPTION_ALWAYS, 1, HTTP_TIMEOUT_MILLIS, NULL); + + // If ALWAYS doesn't work, fall back to REQUIRED + if (ipp_job->http == NULL) { +- ipp_job->http = httpConnectEncrypt(printer_address, ippPortNumber, HTTP_ENCRYPT_REQUIRED); ++ ipp_job->http = httpConnect2(printer_address, ippPortNumber, NULL, AF_UNSPEC, ++ HTTP_ENCRYPTION_REQUIRED, 1, HTTP_TIMEOUT_MILLIS, NULL); + } + } else { +- ipp_job->http = httpConnectEncrypt(printer_address, ippPortNumber, HTTP_ENCRYPTION_IF_REQUESTED); ++ ipp_job->http = httpConnect2(printer_address, ippPortNumber, NULL, AF_UNSPEC, ++ HTTP_ENCRYPTION_IF_REQUESTED, 1, HTTP_TIMEOUT_MILLIS, NULL); + } + + httpSetTimeout(ipp_job->http, DEFAULT_IPP_TIMEOUT, NULL, 0); +@@ -514,8 +517,6 @@ static status_t _start_job(const ifc_print_job_t *this_p, const wprint_job_param + ippDelete(request); + continue; + } +- +- _cupsSetHTTPError(ipp_job->status); + } + ippDelete(request); + LOGI("_start_job httpPrint fd %d status %d ipp_status %d", ipp_job->http->fd, +@@ -615,4 +616,4 @@ static status_t _end_job(const ifc_print_job_t *this_p) { + LOGD("_end_job: exit status %d job_id %d", ipp_job->status, job_id); + + return result; +-} +\ No newline at end of file ++} +diff --git a/jni/ipphelper/ipphelper.c b/jni/ipphelper/ipphelper.c +index 8b7f00d..27a4090 100644 +--- a/jni/ipphelper/ipphelper.c ++++ b/jni/ipphelper/ipphelper.c +@@ -1198,19 +1198,22 @@ http_t *ipp_cups_connect(const wprint_connect_info_t *connect_info, char *printe + int ippPortNumber = ((connect_info->port_num == IPP_PORT) ? ippPort() : connect_info->port_num); + + if (strstr(connect_info->uri_scheme,IPPS_PREFIX) != NULL) { +- curl_http = httpConnectEncrypt(connect_info->printer_addr, ippPortNumber, HTTP_ENCRYPTION_ALWAYS); ++ curl_http = httpConnect2(connect_info->printer_addr, ippPortNumber, NULL, AF_UNSPEC, ++ HTTP_ENCRYPTION_ALWAYS, 1, HTTP_TIMEOUT_MILLIS, NULL); + + // If ALWAYS doesn't work, fall back to REQUIRED + if (curl_http == NULL) { +- curl_http = httpConnectEncrypt(connect_info->printer_addr, ippPortNumber, HTTP_ENCRYPT_REQUIRED); ++ curl_http = httpConnect2(connect_info->printer_addr, ippPortNumber, NULL, AF_UNSPEC, ++ HTTP_ENCRYPTION_REQUIRED, 1, HTTP_TIMEOUT_MILLIS, NULL); + } + } else { +- curl_http = httpConnectEncrypt(connect_info->printer_addr, ippPortNumber, HTTP_ENCRYPTION_IF_REQUESTED); ++ curl_http = httpConnect2(connect_info->printer_addr, ippPortNumber, NULL, AF_UNSPEC, ++ HTTP_ENCRYPTION_IF_REQUESTED, 1, HTTP_TIMEOUT_MILLIS, NULL); + } + + httpSetTimeout(curl_http, (double)connect_info->timeout / 1000, NULL, 0); + httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, uriLength, connect_info->uri_scheme, NULL, +- connect_info->printer_addr, ippPortNumber, uri_path); ++ connect_info->printer_addr, ippPortNumber, "%s", uri_path); + + if (curl_http == NULL) { + LOGD("ipp_cups_connect failed addr=%s port=%d", connect_info->printer_addr, ippPortNumber); +@@ -1242,7 +1245,6 @@ static ipp_t *ippSendRequest(http_t *http, ipp_t *request, char *resource) { + LOGD("ippSendRequest: (Continue with NULL response) Retry"); + retry = true; + } else if (result == HTTP_ERROR || result >= HTTP_BAD_REQUEST) { +- _cupsSetHTTPError(result); + break; + } + +@@ -1345,4 +1347,4 @@ ipp_t *ipp_doCupsRequest(http_t *http, ipp_t *request, char *http_resource, char + } while (1); + + return response; +-} +\ No newline at end of file ++} diff --git a/Scripts/LineageOS-17.1/Patch.sh b/Scripts/LineageOS-17.1/Patch.sh index d05aee0f..66ba3678 100644 --- a/Scripts/LineageOS-17.1/Patch.sh +++ b/Scripts/LineageOS-17.1/Patch.sh @@ -98,7 +98,7 @@ sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aap awk -i inplace '!/updatable_apex.mk/' target/product/mainline_system.mk; #Disable APEX sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_defaults.mk; #Set the minimum supported target SDK to Pie (GrapheneOS) #sed -i 's/PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := true/PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS := false/' core/product_config.mk; #broken by hardenDefconfig -sed -i 's/2023-09-05/2023-10-05/' core/version_defaults.mk; #Bump Security String #Q_asb_2023-10 #XXX +sed -i 's/2023-09-05/2023-11-05/' core/version_defaults.mk; #Bump Security String #Q_asb_2023-11 #XXX fi; if enterAndClear "build/soong"; then @@ -126,10 +126,19 @@ applyPatch "$DOS_PATCHES/android_external_hardened_malloc/0001-Broken_Cameras.pa fi; fi; +if enterAndClear "external/libcups"; then +git fetch https://github.com/LineageOS/android_external_libcups refs/changes/46/373946/1 && git cherry-pick FETCH_HEAD; #R_asb_2023-11 Upgrade libcups to v2.3.1 +git fetch https://github.com/LineageOS/android_external_libcups refs/changes/47/373947/1 && git cherry-pick FETCH_HEAD; #R_asb_2023-11 Upgrade libcups to v2.3.3 +fi; + if enterAndClear "external/libvpx"; then applyPatch "$DOS_PATCHES_COMMON/android_external_libvpx/CVE-2023-5217.patch"; #VP8: disallow thread count changes fi; +if enterAndClear "external/webp"; then +applyPatch "$DOS_PATCHES_COMMON/android_external_webp/373948.patch"; #R_asb_2023-11 Update to v1.1.0-8-g50f60add +fi; + if enterAndClear "external/libxml2"; then applyPatch "$DOS_PATCHES/android_external_libxml2/368053.patch"; #R_asb_2023-10 malloc-fail: Fix OOB read after xmlRegGetCounter fi; @@ -145,6 +154,11 @@ if enterAndClear "external/zlib"; then git fetch https://github.com/LineageOS/android_external_zlib refs/changes/70/352570/1 && git cherry-pick FETCH_HEAD; #Q_asb_2023-03 fi; +if enterAndClear "frameworks/av"; then +applyPatch "$DOS_PATCHES/android_frameworks_av/373949.patch"; #R_asb_2023-11 Fix for heap buffer overflow issue flagged by fuzzer test. +applyPatch "$DOS_PATCHES/android_frameworks_av/373950.patch"; #R_asb_2023-11 Fix heap-use-after-free issue flagged by fuzzer test. +fi; + if enterAndClear "frameworks/base"; then applyPatch "$DOS_PATCHES/android_frameworks_base/368055.patch"; #R_asb_2023-10 RingtoneManager: verify default ringtone is audio applyPatch "$DOS_PATCHES/android_frameworks_base/368059.patch"; #R_asb_2023-10 Do not share key mappings with JNI object @@ -154,6 +168,11 @@ applyPatch "$DOS_PATCHES/android_frameworks_base/368062-backport.patch"; #R_asb_ applyPatch "$DOS_PATCHES/android_frameworks_base/368063.patch"; #R_asb_2023-10 Fixing DatabaseUtils to detect malformed UTF-16 strings #applyPatch "$DOS_PATCHES/android_frameworks_base/368065-backport.patch"; #R_asb_2023-10 SettingsProvider: exclude secure_frp_mode from resets applyPatch "$DOS_PATCHES/android_frameworks_base/368067.patch"; #R_asb_2023-10 Revert "DO NOT MERGE Dismiss keyguard when simpin auth'd and..." +applyPatch "$DOS_PATCHES/android_frameworks_base/373951.patch"; #R_asb_2023-11 Fix BAL via notification.publicVersion +applyPatch "$DOS_PATCHES/android_frameworks_base/373952.patch"; #R_asb_2023-11 Check caller's uid in backupAgentCreated callback +applyPatch "$DOS_PATCHES/android_frameworks_base/373953.patch"; #R_asb_2023-11 Use type safe API of readParcelableArray +applyPatch "$DOS_PATCHES/android_frameworks_base/373954-backport.patch"; #R_asb_2023-11 Make log reader thread a class member +applyPatch "$DOS_PATCHES/android_frameworks_base/373955.patch"; #R_asb_2023-11 [SettingsProvider] verify ringtone URI before setting #applyPatch "$DOS_PATCHES/android_frameworks_base/272645.patch"; #ten-bt-sbc-hd-dualchannel: Add CHANNEL_MODE_DUAL_CHANNEL constant (ValdikSS) #applyPatch "$DOS_PATCHES/android_frameworks_base/272646-forwardport.patch"; #ten-bt-sbc-hd-dualchannel: Add Dual Channel into Bluetooth Audio Channel Mode developer options menu (ValdikSS) #applyPatch "$DOS_PATCHES/android_frameworks_base/272647.patch"; #ten-bt-sbc-hd-dualchannel: Allow SBC as HD audio codec in Bluetooth device configuration (ValdikSS) @@ -380,9 +399,18 @@ if enterAndClear "packages/providers/DownloadProvider"; then applyPatch "$DOS_PATCHES/android_packages_providers_DownloadProvider/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS) fi; -#if enterAndClear "packages/providers/TelephonyProvider"; then +if enterAndClear "packages/providers/MediaProvider"; then +applyPatch "$DOS_PATCHES/android_packages_providers_MediaProvider/368071.patch"; #R_asb_2023-10 Fix path traversal vulnerabilities in MediaProvider +fi; + +if enterAndClear "packages/providers/TelephonyProvider"; then +applyPatch "$DOS_PATCHES/android_packages_providers_TelephonyProvider/373957.patch"; #R_asb_2023-11 Block access to sms/mms db from work profile. #cp $DOS_PATCHES_COMMON/android_packages_providers_TelephonyProvider/carrier_list.* assets/; -#fi; +fi; + +if enterAndClear "packages/services/BuiltInPrintService"; then +applyPatch "$DOS_PATCHES/android_packages_services_BuiltInPrintService/373958.patch"; #R_asb_2023-11 Adjust APIs for CUPS 2.3.3 +fi; if enterAndClear "packages/services/Telecomm"; then applyPatch "$DOS_PATCHES/android_packages_services_Telecomm/368072.patch"; #R_asb_2023-10 Fix vulnerability in CallRedirectionService.