- 14.1: more ffmpeg patches from @syphyr
- 16.0: switch to @MSe1969's patchsets, gains 3 libcups related fixes

Signed-off-by: Tad <tad@spotco.us>
This commit is contained in:
Tad 2023-12-03 19:08:47 -05:00
parent 5d794c1a3a
commit 5c99bc4098
No known key found for this signature in database
GPG Key ID: B286E9F57A07424B
17 changed files with 3 additions and 1693 deletions

View File

@ -81,7 +81,7 @@
<remove-project name="LineageOS/android_external_boringssl" />
<project path="external/boringssl" name="syphyr/android_external_boringssl" remote="github" revision="f8397314565d6441b52f5aa313d06a98a03c31cd" />
<remove-project name="LineageOS/android_external_ffmpeg" />
<project path="external/ffmpeg" name="syphyr/android_external_ffmpeg" remote="github" revision="db17b279a8b4e26c8f5087f266b467b3fdc3c146" />
<project path="external/ffmpeg" name="syphyr/android_external_ffmpeg" remote="github" revision="d78de94d18756b74b97509e581097014efbbbca8" />
<remove-project name="LineageOS/android_external_flac" />
<project path="external/flac" name="syphyr/android_external_flac" remote="github" revision="3c73deb884acf79764a769cac47a12d214929fa5" />
<!-- END OF ADDITIONAL REPOS -->

View File

@ -1,79 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shruti Bihani <shrutibihani@google.com>
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 3dd4248e4c..917967cf17 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 {

View File

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shruti Bihani <shrutibihani@google.com>
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 f25fc71752..60af36457b 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -294,6 +294,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();
@@ -660,6 +664,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;
@@ -671,6 +680,11 @@ void MtpFfsHandle::doSendEvent(mtp_event me) {
if (static_cast<unsigned>(ret) != length)
PLOG(ERROR) << "Mtp error sending event thread!";
delete[] reinterpret_cast<char*>(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<int> child_threads{0};
+
android::base::unique_fd mControl;
// "in" from the host's perspective => sink for mtp server
android::base::unique_fd mBulkIn;

View File

@ -1,60 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jean-Michel Trivi <jmtrivi@google.com>
Date: Wed, 7 Dec 2022 04:36:46 +0000
Subject: [PATCH] RingtoneManager: verify default ringtone is audio
When a ringtone picker tries to set a ringtone through
RingtoneManager.setActualDefaultRingtoneUri (also
called by com.android.settings.DefaultRingtonePreference),
verify the mimeType can be obtained (not found when caller
doesn't have access to it) and it is an audio resource.
Bug: 205837340
Test: atest android.media.audio.cts.RingtoneManagerTest
(cherry picked from commit 38618f9fb16d3b5617e2289354d47abe5af17dad)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:377144b64325dadad102f5233ecb50a4446b205b)
Merged-In: I3f2c487ded405c0c1a83ef0a2fe99cff7cc9328e
Change-Id: I3f2c487ded405c0c1a83ef0a2fe99cff7cc9328e
---
media/java/android/media/RingtoneManager.java | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index fefa1ede849e..0e03bfb2502a 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -819,10 +819,10 @@ public class RingtoneManager {
return ringtoneUri;
}
-
+
/**
* Sets the {@link Uri} of the default sound for a given sound type.
- *
+ *
* @param context A context used for querying.
* @param type The type whose default sound should be set. One of
* {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
@@ -843,6 +843,21 @@ public class RingtoneManager {
if(!isInternalRingtoneUri(ringtoneUri)) {
ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId());
}
+
+ if (ringtoneUri != null) {
+ final String mimeType = resolver.getType(ringtoneUri);
+ if (mimeType == null) {
+ Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri
+ + " ignored: failure to find mimeType (no access from this context?)");
+ return;
+ }
+ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
+ Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri
+ + " ignored: associated mimeType:" + mimeType + " is not an audio type");
+ return;
+ }
+ }
+
Settings.System.putStringForUser(resolver, setting,
ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Josep del Rio <joseprio@google.com>
Date: Mon, 26 Jun 2023 11:16:37 +0000
Subject: [PATCH] Do not share key mappings with JNI object
The key mapping information between the native key mappings and
the KeyCharacterMap object available in Java is currently shared,
which means that a read can be attempted while it's being modified.
Because the code changed between R and S, this CL fixes it just
for R; the patch for versions S+ is ag/23785419
Bug: 274058082
Test: Presubmit
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4b3c4620166071561ec44961fb08a56676b4fd6c)
Merged-In: I3be94534dcda365da473f82347ae2e3f57bb1b42
Change-Id: I3be94534dcda365da473f82347ae2e3f57bb1b42
---
core/jni/android_view_InputDevice.cpp | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 494fad7900ef..806a88f8f50e 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <binder/Parcel.h>
#include <input/Input.h>
#include <android_runtime/AndroidRuntime.h>
@@ -48,9 +49,16 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
return NULL;
}
+ sp<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
+ if (map != nullptr) {
+ Parcel parcel;
+ map->writeToParcel(&parcel);
+ map = map->readFromParcel(&parcel);
+ }
+
ScopedLocalRef<jobject> kcmObj(env,
- android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
- deviceInfo.getKeyCharacterMap()));
+ android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
+ map));
if (!kcmObj.get()) {
return NULL;
}

View File

@ -1,150 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tim Yu <yunicorn@google.com>
Date: Tue, 20 Jun 2023 21:24:36 +0000
Subject: [PATCH] Verify URI Permissions in Autofill RemoteViews
Check permissions of URI inside of FillResponse's RemoteViews. If the
current user does not have the required permissions to view the URI, the
RemoteView is dropped from displaying.
This fixes a security spill in which a user can view content of another
user through a malicious Autofill provider.
Bug: 283137865
Fixes: b/283264674 b/281666022 b/281665050 b/281848557 b/281533566
b/281534749 b/283101289
Test: Verified by POC app attached in bugs
Test: atest CtsAutoFillServiceTestCases (added new tests)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:26beceb9a252a50374d056b162fa7e8ea55051b3)
Merged-In: I6f4d2a35e89bbed7bd9e07bf5cd3e2d68b20af9a
Change-Id: I6f4d2a35e89bbed7bd9e07bf5cd3e2d68b20af9a
---
.../com/android/server/autofill/Helper.java | 43 +++++++++++++++++++
.../android/server/autofill/ui/FillUi.java | 11 +++--
.../android/server/autofill/ui/SaveUi.java | 2 +-
3 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index f14c8f1aa7f6..a50d87ac81e4 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -18,6 +18,8 @@ package com.android.server.autofill;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.content.ComponentName;
@@ -29,13 +31,16 @@ import android.util.Slog;
import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.widget.RemoteViews;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicBoolean;
public final class Helper {
@@ -79,6 +84,44 @@ public final class Helper {
throw new UnsupportedOperationException("contains static members only");
}
+ private static boolean checkRemoteViewUriPermissions(
+ @UserIdInt int userId, @NonNull RemoteViews rView) {
+ final AtomicBoolean permissionsOk = new AtomicBoolean(true);
+
+ rView.visitUris(uri -> {
+ int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
+ boolean allowed = uriOwnerId == userId;
+ permissionsOk.set(allowed && permissionsOk.get());
+ });
+
+ return permissionsOk.get();
+ }
+
+ /**
+ * Checks the URI permissions of the remote view,
+ * to see if the current userId is able to access it.
+ *
+ * Returns the RemoteView that is passed if user is able, null otherwise.
+ *
+ * TODO: instead of returning a null remoteview when
+ * the current userId cannot access an URI,
+ * return a new RemoteView with the URI removed.
+ */
+ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) {
+ if (rView == null) return null;
+
+ int userId = ActivityManager.getCurrentUser();
+
+ boolean ok = checkRemoteViewUriPermissions(userId, rView);
+ if (!ok) {
+ Slog.w(TAG,
+ "sanitizeRemoteView() user: " + userId
+ + " tried accessing resource that does not belong to them");
+ }
+ return (ok ? rView : null);
+ }
+
+
@Nullable
static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
if (set == null) return null;
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 8119054f4196..cacfcdff686f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -137,8 +137,9 @@ final class FillUi {
mContext = new ContextThemeWrapper(context, THEME_ID);
final LayoutInflater inflater = LayoutInflater.from(mContext);
- final RemoteViews headerPresentation = response.getHeader();
- final RemoteViews footerPresentation = response.getFooter();
+ final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader());
+ final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter());
+
final ViewGroup decor;
if (mFullScreen) {
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null);
@@ -219,6 +220,9 @@ final class FillUi {
ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
final View content;
try {
+ if (Helper.sanitizeRemoteView(response.getPresentation()) == null) {
+ throw new RuntimeException("Permission error accessing RemoteView");
+ }
response.getPresentation().setApplyTheme(THEME_ID);
content = response.getPresentation().apply(mContext, decor, interceptionHandler);
container.addView(content);
@@ -296,7 +300,8 @@ final class FillUi {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- final RemoteViews presentation = dataset.getFieldPresentation(index);
+ final RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldPresentation(index));
if (presentation == null) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
+ "service didn't provide a presentation for it on " + dataset);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 58823036212d..695171e82773 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -269,7 +269,7 @@ final class SaveUi {
final int type = info.getType();
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION, type);
- final RemoteViews template = customDescription.getPresentation();
+ final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation());
if (template == null) {
Slog.w(TAG, "No remote view on custom description");
return false;

View File

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Josep del Rio <joseprio@google.com>
Date: Wed, 12 Jul 2023 16:32:05 +0000
Subject: [PATCH] Fix KCM key mapping cloning
ag/23792288 tried to fix a security issue by cloning the key
mappings, but unfortunately the parcel was not being rewinded.
Bug: 274058082
Test: Confirmed change works in newer Android versions
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:aaaba6cf190d976efdc5db6c78997dbdc9214c15)
Merged-In: I6f75b9202e20d82ebf81a35a2916e653ee1b8372
Change-Id: I6f75b9202e20d82ebf81a35a2916e653ee1b8372
---
core/jni/android_view_InputDevice.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 806a88f8f50e..f36300ada64e 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -53,6 +53,7 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
if (map != nullptr) {
Parcel parcel;
map->writeToParcel(&parcel);
+ parcel.setDataPosition(0);
map = map->readFromParcel(&parcel);
}

View File

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hongwei Wang <hwwang@google.com>
Date: Wed, 24 May 2023 19:35:44 -0700
Subject: [PATCH] Disallow loading icon from content URI to PipMenu
Bug: 278246904
Test: manually, with the PoC app attached to the bug
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5f5a87d8a0dc9190327ba0e6113d5b80ee96abae)
Merged-In: Iecfc1fb962de611cbe3c51a44ba4fded53925a7d
Change-Id: Iecfc1fb962de611cbe3c51a44ba4fded53925a7d
---
.../systemui/pip/phone/PipMenuActivity.java | 17 ++++++++++++-----
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 615b29f93269..214c58a80727 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.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -508,11 +509,17 @@ public class PipMenuActivity extends Activity {
final RemoteAction action = mActions.get(i);
final ImageView actionView = (ImageView) mActionsGroup.getChildAt(i);
- // TODO: Check if the action drawable has changed before we reload it
- action.getIcon().loadDrawableAsync(this, d -> {
- d.setTint(Color.WHITE);
- actionView.setImageDrawable(d);
- }, mHandler);
+ final int iconType = action.getIcon().getType();
+ if (iconType == Icon.TYPE_URI /* || iconType == Icon.TYPE_URI_ADAPTIVE_BITMAP*/) {
+ // Disallow loading icon from content URI
+ actionView.setImageDrawable(null);
+ } else {
+ // TODO: Check if the action drawable has changed before we reload it
+ action.getIcon().loadDrawableAsync(this, d -> {
+ d.setTint(Color.WHITE);
+ actionView.setImageDrawable(d);
+ }, mHandler);
+ }
actionView.setContentDescription(action.getContentDescription());
if (action.isEnabled()) {
actionView.setOnClickListener(v -> {

View File

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kunal Malhotra <malhk@google.com>
Date: Fri, 2 Jun 2023 23:32:02 +0000
Subject: [PATCH] Fixing DatabaseUtils to detect malformed UTF-16 strings
Test: tested with POC in bug, also using atest
Bug: 224771621
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fb4a72e3943d166088407e61aa4439ac349f3f12)
Merged-In: Ide65205b83063801971c5778af3154bcf3f0e530
Change-Id: Ide65205b83063801971c5778af3154bcf3f0e530
---
core/java/android/database/DatabaseUtils.java | 32 +++++++++++++------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 3d019f07cb84..d3ebfea947db 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -337,17 +337,31 @@ public class DatabaseUtils {
*/
public static void appendEscapedSQLString(StringBuilder sb, String sqlString) {
sb.append('\'');
- if (sqlString.indexOf('\'') != -1) {
- int length = sqlString.length();
- for (int i = 0; i < length; i++) {
- char c = sqlString.charAt(i);
- if (c == '\'') {
- sb.append('\'');
+ int length = sqlString.length();
+ for (int i = 0; i < length; i++) {
+ char c = sqlString.charAt(i);
+ if (Character.isHighSurrogate(c)) {
+ if (i == length - 1) {
+ continue;
+ }
+ if (Character.isLowSurrogate(sqlString.charAt(i + 1))) {
+ // add them both
+ sb.append(c);
+ sb.append(sqlString.charAt(i + 1));
+ continue;
+ } else {
+ // this is a lone surrogate, skip it
+ continue;
}
- sb.append(c);
}
- } else
- sb.append(sqlString);
+ if (Character.isLowSurrogate(c)) {
+ continue;
+ }
+ if (c == '\'') {
+ sb.append('\'');
+ }
+ sb.append(c);
+ }
sb.append('\'');
}

View File

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tad <tad@spotco.us>
Date: Mon, 9 Oct 2023 20:41:21 -0400
Subject: [PATCH] Revert "DO NOT MERGE Dismiss keyguard when simpin auth'd
and..."
This reverts commit 9137c0f90ae0fc93afa873e8bf6e1565ac46b9ba.
---
.../src/com/android/keyguard/KeyguardSecurityContainer.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index bb205956e932..6a71cf84759c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -351,7 +351,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
+ if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser())) {
finish = true;
} else {

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nan Wu <wnan@google.com>
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 b2daecc659cc..d456e3d57039 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2860,8 +2860,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 ca0ec012fb60..a1e8cd15fd7e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2702,7 +2702,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(),

View File

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kumarashishg <kumarashishg@google.com>
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 6ce420191ed3..34f5c9d0602f 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;

View File

@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Songchun Fan <schfan@google.com>
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 8e8ee46b8488..b65b612ecad5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1497,6 +1497,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();
@@ -1529,6 +1532,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)

View File

@ -1,136 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Weng Su <wengsu@google.com>
Date: Fri, 7 Jul 2023 19:52:04 +0800
Subject: [PATCH] Restrict ApnEditor settings
- Finish ApnEditor settings if user is not an admin
- Finish ApnEditor settings if user has DISALLOW_CONFIG_MOBILE_NETWORKS restriction
Bug: 279902472
Test: manual test
make RunSettingsRoboTests ROBOTEST_FILTER=ApnEditorTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5c2d727b8f9198bf758a4896eda7c9e5385435ff)
Merged-In: Iecdbbff7e21dfb11e3ba385858747a220cfd3e04
Change-Id: Iecdbbff7e21dfb11e3ba385858747a220cfd3e04
---
.../android/settings/network/ApnEditor.java | 23 ++++++++++++++
.../settings/network/ApnEditorTest.java | 31 ++++++++++++++++++-
2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java
index cceb31d29e7..74a7fed07fc 100644
--- a/src/com/android/settings/network/ApnEditor.java
+++ b/src/com/android/settings/network/ApnEditor.java
@@ -27,6 +27,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.UserManager;
import android.provider.Telephony;
import android.support.annotation.VisibleForTesting;
import android.support.v14.preference.MultiSelectListPreference;
@@ -203,6 +204,11 @@ public class ApnEditor extends SettingsPreferenceFragment
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ if (isUserRestricted()) {
+ Log.e(TAG, "This setting isn't available due to user restriction.");
+ finish();
+ return;
+ }
addPreferencesFromResource(R.xml.apn_editor);
@@ -1166,6 +1172,23 @@ public class ApnEditor extends SettingsPreferenceFragment
return userEnteredApnType;
}
+ @VisibleForTesting
+ boolean isUserRestricted() {
+ UserManager userManager = getContext().getSystemService(UserManager.class);
+ if (userManager == null) {
+ return false;
+ }
+ if (!userManager.isAdminUser()) {
+ Log.e(TAG, "User is not an admin");
+ return true;
+ }
+ if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
+ Log.e(TAG, "User is not allowed to configure mobile network");
+ return true;
+ }
+ return false;
+ }
+
public static class ErrorDialog extends InstrumentedDialogFragment {
public static void showError(ApnEditor editor) {
diff --git a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
index 35f68a06698..ed82b59be5b 100644
--- a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
+++ b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
@@ -32,6 +32,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
+import android.os.UserManager;
import android.support.v14.preference.MultiSelectListPreference;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.EditTextPreference;
@@ -97,6 +98,8 @@ public class ApnEditorTest {
private ApnEditor mApnEditorUT;
private Activity mActivity;
+ @Mock
+ private UserManager mUserManager;
private Resources mResources;
@Before
@@ -111,6 +114,11 @@ public class ApnEditorTest {
doNothing().when(mApnEditorUT).finish();
doNothing().when(mApnEditorUT).showError();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(true).when(mUserManager).isAdminUser();
+ doReturn(false).when(mUserManager)
+ .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+
setMockPreference(mActivity);
mApnEditorUT.mApnData = new FakeApnData(APN_DATA);
mApnEditorUT.sNotSet = "Not Set";
@@ -447,6 +455,27 @@ public class ApnEditorTest {
assertThat(ApnEditor.formatInteger("not an int")).isEqualTo("not an int");
}
+ @Test
+ @Config(shadows = ShadowFragment.class)
+ public void onCreate_notAdminUser_shouldFinish() {
+ doReturn(false).when(mUserManager).isAdminUser();
+
+ mApnEditorUT.onCreate(null);
+
+ verify(mApnEditorUT).finish();
+ }
+
+ @Test
+ @Config(shadows = ShadowFragment.class)
+ public void onCreate_hasUserRestriction_shouldFinish() {
+ doReturn(true).when(mUserManager)
+ .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+
+ mApnEditorUT.onCreate(null);
+
+ verify(mApnEditorUT).finish();
+ }
+
private void initCursor() {
doReturn(2).when(mCursor).getColumnCount();
doReturn(Integer.valueOf(2)).when(mCursor).getInt(CURSOR_INTEGER_INDEX);
@@ -489,4 +518,4 @@ public class ApnEditorTest {
mUri = uri;
}
}
-}
\ No newline at end of file
+}

View File

@ -1,817 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aishwarya Mallampati <amallampati@google.com>
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 738963ed..3d765333 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -708,78 +708,96 @@ 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);";
+
private 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 1653cd98..ce83d679 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
@@ -1216,6 +1228,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;
@@ -1272,6 +1292,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;
+ }
+
if (URI_MATCHER.match(uri) == URI_PENDING_MSG) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(TABLE_PENDING_MSG, null, values);
@@ -1283,6 +1311,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 2b40d7eb..986c93a1 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
@@ -458,6 +469,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;
@@ -651,6 +670,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);
@@ -753,6 +780,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 ba632039..13d9ae98 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);

View File

@ -93,6 +93,8 @@ patchWorkspaceReal() {
repopick -fit P_asb_2023-07 -e 361282;
repopick -fit P_asb_2023-08 -e 365327,365328,364605;
repopick -fit P_asb_2023-09;
repopick -fit P_asb_2023-10 -e 370704;
repopick -fit P_asb_2023-11 -e 374916;
sh "$DOS_SCRIPTS/Patch.sh";
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";

View File

@ -165,22 +165,10 @@ awk -i inplace '!/deletePackage/' pico/src/com/svox/pico/LangPackUninstaller.jav
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. #XXX: error: use of class template 'std::unique_lock' requires template arguments
if [ "$DOS_GRAPHENE_MALLOC" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_av/0001-HM-No_RLIMIT_AS.patch"; fi; #(GrapheneOS)
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
applyPatch "$DOS_PATCHES/android_frameworks_base/368060-backport.patch"; #R_asb_2023-10 Verify URI Permissions in Autofill RemoteViews
applyPatch "$DOS_PATCHES/android_frameworks_base/368061.patch"; #R_asb_2023-10 Fix KCM key mapping cloning
applyPatch "$DOS_PATCHES/android_frameworks_base/368062-backport.patch"; #R_asb_2023-10 Disallow loading icon from content URI to PipMenu
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/368067-backport.patch"; #R_asb_2023-10 Revert "DO NOT MERGE Dismiss keyguard when simpin auth'd and..."
applyPatch "$DOS_PATCHES/android_frameworks_base/373951-backport.patch"; #R_asb_2023-11 Fix BAL via notification.publicVersion
applyPatch "$DOS_PATCHES/android_frameworks_base/373953.patch"; #R_asb_2023-11 Use type safe API of readParcelableArray
applyPatch "$DOS_PATCHES/android_frameworks_base/373955.patch"; #R_asb_2023-11 [SettingsProvider] verify ringtone URI before setting
applyPatch "$DOS_PATCHES/android_frameworks_base/0007-Always_Restict_Serial.patch"; #Always restrict access to Build.SERIAL (GrapheneOS)
applyPatch "$DOS_PATCHES/android_frameworks_base/0008-Browser_No_Location.patch"; #Don't grant location permission to system browsers (GrapheneOS)
applyPatch "$DOS_PATCHES/android_frameworks_base/0009-SystemUI_No_Permission_Review.patch"; #Allow SystemUI to directly manage Bluetooth/WiFi (GrapheneOS)
@ -332,7 +320,6 @@ fi;
if enterAndClear "packages/apps/Settings"; then
git revert --no-edit c240992b4c86c7f226290807a2f41f2619e7e5e8; #Don't hide OEM unlock
applyPatch "$DOS_PATCHES/android_packages_apps_Settings/368069-backport.patch"; #R_asb_2023-10 Restrict ApnEditor settings
applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0001-Captive_Portal_Toggle.patch"; #Add option to disable captive portal checks (MSe1969)
#applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0004-Private_DNS.patch"; #More 'Private DNS' options (heavily based off of a CalyxOS patch) #TODO: Needs work
#applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0005-Automatic_Reboot.patch"; #Timeout for reboot (GrapheneOS)
@ -370,7 +357,6 @@ applyPatch "$DOS_PATCHES/android_packages_providers_DownloadProvider/0001-Networ
fi;
if enterAndClear "packages/providers/TelephonyProvider"; then
applyPatch "$DOS_PATCHES/android_packages_providers_TelephonyProvider/373957-backport.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;