Signed-off-by: Tad <tad@spotco.us>
This commit is contained in:
Tad 2023-09-18 15:15:47 -04:00
parent 337ae6012d
commit 724b742b64
No known key found for this signature in database
GPG Key ID: B286E9F57A07424B
32 changed files with 20 additions and 2552 deletions

View File

@ -21,10 +21,10 @@ Change-Id: I907877608f4672f24c002e630e58bf9133937a5e
1 file changed, 10 insertions(+), 11 deletions(-) 1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index dca49738c..2650a307a 100644 index 014240888..203808806 100644
--- a/stack/gatt/gatt_cl.cc --- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc +++ b/stack/gatt/gatt_cl.cc
@@ -297,7 +297,7 @@ void gatt_send_queue_write_cancel(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -291,7 +291,7 @@ void gatt_send_queue_write_cancel(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
bool gatt_check_write_long_terminate(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool gatt_check_write_long_terminate(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
tGATT_VALUE* p_rsp_value) { tGATT_VALUE* p_rsp_value) {
tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf; tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
@ -33,7 +33,7 @@ index dca49738c..2650a307a 100644
tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC; tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
VLOG(1) << __func__; VLOG(1) << __func__;
@@ -310,19 +310,18 @@ bool gatt_check_write_long_terminate(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -304,19 +304,18 @@ bool gatt_check_write_long_terminate(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
/* data does not match */ /* data does not match */
p_clcb->status = GATT_ERROR; p_clcb->status = GATT_ERROR;
flag = GATT_PREP_WRITE_CANCEL; flag = GATT_PREP_WRITE_CANCEL;
@ -57,7 +57,7 @@ index dca49738c..2650a307a 100644
} }
/** Send prepare write */ /** Send prepare write */
@@ -586,15 +585,15 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -583,15 +582,15 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
memcpy(value.value, p, value.len); memcpy(value.value, p, value.len);

View File

@ -20,10 +20,10 @@ Change-Id: I085ecfa1a9ba098ecbfecbd3cb3e263ae13f9724
1 file changed, 6 insertions(+), 1 deletion(-) 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index db41c5f9f..f7f11b7a9 100644 index 203808806..49ccc7e52 100644
--- a/stack/gatt/gatt_cl.cc --- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc +++ b/stack/gatt/gatt_cl.cc
@@ -586,12 +586,17 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -582,12 +582,17 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
memcpy(value.value, p, value.len); memcpy(value.value, p, value.len);

View File

@ -21,7 +21,7 @@ Change-Id: I907877608f4672f24c002e630e58bf9133937a5e
1 file changed, 10 insertions(+), 11 deletions(-) 1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index dca49738c..2650a307a 100644 index f8d5bab92..16a7171f6 100644
--- a/stack/gatt/gatt_cl.cc --- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc +++ b/stack/gatt/gatt_cl.cc
@@ -297,7 +297,7 @@ void gatt_send_queue_write_cancel(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -297,7 +297,7 @@ void gatt_send_queue_write_cancel(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
@ -57,7 +57,7 @@ index dca49738c..2650a307a 100644
} }
/** Send prepare write */ /** Send prepare write */
@@ -586,15 +585,15 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -587,15 +586,15 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
memcpy(value.value, p, value.len); memcpy(value.value, p, value.len);

View File

@ -20,7 +20,7 @@ Change-Id: I085ecfa1a9ba098ecbfecbd3cb3e263ae13f9724
1 file changed, 6 insertions(+), 1 deletion(-) 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index db41c5f9f..f7f11b7a9 100644 index 16a7171f6..5e4837020 100644
--- a/stack/gatt/gatt_cl.cc --- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc +++ b/stack/gatt/gatt_cl.cc
@@ -586,12 +586,17 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, @@ -586,12 +586,17 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,

View File

@ -1,4 +1,4 @@
From 50f60add5c547b8c9bc4462bd2fc2840d8fc4525 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vincent Rabaud <vrabaud@google.com> From: Vincent Rabaud <vrabaud@google.com>
Date: Thu, 7 Sep 2023 21:16:03 +0200 Date: Thu, 7 Sep 2023 21:16:03 +0200
Subject: [PATCH] Fix OOB write in BuildHuffmanTable. Subject: [PATCH] Fix OOB write in BuildHuffmanTable.
@ -21,7 +21,7 @@ Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
4 files changed, 129 insertions(+), 43 deletions(-) 4 files changed, 129 insertions(+), 43 deletions(-)
diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c
index 93615d4ed2..0d38314db8 100644 index 93615d4e..0d38314d 100644
--- a/src/dec/vp8l_dec.c --- a/src/dec/vp8l_dec.c
+++ b/src/dec/vp8l_dec.c +++ b/src/dec/vp8l_dec.c
@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths( @@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
@ -169,7 +169,7 @@ index 93615d4ed2..0d38314db8 100644
assert(dec->hdr_.num_htree_groups_ > 0); assert(dec->hdr_.num_htree_groups_ > 0);
diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h
index 72b2e86120..32540a4b88 100644 index 72b2e861..32540a4b 100644
--- a/src/dec/vp8li_dec.h --- a/src/dec/vp8li_dec.h
+++ b/src/dec/vp8li_dec.h +++ b/src/dec/vp8li_dec.h
@@ -51,7 +51,7 @@ typedef struct { @@ -51,7 +51,7 @@ typedef struct {
@ -182,7 +182,7 @@ index 72b2e86120..32540a4b88 100644
typedef struct VP8LDecoder VP8LDecoder; typedef struct VP8LDecoder VP8LDecoder;
diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c
index 0cba0fbb7d..9efd6283ac 100644 index 0cba0fbb..9efd6283 100644
--- a/src/utils/huffman_utils.c --- a/src/utils/huffman_utils.c
+++ b/src/utils/huffman_utils.c +++ b/src/utils/huffman_utils.c
@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, @@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
@ -313,7 +313,7 @@ index 0cba0fbb7d..9efd6283ac 100644
+ } + }
+} +}
diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h
index 13b7ad1ac4..98415c5328 100644 index 13b7ad1a..98415c53 100644
--- a/src/utils/huffman_utils.h --- a/src/utils/huffman_utils.h
+++ b/src/utils/huffman_utils.h +++ b/src/utils/huffman_utils.h
@@ -43,6 +43,29 @@ typedef struct { @@ -43,6 +43,29 @@ typedef struct {

View File

@ -1,4 +1,4 @@
From 20ceff7eb3ccb679bd299f3d481309e10cbf2616 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vincent Rabaud <vrabaud@google.com> From: Vincent Rabaud <vrabaud@google.com>
Date: Thu, 7 Sep 2023 21:16:03 +0200 Date: Thu, 7 Sep 2023 21:16:03 +0200
Subject: [PATCH] Fix OOB write in BuildHuffmanTable. Subject: [PATCH] Fix OOB write in BuildHuffmanTable.
@ -21,7 +21,7 @@ Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
4 files changed, 129 insertions(+), 43 deletions(-) 4 files changed, 129 insertions(+), 43 deletions(-)
diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c
index 2d603b4379..09a0eeccf1 100644 index 2d603b4..09a0eec 100644
--- a/src/dec/vp8l_dec.c --- a/src/dec/vp8l_dec.c
+++ b/src/dec/vp8l_dec.c +++ b/src/dec/vp8l_dec.c
@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths( @@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
@ -169,7 +169,7 @@ index 2d603b4379..09a0eeccf1 100644
assert(dec->hdr_.num_htree_groups_ > 0); assert(dec->hdr_.num_htree_groups_ > 0);
diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h
index 72b2e86120..32540a4b88 100644 index 72b2e86..32540a4 100644
--- a/src/dec/vp8li_dec.h --- a/src/dec/vp8li_dec.h
+++ b/src/dec/vp8li_dec.h +++ b/src/dec/vp8li_dec.h
@@ -51,7 +51,7 @@ typedef struct { @@ -51,7 +51,7 @@ typedef struct {
@ -182,7 +182,7 @@ index 72b2e86120..32540a4b88 100644
typedef struct VP8LDecoder VP8LDecoder; typedef struct VP8LDecoder VP8LDecoder;
diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c
index 0cba0fbb7d..9efd6283ac 100644 index 0cba0fb..9efd628 100644
--- a/src/utils/huffman_utils.c --- a/src/utils/huffman_utils.c
+++ b/src/utils/huffman_utils.c +++ b/src/utils/huffman_utils.c
@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, @@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
@ -313,7 +313,7 @@ index 0cba0fbb7d..9efd6283ac 100644
+ } + }
+} +}
diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h
index 13b7ad1ac4..98415c5328 100644 index 13b7ad1..98415c5 100644
--- a/src/utils/huffman_utils.h --- a/src/utils/huffman_utils.h
+++ b/src/utils/huffman_utils.h +++ b/src/utils/huffman_utils.h
@@ -43,6 +43,29 @@ typedef struct { @@ -43,6 +43,29 @@ typedef struct {

View File

@ -1,32 +0,0 @@
From 00a42241007a2c2a03b97656c958236091553b80 Mon Sep 17 00:00:00 2001
From: Shruti Bihani <shrutibihani@google.com>
Date: Thu, 6 Jul 2023 08:41:56 +0000
Subject: [PATCH] Fix Segv on unknown address error flagged by fuzzer test.
The error is thrown when the destructor tries to free pointer memory.
This is happening for cases where the pointer was not initialized. Initializing it to a default value fixes the error.
Bug: 245135112
Test: Build mtp_host_property_fuzzer and run on the target device
(cherry picked from commit 3afa6e80e8568fe63f893fa354bc79ef91d3dcc0)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:99d0823ca2b8275f000a437150fb8d1938b1b31a)
Merged-In: I255cd68b7641e96ac47ab81479b9b46b78c15580
Change-Id: I255cd68b7641e96ac47ab81479b9b46b78c15580
---
media/mtp/MtpProperty.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h
index 36d736065f..2bdbfd3262 100644
--- a/media/mtp/MtpProperty.h
+++ b/media/mtp/MtpProperty.h
@@ -26,6 +26,9 @@ namespace android {
class MtpDataPacket;
struct MtpPropertyValue {
+ // pointer str initialized to NULL so that free operation
+ // is not called for pre-assigned value
+ MtpPropertyValue() : str (NULL) {}
union {
int8_t i8;
uint8_t u8;

View File

@ -1,41 +0,0 @@
From ce2776f4ca4fba080bd64bffa2c8fa2d0188bd45 Mon Sep 17 00:00:00 2001
From: Hui Peng <phui@google.com>
Date: Thu, 27 Apr 2023 00:50:26 +0000
Subject: [PATCH] Fix a type confusion bug in bta_av_setconfig_rej
tBTA_AV_CI_SETCONFIG is treated as tBTA_AV_STR_MSG
in bta_av_setconfig_rej, resulting OOB access.
Bug: 260230151
Test: manual
Ignore-AOSP-First: security
Tag: #security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bbd88e88ce749aab87178e189a05e5a356d0631c)
Merged-In: I78a1ee50dea0113381e51f8521711d758dc759cf
Change-Id: I78a1ee50dea0113381e51f8521711d758dc759cf
---
system/bta/av/bta_av_aact.cc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index d0db36ea3e..39f95e5040 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -1740,14 +1740,14 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
******************************************************************************/
void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
tBTA_AV_REJECT reject;
- uint8_t avdt_handle = p_data->ci_setconfig.avdt_handle;
- bta_av_adjust_seps_idx(p_scb, avdt_handle);
+ bta_av_adjust_seps_idx(p_scb, p_scb->avdt_handle);
+
LOG_INFO("%s: sep_idx=%d avdt_handle=%d bta_handle=0x%x", __func__,
p_scb->sep_idx, p_scb->avdt_handle, p_scb->hndl);
AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0);
- reject.bd_addr = p_data->str_msg.bd_addr;
+ reject.bd_addr = p_scb->PeerAddress();
reject.hndl = p_scb->hndl;
tBTA_AV bta_av_data;

View File

@ -1,83 +0,0 @@
From 585f583ef5e6c2446df7700d8959774771d2a9d8 Mon Sep 17 00:00:00 2001
From: Hui Peng <phui@google.com>
Date: Thu, 11 May 2023 01:10:04 +0000
Subject: [PATCH] Fix multiple OOB bugs resulted from tx mtu in EATT
The tx mtu in EATT can be controlled by remote device. With malicious
mtu values, it is possible to trigger integer overflow and
OOB write at multiple places (see the bug below).
This fix enforces a max tx mtu in EATT.
Bug: 271335899
Test: manual
Ignore-AOSP-First: security
Tag: #security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ea76b7d99e6366e2043c5621eda630d559104d36)
Merged-In: Ia06c9a17f2daa5ce4c32cffa536777f47774cf31
Change-Id: Ia06c9a17f2daa5ce4c32cffa536777f47774cf31
---
system/stack/eatt/eatt.h | 9 +++++++--
system/stack/eatt/eatt_impl.h | 2 +-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/system/stack/eatt/eatt.h b/system/stack/eatt/eatt.h
index 6ef3d3359a..1310f65480 100644
--- a/system/stack/eatt/eatt.h
+++ b/system/stack/eatt/eatt.h
@@ -17,6 +17,7 @@
#pragma once
+#include <algorithm>
#include <deque>
#include "stack/gatt/gatt_int.h"
@@ -24,6 +25,7 @@
#define EATT_MIN_MTU_MPS (64)
#define EATT_DEFAULT_MTU (256)
+#define EATT_MAX_TX_MTU (1024)
#define EATT_ALL_CIDS (0xFFFF)
namespace bluetooth {
@@ -59,13 +61,13 @@ class EattChannel {
EattChannel(RawAddress& bda, uint16_t cid, uint16_t tx_mtu, uint16_t rx_mtu)
: bda_(bda),
cid_(cid),
- tx_mtu_(tx_mtu),
rx_mtu_(rx_mtu),
state_(EattChannelState::EATT_CHANNEL_PENDING),
indicate_handle_(0),
ind_ack_timer_(NULL),
ind_confirmation_timer_(NULL) {
cl_cmd_q_ = std::deque<tGATT_CMD_Q>();
+ EattChannelSetTxMTU(tx_mtu);
}
~EattChannel() {
@@ -94,7 +96,10 @@ class EattChannel {
}
state_ = state;
}
- void EattChannelSetTxMTU(uint16_t tx_mtu) { this->tx_mtu_ = tx_mtu; }
+
+ void EattChannelSetTxMTU(uint16_t tx_mtu) {
+ this->tx_mtu_ = std::min<uint16_t>(tx_mtu, EATT_MAX_TX_MTU);
+ }
};
/* Interface class */
diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h
index 998fc10905..c5a78550ce 100644
--- a/system/stack/eatt/eatt_impl.h
+++ b/system/stack/eatt/eatt_impl.h
@@ -447,7 +447,7 @@ struct eatt_impl {
if (is_local_cfg)
channel->rx_mtu_ = p_cfg->mtu;
else
- channel->tx_mtu_ = p_cfg->mtu;
+ channel->EattChannelSetTxMTU(p_cfg->mtu);
/* Go back to open state */
channel->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED);

View File

@ -1,37 +0,0 @@
From c9905e7968f603014d8ebd631393f9ba1ffd98c9 Mon Sep 17 00:00:00 2001
From: Hui Peng <phui@google.com>
Date: Wed, 10 May 2023 23:34:20 +0000
Subject: [PATCH] Fix an integer overflow bug in avdt_msg_asmbl
Bug: 280633699
Test: manual
Ignore-AOSP-First: security
Tag: #security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bf9449a704c2983861dbe0ede9ab660e42826179)
Merged-In: Iaa4d603921fc4ffb8cfb5783f99ec0963affd6a2
Change-Id: Iaa4d603921fc4ffb8cfb5783f99ec0963affd6a2
---
system/stack/avdt/avdt_msg.cc | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/system/stack/avdt/avdt_msg.cc b/system/stack/avdt/avdt_msg.cc
index f9f3f7e1e0..0baf5f1f35 100644
--- a/system/stack/avdt/avdt_msg.cc
+++ b/system/stack/avdt/avdt_msg.cc
@@ -1285,14 +1285,14 @@ BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
* NOTE: The buffer is allocated above at the beginning of the
* reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
*/
- uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+ size_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
/* adjust offset and len of fragment for header byte */
p_buf->offset += AVDT_LEN_TYPE_CONT;
p_buf->len -= AVDT_LEN_TYPE_CONT;
/* verify length */
- if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len) {
+ if (((size_t) p_ccb->p_rx_msg->offset + (size_t) p_buf->len) > buf_len) {
/* won't fit; free everything */
AVDT_TRACE_WARNING("%s: Fragmented message too big!", __func__);
osi_free_and_reset((void**)&p_ccb->p_rx_msg);

View File

@ -1,66 +0,0 @@
From c93ec045f59462f2fb64242da1a119a7b49c3d50 Mon Sep 17 00:00:00 2001
From: Brian Delwiche <delwiche@google.com>
Date: Tue, 18 Apr 2023 23:58:50 +0000
Subject: [PATCH] Fix integer overflow in build_read_multi_rsp
Local variables tracking structure size in build_read_multi_rsp are of
uint16 type but accept a full uint16 range from function arguments while
appending a fixed-length offset. This can lead to an integer overflow
and unexpected behavior.
Change the locals to size_t, and add a check during reasssignment.
Bug: 273966636
Test: atest bluetooth_test_gd_unit, net_test_stack_btm
Tag: #security
Ignore-AOSP-First: Security
(cherry picked from commit 70a4d628fa016a9487fae07f211644b95e1f0000)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:badb8ffce06b517cbcfdbfa68cb7b7e02d22494a)
Merged-In: I3a74bdb0d003cb6bf4f282615be8c68836676715
Change-Id: I3a74bdb0d003cb6bf4f282615be8c68836676715
---
system/stack/gatt/gatt_sr.cc | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/system/stack/gatt/gatt_sr.cc b/system/stack/gatt/gatt_sr.cc
index 9f48d830d5..f2a3e22414 100644
--- a/system/stack/gatt/gatt_sr.cc
+++ b/system/stack/gatt/gatt_sr.cc
@@ -142,7 +142,8 @@ void gatt_dequeue_sr_cmd(tGATT_TCB& tcb, uint16_t cid) {
}
static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) {
- uint16_t ii, total_len, len;
+ uint16_t ii;
+ size_t total_len, len;
uint8_t* p;
bool is_overflow = false;
@@ -187,7 +188,7 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) {
len = p_rsp->attr_value.len - (total_len - mtu);
is_overflow = true;
VLOG(1) << StringPrintf(
- "multi read overflow available len=%d val_len=%d", len,
+ "multi read overflow available len=%zu val_len=%d", len,
p_rsp->attr_value.len);
} else {
len = p_rsp->attr_value.len;
@@ -199,9 +200,15 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) {
}
if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) {
- memcpy(p, p_rsp->attr_value.value, len);
- if (!is_overflow) p += len;
- p_buf->len += len;
+ // check for possible integer overflow
+ if (p_buf->len + len <= UINT16_MAX) {
+ memcpy(p, p_rsp->attr_value.value, len);
+ if (!is_overflow) p += len;
+ p_buf->len += len;
+ } else {
+ p_cmd->status = GATT_NOT_FOUND;
+ break;
+ }
} else {
p_cmd->status = GATT_NOT_FOUND;
break;

View File

@ -1,40 +0,0 @@
From 89fb17d17249382f8bd5c4c9b0912447ea7ff676 Mon Sep 17 00:00:00 2001
From: Brian Delwiche <delwiche@google.com>
Date: Wed, 1 Mar 2023 00:22:59 +0000
Subject: [PATCH] Fix potential abort in btu_av_act.cc
Partner analysis shows that bta_av_rc_msg does not respect handling
established for a null browse packet, instead dispatching the null
pointer to bta_av_rc_free_browse_msg. Strictly speaking this does
not cause a UAF, as osi_free_and_reset will find the null and abort,
but it will lead to improper program termination.
Handle the case instead.
Bug: 269253349
Test: atest bluetooth_test_gd_unit
Tag: #security
Ignore-AOSP-First: Security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d3ee136851de30261e56c62fbb488541dc564b94)
Merged-In: I14dc4910476c733b246bcf7ff292afe9b7c0cc3d
Change-Id: I14dc4910476c733b246bcf7ff292afe9b7c0cc3d
---
system/bta/av/bta_av_act.cc | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/system/bta/av/bta_av_act.cc b/system/bta/av/bta_av_act.cc
index be199a4da3..357ca0ecf6 100644
--- a/system/bta/av/bta_av_act.cc
+++ b/system/bta/av/bta_av_act.cc
@@ -1001,7 +1001,10 @@ void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
av.remote_cmd.rc_handle = p_data->rc_msg.handle;
(*p_cb->p_cback)(evt, &av);
/* If browsing message, then free the browse message buffer */
- bta_av_rc_free_browse_msg(p_cb, p_data);
+ if (p_data->rc_msg.opcode == AVRC_OP_BROWSE &&
+ p_data->rc_msg.msg.browse.p_browse_pkt != NULL) {
+ bta_av_rc_free_browse_msg(p_cb, p_data);
+ }
}
}

View File

@ -1,44 +0,0 @@
From 14aed2455e4e800e4bde6175ad3c4910ffcf7b0e Mon Sep 17 00:00:00 2001
From: Brian Delwiche <delwiche@google.com>
Date: Tue, 11 Apr 2023 23:05:45 +0000
Subject: [PATCH] Fix UAF in gatt_cl.cc
gatt_cl.cc accesses a header field after the buffer holding it may have
been freed.
Track the relevant state as a local variable instead.
Bug: 274617156
Test: atest: bluetooth, validated against fuzzer
Tag: #security
Ignore-AOSP-First: Security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:cbaa83627b328eee8f2e26188909a5ebfb0388d5)
Merged-In: I085ecfa1a9ba098ecbfecbd3cb3e263ae13f9724
Change-Id: I085ecfa1a9ba098ecbfecbd3cb3e263ae13f9724
---
system/stack/gatt/gatt_cl.cc | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/system/stack/gatt/gatt_cl.cc b/system/stack/gatt/gatt_cl.cc
index d026633ccd..029e5cba45 100644
--- a/system/stack/gatt/gatt_cl.cc
+++ b/system/stack/gatt/gatt_cl.cc
@@ -609,12 +609,17 @@ void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
memcpy(value.value, p, value.len);
+ bool subtype_is_write_prepare = (p_clcb->op_subtype == GATT_WRITE_PREPARE);
+
if (!gatt_check_write_long_terminate(tcb, p_clcb, &value)) {
gatt_send_prepare_write(tcb, p_clcb);
return;
}
- if (p_clcb->op_subtype == GATT_WRITE_PREPARE) {
+ // We now know that we have not terminated, or else we would have returned
+ // early. We free the buffer only if the subtype is not equal to
+ // GATT_WRITE_PREPARE, so checking here is adequate to prevent UAF.
+ if (subtype_is_write_prepare) {
/* application should verify handle offset
and value are matched or not */
gatt_end_operation(p_clcb, p_clcb->status, &value);

View File

@ -1,37 +0,0 @@
From cd438ebc524bc27b6200c70ccb6ed9f8d0271a10 Mon Sep 17 00:00:00 2001
From: Hui Peng <phui@google.com>
Date: Wed, 19 Jul 2023 18:14:59 +0000
Subject: [PATCH] Revert "Fix a type confusion bug in bta_av_setconfig_rej"
This reverts commit bbd88e88ce749aab87178e189a05e5a356d0631c.
Reason for revert: b/281788858
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c3356f17866099405ef6c01244211af4bd93db2c)
Merged-In: I0f45c87ba5f0b2c84843e568ca117439b42d1ed3
Change-Id: I0f45c87ba5f0b2c84843e568ca117439b42d1ed3
---
system/bta/av/bta_av_aact.cc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index 39f95e5040..d0db36ea3e 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -1740,14 +1740,14 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
******************************************************************************/
void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
tBTA_AV_REJECT reject;
+ uint8_t avdt_handle = p_data->ci_setconfig.avdt_handle;
- bta_av_adjust_seps_idx(p_scb, p_scb->avdt_handle);
-
+ bta_av_adjust_seps_idx(p_scb, avdt_handle);
LOG_INFO("%s: sep_idx=%d avdt_handle=%d bta_handle=0x%x", __func__,
p_scb->sep_idx, p_scb->avdt_handle, p_scb->hndl);
AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0);
- reject.bd_addr = p_scb->PeerAddress();
+ reject.bd_addr = p_data->str_msg.bd_addr;
reject.hndl = p_scb->hndl;
tBTA_AV bta_av_data;

View File

@ -1,85 +0,0 @@
From df4a9362cd39867ca7deee537934649bd6a2589f Mon Sep 17 00:00:00 2001
From: Ioana Alexandru <aioana@google.com>
Date: Mon, 3 Jul 2023 16:29:47 +0000
Subject: [PATCH] DO NOT MERGE Revert "Verify URI permissions for
EXTRA_REMOTE_INPUT_HISTORY_ITEMS."
This reverts commit 43b1711332763788c7abf05c3baa931296c45bbb.
Reason for revert: regression reported at b/289223315
Bug: 289223315
Bug: 276729064
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bdc9b977e376fb3b6047530a179d00fd77f2aec1)
Merged-In: I101938fbc51592537023345ba1e642827510981b
Change-Id: I101938fbc51592537023345ba1e642827510981b
---
core/java/android/app/Notification.java | 11 -----------
.../notification/NotificationManagerServiceTest.java | 11 -----------
2 files changed, 22 deletions(-)
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8a730fb0deaa..6efb83cb3d93 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2857,17 +2857,6 @@ public void visitUris(@NonNull Consumer<Uri> visitor) {
if (person != null) {
visitor.accept(person.getIconUri());
}
-
- final RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- if (history != null) {
- for (int i = 0; i < history.length; i++) {
- RemoteInputHistoryItem item = history[i];
- if (item.getUri() != null) {
- visitor.accept(item.getUri());
- }
- }
- }
}
if (isStyle(MessagingStyle.class) && extras != null) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 2fa14a7c93c6..718d9c50c6b2 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -128,7 +128,6 @@
import android.app.PendingIntent;
import android.app.Person;
import android.app.RemoteInput;
-import android.app.RemoteInputHistoryItem;
import android.app.StatsManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
@@ -5391,12 +5390,6 @@ public void testVisitUris() throws Exception {
.setName("People List Person 2")
.setIcon(personIcon3)
.build();
- final Uri historyUri1 = Uri.parse("content://com.example/history1");
- final Uri historyUri2 = Uri.parse("content://com.example/history2");
- final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1,
- "a");
- final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2,
- "b");
Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents);
@@ -5404,8 +5397,6 @@ public void testVisitUris() throws Exception {
extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1);
extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST,
new ArrayList<>(Arrays.asList(person2, person3)));
- extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
- new RemoteInputHistoryItem[]{historyItem1, historyItem2});
Notification n = new Notification.Builder(mContext, "a")
.setContentTitle("notification with uris")
@@ -5423,8 +5414,6 @@ public void testVisitUris() throws Exception {
verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
- verify(visitor, times(1)).accept(eq(historyUri1));
- verify(visitor, times(1)).accept(eq(historyUri2));
}
@Test

View File

@ -1,45 +0,0 @@
From b55563bb9d534210c3f4c5e21ba07a63360c2094 Mon Sep 17 00:00:00 2001
From: Achim Thesmann <achim@google.com>
Date: Tue, 23 May 2023 00:26:33 +0000
Subject: [PATCH] Ignore virtual presentation windows - RESTRICT AUTOMERGE
Windows of TYPE_PRESENTATION on virtual displays should not be counted
as visible windows to determine if BAL is allowed.
Test: manual test, atest BackgroundActivityLaunchTest
Bug: 264029851, 205130886
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4c40b187cd5277c27d20758c675865bf89180c7a)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5bf9607bec3f1224158cfcff7dd91ac558b46c0f)
Merged-In: I08b16ba1c155e951286ddc22019180cbd6334dfa
Change-Id: I08b16ba1c155e951286ddc22019180cbd6334dfa
---
.../core/java/com/android/server/wm/WindowState.java | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 95fea0ee22f5..66213cc6403d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3596,12 +3596,20 @@ void onSurfaceShownChanged(boolean shown) {
// apps won't always be considered as foreground state.
// Exclude private presentations as they can only be shown on private virtual displays and
// shouldn't be the cause of an app be considered foreground.
- if (mAttrs.type >= FIRST_SYSTEM_WINDOW && mAttrs.type != TYPE_TOAST
- && mAttrs.type != TYPE_PRIVATE_PRESENTATION) {
+ // Exclude presentations on virtual displays as they are not actually visible.
+ if (mAttrs.type >= FIRST_SYSTEM_WINDOW
+ && mAttrs.type != TYPE_TOAST
+ && mAttrs.type != TYPE_PRIVATE_PRESENTATION
+ && !(mAttrs.type == TYPE_PRESENTATION && isOnVirtualDisplay())
+ ) {
mWmService.mAtmService.mActiveUids.onNonAppSurfaceVisibilityChanged(mOwnerUid, shown);
}
}
+ private boolean isOnVirtualDisplay() {
+ return getDisplayContent().mDisplay.getType() == Display.TYPE_VIRTUAL;
+ }
+
private void logExclusionRestrictions(int side) {
if (!logsGestureExclusionRestrictions(this)
|| SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side]

View File

@ -1,140 +0,0 @@
From a80971a28168f2667a2821d008964ba001cad059 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= <matiashe@google.com>
Date: Thu, 15 Jun 2023 18:31:34 +0200
Subject: [PATCH] Forbid granting access to NLSes with too-long component names
This makes the limitation, which was previously only checked on the Settings UI, enforced everywhere.
Fixes: 260570119
Fixes: 286043036
Test: atest + manually
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6fcdbd0c6efc67b014b8e1b43c5ec233f912ee8b)
Merged-In: I4c25d80978cb37a8fa1531f5045259d25ac64692
Change-Id: I4c25d80978cb37a8fa1531f5045259d25ac64692
---
.../java/android/app/NotificationManager.java | 6 +++++
.../RestrictedSwitchPreference.java | 8 ++++--
.../NotificationManagerService.java | 5 ++++
.../android/server/vr/VrManagerService.java | 6 ++++-
.../NotificationManagerServiceTest.java | 25 +++++++++++++++++++
5 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 3506c41310a3..2807b0b4b682 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -575,6 +575,12 @@ public class NotificationManager {
*/
public static final int BUBBLE_PREFERENCE_SELECTED = 2;
+ /**
+ * Maximum length of the component name of a registered NotificationListenerService.
+ * @hide
+ */
+ public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500;
+
@UnsupportedAppUsage
private static INotificationManager sService;
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index b5e4fa38d244..af06d7304160 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -243,7 +243,9 @@ public String getPackageName() {
return mHelper != null ? mHelper.packageName : null;
}
- public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
+ /** Updates enabled state based on associated package. */
+ public void updateState(
+ @NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
if (mAppOpsManager == null) {
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
@@ -254,7 +256,9 @@ public void updateState(@NonNull String packageName, int uid, boolean isEnabled)
final boolean ecmEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
- if (isEnabled) {
+ if (!isEnableAllowed && !isEnabled) {
+ setEnabled(false);
+ } else if (isEnabled) {
setEnabled(true);
} else if (appOpsAllowed && isDisabledByAppOps()) {
setEnabled(true);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 51db4b820aad..286782c60c66 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5529,6 +5529,11 @@ public void setNotificationListenerAccessGrantedForUser(ComponentName listener,
boolean granted, boolean userSet) {
Objects.requireNonNull(listener);
checkNotificationListenerAccess();
+ if (granted && listener.flattenToString().length()
+ > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
+ throw new IllegalArgumentException(
+ "Component name too long: " + listener.flattenToString());
+ }
if (!userSet && isNotificationListenerAccessUserSet(listener)) {
// Don't override user's choice
return;
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index b296ef2a1443..1ff01a6c70bf 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1049,7 +1049,11 @@ private void grantNotificationListenerAccess(String pkg, int userId) {
for (ComponentName c : possibleServices) {
if (Objects.equals(c.getPackageName(), pkg)) {
- nm.setNotificationListenerAccessGrantedForUser(c, userId, true);
+ try {
+ nm.setNotificationListenerAccessGrantedForUser(c, userId, true);
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not grant NLS access to package " + pkg, e);
+ }
}
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 718d9c50c6b2..24fff1279a4e 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -84,6 +84,7 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
@@ -3846,6 +3847,30 @@ public void testSetListenerAccessForUser() throws Exception {
any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
}
+ @Test
+ public void testSetListenerAccessForUser_grantWithNameTooLong_throws() {
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
+ ComponentName c = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mBinderService.setNotificationListenerAccessGrantedForUser(
+ c, user.getIdentifier(), /* enabled= */ true, true));
+ }
+
+ @Test
+ public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception {
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
+ ComponentName c = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+
+ mBinderService.setNotificationListenerAccessGrantedForUser(
+ c, user.getIdentifier(), /* enabled= */ false, true);
+
+ verify(mListeners).setPackageOrComponentEnabled(
+ c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
+ }
+
@Test
public void testSetAssistantAccessForUser() throws Exception {
UserInfo ui = new UserInfo();

View File

@ -1,529 +0,0 @@
From 7e173b43837c419a7cb77f5758191a557fdc76fa Mon Sep 17 00:00:00 2001
From: Miranda Kephart <mkephart@google.com>
Date: Fri, 28 Apr 2023 10:58:46 -0400
Subject: [PATCH] [DO NOT MERGE] Update quickshare intent rather than
recreating
Currently, we extract the quickshare intent and re-wrap it as a new
PendingIntent once we get the screenshot URI. This is insecure as
it leads to executing the original with SysUI's permissions, which
the app may not have. This change switches to using Intent.fillin
to add the URI, keeping the original PendingIntent and original
permission set.
Bug: 278720336
Test: manual (to test successful quickshare), atest
SaveImageInBackgroundTaskTest (to verify original pending intent
unchanged)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:02938e8ccae910d96578475a19dff0a5e746b03d)
Merged-In: Icad3d5f939fcfb894e2038948954bc2735dbe326
Change-Id: Icad3d5f939fcfb894e2038948954bc2735dbe326
---
.../screenshot/SaveImageInBackgroundTask.java | 113 ++++---
.../screenshot/ScreenshotController.java | 1 +
.../screenshot/SmartActionsReceiver.java | 7 +-
.../SaveImageInBackgroundTaskTest.kt | 282 ++++++++++++++++++
4 files changed, 353 insertions(+), 50 deletions(-)
create mode 100644 packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index bf5fbd223186..49989273d012 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -21,6 +21,7 @@
import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE;
import static com.android.systemui.screenshot.LogConfig.logTag;
import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType;
+import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.QUICK_SHARE_ACTION;
import android.app.ActivityTaskManager;
import android.app.Notification;
@@ -141,7 +142,12 @@ protected Void doInBackground(Void... paramsUnused) {
// Since Quick Share target recommendation does not rely on image URL, it is
// queried and surfaced before image compress/export. Action intent would not be
// used, because it does not contain image URL.
- queryQuickShareAction(image, user);
+ Notification.Action quickShare =
+ queryQuickShareAction(mScreenshotId, image, user, null);
+ if (quickShare != null) {
+ mQuickShareData.quickShareAction = quickShare;
+ mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
+ }
}
// Call synchronously here since already on a background thread.
@@ -180,8 +186,8 @@ protected Void doInBackground(Void... paramsUnused) {
smartActionsEnabled);
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri,
smartActionsEnabled);
- mImageData.quickShareAction = createQuickShareAction(mContext,
- mQuickShareData.quickShareAction, uri);
+ mImageData.quickShareAction = createQuickShareAction(
+ mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image, user);
mImageData.subject = getSubjectString();
mParams.mActionsReadyListener.onActionsReady(mImageData);
@@ -423,75 +429,86 @@ private static void addIntentExtras(String screenshotId, Intent intent, String a
}
/**
- * Populate image uri into intent of Quick Share action.
+ * Wrap the quickshare intent and populate the fillin intent with the URI
*/
@VisibleForTesting
- private Notification.Action createQuickShareAction(Context context, Notification.Action action,
- Uri uri) {
- if (action == null) {
+ Notification.Action createQuickShareAction(
+ Notification.Action quickShare, String screenshotId, Uri uri, long imageTime,
+ Bitmap image, UserHandle user) {
+ if (quickShare == null) {
return null;
+ } else if (quickShare.actionIntent.isImmutable()) {
+ Notification.Action quickShareWithUri =
+ queryQuickShareAction(screenshotId, image, user, uri);
+ if (quickShareWithUri == null
+ || !quickShareWithUri.title.toString().contentEquals(quickShare.title)) {
+ return null;
+ }
+ quickShare = quickShareWithUri;
}
- // Populate image URI into Quick Share chip intent
- Intent sharingIntent = action.actionIntent.getIntent();
- sharingIntent.setType("image/png");
- sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
- String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
+
+ Intent wrappedIntent = new Intent(mContext, SmartActionsReceiver.class)
+ .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
+ .putExtra(ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
+ createFillInIntent(uri, imageTime))
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ Bundle extras = quickShare.getExtras();
+ String actionType = extras.getString(
+ ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
+ ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
+ addIntentExtras(screenshotId, wrappedIntent, actionType, true);
+ PendingIntent broadcastIntent =
+ PendingIntent.getBroadcast(mContext, mRandom.nextInt(), wrappedIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ return new Notification.Action.Builder(quickShare.getIcon(), quickShare.title,
+ broadcastIntent)
+ .setContextual(true)
+ .addExtras(extras)
+ .build();
+ }
+
+ private Intent createFillInIntent(Uri uri, long imageTime) {
+ Intent fillIn = new Intent();
+ fillIn.setType("image/png");
+ fillIn.putExtra(Intent.EXTRA_STREAM, uri);
+ String subjectDate = DateFormat.getDateTimeInstance().format(new Date(imageTime));
String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
- sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ fillIn.putExtra(Intent.EXTRA_SUBJECT, subject);
// Include URI in ClipData also, so that grantPermission picks it up.
// We don't use setData here because some apps interpret this as "to:".
- ClipData clipdata = new ClipData(new ClipDescription("content",
- new String[]{"image/png"}),
+ ClipData clipData = new ClipData(
+ new ClipDescription("content", new String[]{"image/png"}),
new ClipData.Item(uri));
- sharingIntent.setClipData(clipdata);
- sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- PendingIntent updatedPendingIntent = PendingIntent.getActivity(
- context, 0, sharingIntent,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-
- // Proxy smart actions through {@link SmartActionsReceiver} for logging smart actions.
- Bundle extras = action.getExtras();
- String actionType = extras.getString(
- ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
- ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
- Intent intent = new Intent(context, SmartActionsReceiver.class)
- .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- // We only query for quick share actions when smart actions are enabled, so we can assert
- // that it's true here.
- addIntentExtras(mScreenshotId, intent, actionType, true /* smartActionsEnabled */);
- PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
- mRandom.nextInt(),
- intent,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- return new Notification.Action.Builder(action.getIcon(), action.title,
- broadcastIntent).setContextual(true).addExtras(extras).build();
+ fillIn.setClipData(clipData);
+ fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ return fillIn;
}
/**
* Query and surface Quick Share chip if it is available. Action intent would not be used,
* because it does not contain image URL which would be populated in {@link
- * #createQuickShareAction(Context, Notification.Action, Uri)}
+ * #createQuickShareAction(Notification.Action, String, Uri, long, Bitmap, UserHandle)}
*/
- private void queryQuickShareAction(Bitmap image, UserHandle user) {
+
+ @VisibleForTesting
+ Notification.Action queryQuickShareAction(
+ String screenshotId, Bitmap image, UserHandle user, Uri uri) {
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
- mScreenshotId, null, image, mSmartActionsProvider,
- ScreenshotSmartActionType.QUICK_SHARE_ACTION,
- true /* smartActionsEnabled */, user);
+ screenshotId, uri, image, mSmartActionsProvider, QUICK_SHARE_ACTION,
+ true, user);
int timeoutMs = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.SCREENSHOT_NOTIFICATION_QUICK_SHARE_ACTIONS_TIMEOUT_MS,
500);
List<Notification.Action> quickShareActions =
mScreenshotSmartActions.getSmartActions(
- mScreenshotId, quickShareActionsFuture, timeoutMs,
- mSmartActionsProvider,
- ScreenshotSmartActionType.QUICK_SHARE_ACTION);
+ screenshotId, quickShareActionsFuture, timeoutMs,
+ mSmartActionsProvider, QUICK_SHARE_ACTION);
if (!quickShareActions.isEmpty()) {
- mQuickShareData.quickShareAction = quickShareActions.get(0);
- mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
+ return quickShareActions.get(0);
}
+ return null;
}
private String getSubjectString() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 2e51cefb2c4b..8b0e7ff51aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -246,6 +246,7 @@ interface TransitionDestination {
static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
+ static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index 45af1874e9db..9761f5931193 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -18,6 +18,7 @@
import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
+import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT_FILLIN;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_TYPE;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID;
@@ -46,7 +47,9 @@ public class SmartActionsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
+ PendingIntent pendingIntent =
+ intent.getParcelableExtra(EXTRA_ACTION_INTENT, PendingIntent.class);
+ Intent fillIn = intent.getParcelableExtra(EXTRA_ACTION_INTENT_FILLIN, Intent.class);
String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
if (DEBUG_ACTIONS) {
Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
@@ -54,7 +57,7 @@ public void onReceive(Context context, Intent intent) {
ActivityOptions opts = ActivityOptions.makeBasic();
try {
- pendingIntent.send(context, 0, null, null, null, null, opts.toBundle());
+ pendingIntent.send(context, 0, fillIn, null, null, null, opts.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Pending intent canceled", e);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
new file mode 100644
index 000000000000..03f8c9394218
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.ScreenshotController.SaveImageInBackgroundData
+import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import java.util.concurrent.CompletableFuture
+import java.util.function.Supplier
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.Test
+import org.mockito.Mockito
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SaveImageInBackgroundTaskTest : SysuiTestCase() {
+ private val imageExporter = mock<ImageExporter>()
+ private val smartActions = mock<ScreenshotSmartActions>()
+ private val saveImageData = SaveImageInBackgroundData()
+ private val sharedTransitionSupplier =
+ mock<Supplier<ScreenshotController.SavedImageData.ActionTransition>>()
+ private val testScreenshotId: String = "testScreenshotId"
+ private val testBitmap = mock<Bitmap>()
+ private val testUser = UserHandle.getUserHandleForUid(0)
+ private val testIcon = mock<Icon>()
+ private val testImageTime = 1234.toLong()
+
+ private val smartActionsUriFuture = mock<CompletableFuture<List<Notification.Action>>>()
+ private val smartActionsFuture = mock<CompletableFuture<List<Notification.Action>>>()
+
+ private val testUri: Uri = Uri.parse("testUri")
+ private val intent =
+ Intent(Intent.ACTION_SEND)
+ .setComponent(
+ ComponentName.unflattenFromString(
+ "com.google.android.test/com.google.android.test.TestActivity"
+ )
+ )
+ private val immutablePendingIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ private val mutablePendingIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
+ )
+
+ private val saveImageTask =
+ SaveImageInBackgroundTask(
+ mContext,
+ imageExporter,
+ smartActions,
+ saveImageData,
+ sharedTransitionSupplier,
+ )
+
+ @Before
+ fun setup() {
+ Mockito.`when`(
+ smartActions.getSmartActionsFuture(
+ eq(testScreenshotId),
+ any(Uri::class.java),
+ eq(testBitmap),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ any(ScreenshotSmartActionType::class.java),
+ any(Boolean::class.java),
+ eq(testUser)
+ )
+ )
+ .thenReturn(smartActionsUriFuture)
+ Mockito.`when`(
+ smartActions.getSmartActionsFuture(
+ eq(testScreenshotId),
+ eq(null),
+ eq(testBitmap),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ any(ScreenshotSmartActionType::class.java),
+ any(Boolean::class.java),
+ eq(testUser)
+ )
+ )
+ .thenReturn(smartActionsFuture)
+ }
+
+ @Test
+ fun testQueryQuickShare_noAction() {
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(ArrayList<Notification.Action>())
+
+ val quickShareAction =
+ saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)
+
+ assertNull(quickShareAction)
+ }
+
+ @Test
+ fun testQueryQuickShare_withActions() {
+ val actions = ArrayList<Notification.Action>()
+ actions.add(constructAction("Action One", mutablePendingIntent))
+ actions.add(constructAction("Action Two", mutablePendingIntent))
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+
+ val quickShareAction =
+ saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)!!
+
+ assertEquals("Action One", quickShareAction.title)
+ assertEquals(mutablePendingIntent, quickShareAction.actionIntent)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_originalWasNull_returnsNull() {
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ null,
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser
+ )
+
+ assertNull(quickShareAction)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_immutableIntentDifferentAction_returnsNull() {
+ val actions = ArrayList<Notification.Action>()
+ actions.add(constructAction("New Test Action", immutablePendingIntent))
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+ val origAction = constructAction("Old Test Action", immutablePendingIntent)
+
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ origAction,
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser,
+ )
+
+ assertNull(quickShareAction)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_mutableIntent_returnsSafeIntent() {
+ val actions = ArrayList<Notification.Action>()
+ val action = constructAction("Action One", mutablePendingIntent)
+ actions.add(action)
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ constructAction("Test Action", mutablePendingIntent),
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser
+ )
+ val quickSharePendingIntent =
+ quickShareAction.actionIntent.intent.extras!!.getParcelable(
+ ScreenshotController.EXTRA_ACTION_INTENT,
+ PendingIntent::class.java
+ )
+
+ assertEquals("Test Action", quickShareAction.title)
+ assertEquals(mutablePendingIntent, quickSharePendingIntent)
+ }
+
+ @Test
+ fun testCreateQuickShareAction_immutableIntent_returnsSafeIntent() {
+ val actions = ArrayList<Notification.Action>()
+ val action = constructAction("Test Action", immutablePendingIntent)
+ actions.add(action)
+ Mockito.`when`(
+ smartActions.getSmartActions(
+ eq(testScreenshotId),
+ eq(smartActionsUriFuture),
+ any(Int::class.java),
+ any(ScreenshotNotificationSmartActionsProvider::class.java),
+ eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
+ )
+ )
+ .thenReturn(actions)
+
+ val quickShareAction =
+ saveImageTask.createQuickShareAction(
+ constructAction("Test Action", immutablePendingIntent),
+ testScreenshotId,
+ testUri,
+ testImageTime,
+ testBitmap,
+ testUser,
+ )!!
+
+ assertEquals("Test Action", quickShareAction.title)
+ assertEquals(
+ immutablePendingIntent,
+ quickShareAction.actionIntent.intent.extras!!.getParcelable(
+ ScreenshotController.EXTRA_ACTION_INTENT,
+ PendingIntent::class.java
+ )
+ )
+ }
+
+ private fun constructAction(title: String, intent: PendingIntent): Notification.Action {
+ return Notification.Action.Builder(testIcon, title, intent).build()
+ }
+}

View File

@ -1,30 +0,0 @@
From 44191b1c6b55d9e09d8b5fca96176035abc18c31 Mon Sep 17 00:00:00 2001
From: Dmitry Dementyev <dementyev@google.com>
Date: Wed, 5 Jul 2023 10:45:04 -0700
Subject: [PATCH] Update AccountManagerService checkKeyIntentParceledCorrectly.
Bug: 265798288
Test: manual
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8476b140eed0235df4e8f07d94420a1471191b55)
Merged-In: Ia2030a9dc371dccadd4e188a529351ac4232bb4f
Change-Id: Ia2030a9dc371dccadd4e188a529351ac4232bb4f
---
.../com/android/server/accounts/AccountManagerService.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1dc0942ceac5..7a51f5155a98 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4932,7 +4932,10 @@ private boolean checkKeyIntentParceledCorrectly(Bundle bundle) {
p.setDataPosition(0);
Bundle simulateBundle = p.readBundle();
p.recycle();
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent != null && intent.getClass() != Intent.class) {
+ return false;
+ }
Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT,
Intent.class);
if (intent == null) {

View File

@ -1,216 +0,0 @@
From 8dc8dfe572ce5e4bcb64418275b6d8c4e05284ac Mon Sep 17 00:00:00 2001
From: Beth Thibodeau <ethibodeau@google.com>
Date: Thu, 22 Jun 2023 18:26:44 -0500
Subject: [PATCH] Improve user handling when querying for resumable media
- Before trying to query recent media from a saved component, check
whether the current user actually has that component installed
- Track user when creating the MediaBrowser, in case the user changes
before the MBS returns a result
Test: atest MediaResumeListenerTest
Bug: 284297711
(cherry picked from commit e566a250ad61e269119b475c7ebdae6ca962c4a7)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d61741288b4d7614e4677428aac6418f6f1d79f0)
Merged-In: I838ff0e125acadabc8436a00dbff707cc4be6249
Change-Id: I838ff0e125acadabc8436a00dbff707cc4be6249
---
.../controls/resume/MediaResumeListener.kt | 54 ++++++++++++-------
.../controls/resume/ResumeMediaBrowser.java | 15 +++++-
.../resume/ResumeMediaBrowserFactory.java | 7 ++-
3 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index b0389b50cd7d..813ca17422ec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -122,18 +122,18 @@ constructor(
Log.e(TAG, "Error getting package information", e)
}
- Log.d(TAG, "Adding resume controls $desc")
- mediaDataManager.addResumptionControls(
- currentUserId,
- desc,
- resumeAction,
- token,
- appName.toString(),
- appIntent,
- component.packageName
- )
- }
+ Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
+ mediaDataManager.addResumptionControls(
+ browser.userId,
+ desc,
+ resumeAction,
+ token,
+ appName.toString(),
+ appIntent,
+ component.packageName
+ )
}
+ }
init {
if (useMediaResumption) {
@@ -196,7 +196,11 @@ constructor(
}
resumeComponents.add(component to lastPlayed)
}
- Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
+ Log.d(
+ TAG,
+ "loaded resume components for $currentUserId: " +
+ "${resumeComponents.toArray().contentToString()}"
+ )
if (needsUpdate) {
// Save any missing times that we had to fill in
@@ -210,11 +214,21 @@ constructor(
return
}
+ val pm = context.packageManager
val now = systemClock.currentTimeMillis()
resumeComponents.forEach {
if (now.minus(it.second) <= RESUME_MEDIA_TIMEOUT) {
- val browser = mediaBrowserFactory.create(mediaBrowserCallback, it.first)
- browser.findRecentMedia()
+ // Verify that the service exists for this user
+ val intent = Intent(MediaBrowserService.SERVICE_INTERFACE)
+ intent.component = it.first
+ val inf = pm.resolveServiceAsUser(intent, 0, currentUserId)
+ if (inf != null) {
+ val browser =
+ mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
+ browser.findRecentMedia()
+ } else {
+ Log.d(TAG, "User $currentUserId does not have component ${it.first}")
+ }
}
}
}
@@ -244,7 +258,7 @@ constructor(
Log.d(TAG, "Checking for service component for " + data.packageName)
val pm = context.packageManager
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
- val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
+ val resumeInfo = pm.queryIntentServicesAsUser(serviceIntent, 0, currentUserId)
val inf = resumeInfo?.filter { it.serviceInfo.packageName == data.packageName }
if (inf != null && inf.size > 0) {
@@ -280,13 +294,17 @@ constructor(
browser: ResumeMediaBrowser
) {
// Since this is a test, just save the component for later
- Log.d(TAG, "Can get resumable media from $componentName")
+ Log.d(
+ TAG,
+ "Can get resumable media for ${browser.userId} from $componentName"
+ )
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
mediaBrowser = null
}
},
- componentName
+ componentName,
+ currentUserId
)
mediaBrowser?.testConnection()
}
@@ -326,7 +344,7 @@ constructor(
/** Get a runnable which will resume media playback */
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
- mediaBrowser = mediaBrowserFactory.create(null, componentName)
+ mediaBrowser = mediaBrowserFactory.create(null, componentName, currentUserId)
mediaBrowser?.restart()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
index d460b5b5d782..ceaccafd8f40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
@@ -17,6 +17,7 @@
package com.android.systemui.media.controls.resume;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -53,6 +54,7 @@ public class ResumeMediaBrowser {
private final ResumeMediaBrowserLogger mLogger;
private final ComponentName mComponentName;
private final MediaController.Callback mMediaControllerCallback = new SessionDestroyCallback();
+ @UserIdInt private final int mUserId;
private MediaBrowser mMediaBrowser;
@Nullable private MediaController mMediaController;
@@ -62,18 +64,21 @@ public class ResumeMediaBrowser {
* @param context the context
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
+ * @param userId ID of the current user
*/
public ResumeMediaBrowser(
Context context,
@Nullable Callback callback,
ComponentName componentName,
MediaBrowserFactory browserFactory,
- ResumeMediaBrowserLogger logger) {
+ ResumeMediaBrowserLogger logger,
+ @UserIdInt int userId) {
mContext = context;
mCallback = callback;
mComponentName = componentName;
mBrowserFactory = browserFactory;
mLogger = logger;
+ mUserId = userId;
}
/**
@@ -284,6 +289,14 @@ protected MediaController createMediaController(MediaSession.Token token) {
return new MediaController(mContext, token);
}
+ /**
+ * Get the ID of the user associated with this broswer
+ * @return the user ID
+ */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
/**
* Get the media session token
* @return the token, or null if the MediaBrowser is null or disconnected
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java
index c558227df0b5..e37419127f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java
@@ -16,6 +16,7 @@
package com.android.systemui.media.controls.resume;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
@@ -42,10 +43,12 @@ public ResumeMediaBrowserFactory(
*
* @param callback will be called on connection or error, and addTrack when media item found
* @param componentName component to browse
+ * @param userId ID of the current user
* @return
*/
public ResumeMediaBrowser create(ResumeMediaBrowser.Callback callback,
- ComponentName componentName) {
- return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger);
+ ComponentName componentName, @UserIdInt int userId) {
+ return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger,
+ userId);
}
}

View File

@ -1,48 +0,0 @@
From dfeb4270b8ecad08bc5361f122af9453881a5987 Mon Sep 17 00:00:00 2001
From: Pinyao Ting <pinyaoting@google.com>
Date: Thu, 1 Jun 2023 18:12:44 -0700
Subject: [PATCH] Fix permission issue in legacy shortcut
When building legacy shortcut, Launcher calls
PackageManager#resolveActivity to retrieve necessary permission to
launch the intent.
However, when the source app wraps an arbitrary intent within
Intent#createChooser, the existing logic will fail because launching
Chooser doesn't require additional permission.
This CL fixes the security vulnerability by performing the permission
check against the intent that is wrapped within.
Bug: 270152142
Test: manual
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c53818a16b4322a823497726ac7e7a44501b4442)
Merged-In: If35344c08975e35085c7c2b9b814a3c457a144b0
Change-Id: If35344c08975e35085c7c2b9b814a3c457a144b0
---
.../android/launcher3/util/PackageManagerHelper.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index a6a2751dc7..586e0c9e89 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -145,6 +145,18 @@ public static boolean isAppSuspended(ApplicationInfo info) {
* any permissions
*/
public boolean hasPermissionForActivity(Intent intent, String srcPackage) {
+ // b/270152142
+ if (Intent.ACTION_CHOOSER.equals(intent.getAction())) {
+ final Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return true;
+ }
+ // If given intent is ACTION_CHOOSER, verify srcPackage has permission over EXTRA_INTENT
+ intent = (Intent) extras.getParcelable(Intent.EXTRA_INTENT);
+ if (intent == null) {
+ return true;
+ }
+ }
ResolveInfo target = mPm.resolveActivity(intent, 0);
if (target == null) {
// Not a valid target

View File

@ -1,98 +0,0 @@
From c16e6e78c1c8ba40f8c2ff6a4d87afe44590eb7f Mon Sep 17 00:00:00 2001
From: Krishang Garodia <krishang@google.com>
Date: Mon, 19 Jun 2023 11:43:45 +0000
Subject: [PATCH] Remove invalid surrogates during bindSelection
Test: atest MediaProviderTests
Bug: 223793631
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:108f736d0ec6e974c3f947e7e568845b7e039a0a)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a48b01f78f28fc642b144c673bfcd12ae78c5a73)
Merged-In: I18b879f1a51394b4739225ec88b862fd6d0d5526
Change-Id: I18b879f1a51394b4739225ec88b862fd6d0d5526
---
.../providers/media/util/DatabaseUtils.java | 36 +++++++++++++++++--
.../media/util/DatabaseUtilsTest.java | 10 ++++++
2 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/src/com/android/providers/media/util/DatabaseUtils.java b/src/com/android/providers/media/util/DatabaseUtils.java
index 55efafc7f..53ecf964e 100644
--- a/src/com/android/providers/media/util/DatabaseUtils.java
+++ b/src/com/android/providers/media/util/DatabaseUtils.java
@@ -127,8 +127,9 @@ public class DatabaseUtils {
res.append(((Boolean) arg).booleanValue() ? 1 : 0);
} else {
res.append('\'');
- // Escape single quote character while appending the string.
- res.append(arg.toString().replace("'", "''"));
+ // Escape single quote character while appending the string and reject
+ // invalid unicode.
+ res.append(escapeSingleQuoteAndRejectInvalidUnicode(arg.toString()));
res.append('\'');
}
break;
@@ -142,6 +143,37 @@ public class DatabaseUtils {
return res.toString();
}
+ private static String escapeSingleQuoteAndRejectInvalidUnicode(@NonNull String target) {
+ final int len = target.length();
+ final StringBuilder res = new StringBuilder(len);
+ boolean lastHigh = false;
+
+ for (int i = 0; i < len; ) {
+ final char c = target.charAt(i++);
+
+ if (lastHigh != Character.isLowSurrogate(c)) {
+ Log.e(TAG, "Invalid surrogate in string " + target);
+ throw new IllegalArgumentException("Invalid surrogate in string " + target);
+ }
+
+ lastHigh = Character.isHighSurrogate(c);
+
+ // Escape the single quotes by duplicating them
+ if (c == '\'') {
+ res.append(c);
+ }
+
+ res.append(c);
+ }
+
+ if (lastHigh) {
+ Log.e(TAG, "Invalid surrogate in string " + target);
+ throw new IllegalArgumentException("Invalid surrogate in string " + target);
+ }
+
+ return res.toString();
+ }
+
/**
* Returns data type of the given object's value.
*<p>
diff --git a/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java b/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java
index 685d89704..a90787589 100644
--- a/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java
+++ b/tests/src/com/android/providers/media/util/DatabaseUtilsTest.java
@@ -39,6 +39,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -126,6 +127,15 @@ public void testBindSelection_singleQuoteCharacter() throws Exception {
bindSelection("DATA=?", "Fo''o"));
}
+ @Test
+ public void testBindSelection_RejectInvalidUnicode() {
+ assertThrows(IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uD83Do"));
+ assertThrows(IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uDE00o"));
+ assertEquals("DATA='Fo\uD83D\uDE00o'", bindSelection("DATA=?", "Fo\uD83D\uDE00o"));
+ assertThrows(
+ IllegalArgumentException.class, () -> bindSelection("DATA=?", "Fo\uDE00\uD83Do"));
+ }
+
@Test
public void testResolveQueryArgs_GroupBy() throws Exception {
args.putStringArray(QUERY_ARG_GROUP_COLUMNS, new String[] { "foo", "bar" });

View File

@ -1,41 +0,0 @@
From d5771450d7b2acde9fa051dedbb6c115b001d48b Mon Sep 17 00:00:00 2001
From: Dipankar Bhardwaj <dipankarb@google.com>
Date: Thu, 6 Jul 2023 10:01:20 +0000
Subject: [PATCH] Canonicalize file path for insertion by legacy apps
Apps with legacy external storage can try to create entries in MP for
file paths in other apps external private directories by using a
non-canonical path in insertion calls.
Test: atest LegacyStorageHostTest#testInsertToOtherAppPrivateDirFails
Bug: 276898626
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3c0f583f5dc3f4d395fa2423ab72dbd902c0c6c8)
Merged-In: If4c941c8156f19459b3ec6cbaf705824ecc2ba77
Change-Id: If4c941c8156f19459b3ec6cbaf705824ecc2ba77
---
src/com/android/providers/media/util/FileUtils.java | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index 2e2a3e761..097eca8c9 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -1324,9 +1324,17 @@ public static void computeValuesFromData(@NonNull ContentValues values, boolean
values.remove(MediaColumns.BUCKET_ID);
values.remove(MediaColumns.BUCKET_DISPLAY_NAME);
- final String data = values.getAsString(MediaColumns.DATA);
+ String data = values.getAsString(MediaColumns.DATA);
if (TextUtils.isEmpty(data)) return;
+ try {
+ data = new File(data).getCanonicalPath();
+ values.put(MediaColumns.DATA, data);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(
+ String.format(Locale.ROOT, "Invalid file path:%s in request.", data));
+ }
+
final File file = new File(data);
final File fileLower = new File(data.toLowerCase(Locale.ROOT));

View File

@ -1,34 +0,0 @@
From b1993f6cec45bc638ea1d2875c91d069e89ca57e Mon Sep 17 00:00:00 2001
From: Devin Moore <devinmoore@google.com>
Date: Tue, 25 Apr 2023 00:17:13 +0000
Subject: [PATCH] Allow sensors list to be empty
Test: atest VtsHalSensorManagerV1_0TargetTest
Bug: 278013275
Bug: 269014004
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:49600b10aa5675d4e7e985203d69f252ead13e45)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d9e0d0ad7cb94b2b2d83066685cee45d76381355)
Merged-In: I091f57de9570b0ace3a8da76f16fe0e83f0aa624
Change-Id: I091f57de9570b0ace3a8da76f16fe0e83f0aa624
---
libs/sensor/SensorManager.cpp | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 40061cde61..9f814f1c48 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -176,11 +176,8 @@ status_t SensorManager::assertStateLocked() {
mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
- if (count == 0) {
- ALOGE("Failed to get Sensor list");
- mSensorServer.clear();
- return UNKNOWN_ERROR;
- }
+ // If count is 0, mSensorList will be non-null. This is old
+ // existing behavior and callers expect this.
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");

View File

@ -1,47 +0,0 @@
From 27e7cdc4e5748e2ad85552433cf9c120fd7a936b Mon Sep 17 00:00:00 2001
From: Alisher Alikhodjaev <alisher@google.com>
Date: Wed, 10 May 2023 18:27:42 -0700
Subject: [PATCH] Ensure that SecureNFC setting cannot be bypassed
Bug: 268038643
Test: ctsverifier
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6cb53d963d376b97963120a4d2c7df961789e428)
Merged-In: I53a45c3600dc6bba7009921ca5135ee37b5edfd0
Change-Id: I53a45c3600dc6bba7009921ca5135ee37b5edfd0
---
src/com/android/nfc/NfcService.java | 6 ++++++
src/com/android/nfc/cardemulation/HostEmulationManager.java | 4 +++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index a1b28e97..2305922a 100644
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -1166,6 +1166,12 @@ void enforceBeamShareActivityPolicy(Context context, UserHandle uh) {
}
}
+ public boolean isSecureNfcEnabled() {
+ synchronized (NfcService.this) {
+ return mIsSecureNfcEnabled;
+ }
+ }
+
final class NfcAdapterService extends INfcAdapter.Stub {
@Override
public boolean enable() throws RemoteException {
diff --git a/src/com/android/nfc/cardemulation/HostEmulationManager.java b/src/com/android/nfc/cardemulation/HostEmulationManager.java
index 81462024..8849cca5 100644
--- a/src/com/android/nfc/cardemulation/HostEmulationManager.java
+++ b/src/com/android/nfc/cardemulation/HostEmulationManager.java
@@ -188,7 +188,9 @@ public void onHostEmulationData(byte[] data) {
// Resolve to default
// Check if resolvedService requires unlock
ApduServiceInfo defaultServiceInfo = resolveInfo.defaultService;
- if (defaultServiceInfo.requiresUnlock() && mKeyguard.isKeyguardLocked()) {
+ if ((defaultServiceInfo.requiresUnlock()
+ || NfcService.getInstance().isSecureNfcEnabled())
+ && mKeyguard.isKeyguardLocked()) {
NfcService.getInstance().sendRequireUnlockIntent();
NfcService.getInstance().sendData(AID_NOT_FOUND);
if (DBG) Log.d(TAG, "requiresUnlock()! show toast");

View File

@ -1,31 +0,0 @@
From a1370bd00c106e4d172dc68638778fa111f6ecbe Mon Sep 17 00:00:00 2001
From: Ian Hua <ianhua@google.com>
Date: Thu, 6 Jul 2023 10:05:36 +0000
Subject: [PATCH] Fix out of Bounds Read in convertSubgraphFromHAL in
ShimConverter.cpp in libneuralnetworks_shim_static
Bug: 269270167
Test: N/A
(cherry picked from commit 4bf7bb6b50b412678a681d29f7ced70a4d737762)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:244ac21307a785d49930d4c7e289b74856fa9647)
Merged-In: I33272284b965efcbb531f64cbf838a0d59c28e00
Change-Id: I33272284b965efcbb531f64cbf838a0d59c28e00
---
shim_and_sl/ShimConverter.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/shim_and_sl/ShimConverter.cpp b/shim_and_sl/ShimConverter.cpp
index 1ed0e31cf..4830c5d05 100644
--- a/shim_and_sl/ShimConverter.cpp
+++ b/shim_and_sl/ShimConverter.cpp
@@ -150,6 +150,10 @@ ANeuralNetworksModel* convertSubgraphFromHAL(
break;
}
case OperandLifeTime::CONSTANT_POOL: {
+ if (operand.location.poolIndex >= memoryPools.size()) {
+ *errorStatus = ErrorStatus::INVALID_ARGUMENT;
+ return nullptr;
+ }
resultModel.setOperandValueFromMemory(
i, memoryPools[operand.location.poolIndex].get(), operand.location.offset,
operand.location.length);

View File

@ -1,262 +0,0 @@
From 21623d1f437beb59ceee1fc88cd07d48e3f6a13e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= <matiashe@google.com>
Date: Mon, 5 Jun 2023 18:24:04 +0200
Subject: [PATCH] Don't hide approved NLSes in Settings
Note that an NLS that shouldn't be approvable (because its name is too long) but was already approved (either before the max length check was introduced, or through other means) will disappear from the list if the user revokes its access. This might be somewhat confusing, but since this is a very-edge case already it's fine.
Bug: 282932362
Test: manual
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ff255c6eda1528f01a167a9a65b7f8e414d28584)
Merged-In: I4c9faea68e6d16b1a4ec7f472b5433cac1704c06
Change-Id: I4c9faea68e6d16b1a4ec7f472b5433cac1704c06
---
.../NotificationAccessSettings.java | 25 +--
.../notification/NotificationBackend.java | 3 +
.../NotificationAccessSettingsTest.java | 144 ++++++++++++++++++
3 files changed, 160 insertions(+), 12 deletions(-)
create mode 100644 tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 56d3f0e445..369c4f6dfa 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -43,6 +43,7 @@
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
@@ -63,8 +64,8 @@
@SearchIndexable
public class NotificationAccessSettings extends EmptyTextSettings {
private static final String TAG = "NotifAccessSettings";
- private static final String ALLOWED_KEY = "allowed";
- private static final String NOT_ALLOWED_KEY = "not_allowed";
+ static final String ALLOWED_KEY = "allowed";
+ static final String NOT_ALLOWED_KEY = "not_allowed";
private static final int MAX_CN_LENGTH = 500;
private static final ManagedServiceSettings.Config CONFIG =
@@ -80,9 +81,9 @@ public class NotificationAccessSettings extends EmptyTextSettings {
.setEmptyText(R.string.no_notification_listeners)
.build();
- private NotificationManager mNm;
+ @VisibleForTesting NotificationManager mNm;
protected Context mContext;
- private PackageManager mPm;
+ @VisibleForTesting PackageManager mPm;
private DevicePolicyManager mDpm;
private ServiceListing mServiceListing;
private IconDrawableFactory mIconDrawableFactory;
@@ -102,12 +103,6 @@ public void onCreate(Bundle icicle) {
.setNoun(CONFIG.noun)
.setSetting(CONFIG.setting)
.setTag(CONFIG.tag)
- .setValidator(info -> {
- if (info.getComponentName().flattenToString().length() > MAX_CN_LENGTH) {
- return false;
- }
- return true;
- })
.build();
mServiceListing.addCallback(this::updateList);
@@ -140,7 +135,8 @@ public void onPause() {
mServiceListing.setListening(false);
}
- private void updateList(List<ServiceInfo> services) {
+ @VisibleForTesting
+ void updateList(List<ServiceInfo> services) {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final int managedProfileId = Utils.getManagedProfileId(um, UserHandle.myUserId());
@@ -153,6 +149,11 @@ private void updateList(List<ServiceInfo> services) {
services.sort(new PackageItemInfo.DisplayNameComparator(mPm));
for (ServiceInfo service : services) {
final ComponentName cn = new ComponentName(service.packageName, service.name);
+ boolean isAllowed = mNm.isNotificationListenerAccessGranted(cn);
+ if (!isAllowed && cn.flattenToString().length() > MAX_CN_LENGTH) {
+ continue;
+ }
+
CharSequence title = null;
try {
title = mPm.getApplicationInfoAsUser(
@@ -200,7 +201,7 @@ private void updateList(List<ServiceInfo> services) {
return true;
});
pref.setKey(cn.flattenToString());
- if (mNm.isNotificationListenerAccessGranted(cn)) {
+ if (isAllowed) {
allowedCategory.addPreference(pref);
} else {
notAllowedCategory.addPreference(pref);
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 68f5d081d1..589d455428 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -133,6 +133,9 @@ void recordCanBeBlocked(PackageInfo app, AppRow row) {
static public CharSequence getDeviceList(ICompanionDeviceManager cdm, LocalBluetoothManager lbm,
String pkg, int userId) {
+ if (cdm == null) {
+ return "";
+ }
boolean multiple = false;
StringBuilder sb = new StringBuilder();
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
new file mode 100644
index 0000000000..e644c2975b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.settings.notification;
+
+import static com.android.settings.notification.NotificationAccessSettings.ALLOWED_KEY;
+import static com.android.settings.notification.NotificationAccessSettings.NOT_ALLOWED_KEY;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import com.google.common.base.Strings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.ArrayList;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothUtils.class})
+public class NotificationAccessSettingsTest {
+
+ private Context mContext;
+ private NotificationAccessSettings mAccessSettings;
+ @Mock
+ private NotificationManager mNotificationManager;
+ @Mock
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ ShadowApplication shadowApp = ShadowApplication.getInstance();
+ shadowApp.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+ mAccessSettings = new NotificationAccessSettings();
+ FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).setup().get();
+ activity.getSupportFragmentManager().beginTransaction().add(mAccessSettings, null).commit();
+
+ when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).then(
+ (Answer<ApplicationInfo>) invocation -> {
+ ApplicationInfo appInfo = mock(ApplicationInfo.class);
+ when(appInfo.loadLabel(any())).thenReturn(invocation.getArgument(0));
+ return appInfo;
+ });
+
+ mAccessSettings.mNm = mNotificationManager;
+ mAccessSettings.mPm = mPackageManager;
+ ShadowBluetoothUtils.sLocalBluetoothManager = mock(LocalBluetoothManager.class);
+ }
+
+ @Test
+ public void updateList_enabledLongName_shown() {
+ ComponentName longCn = new ComponentName("test.pkg1",
+ Strings.repeat("Blah", 200) + "Service");
+ ComponentName shortCn = new ComponentName("test.pkg2", "ReasonableService");
+ ArrayList<ServiceInfo> services = new ArrayList<>();
+ services.add(newServiceInfo(longCn.getPackageName(), longCn.getClassName(), 1));
+ services.add(newServiceInfo(shortCn.getPackageName(), shortCn.getClassName(), 2));
+ when(mNotificationManager.isNotificationListenerAccessGranted(any())).thenReturn(true);
+
+ mAccessSettings.updateList(services);
+
+ PreferenceScreen screen = mAccessSettings.getPreferenceScreen();
+ PreferenceCategory allowed = checkNotNull(screen.findPreference(ALLOWED_KEY));
+ PreferenceCategory notAllowed = checkNotNull(screen.findPreference(NOT_ALLOWED_KEY));
+ assertThat(allowed.getPreferenceCount()).isEqualTo(2);
+ assertThat(allowed.getPreference(0).getKey()).isEqualTo(longCn.flattenToString());
+ assertThat(allowed.getPreference(1).getKey()).isEqualTo(shortCn.flattenToString());
+ assertThat(notAllowed.getPreferenceCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void updateList_disabledLongName_notShown() {
+ ComponentName longCn = new ComponentName("test.pkg1",
+ Strings.repeat("Blah", 200) + "Service");
+ ComponentName shortCn = new ComponentName("test.pkg2", "ReasonableService");
+ ArrayList<ServiceInfo> services = new ArrayList<>();
+ services.add(newServiceInfo(longCn.getPackageName(), longCn.getClassName(), 1));
+ services.add(newServiceInfo(shortCn.getPackageName(), shortCn.getClassName(), 2));
+ when(mNotificationManager.isNotificationListenerAccessGranted(any())).thenReturn(false);
+
+ mAccessSettings.updateList(services);
+
+ PreferenceScreen screen = mAccessSettings.getPreferenceScreen();
+ PreferenceCategory allowed = checkNotNull(screen.findPreference(ALLOWED_KEY));
+ PreferenceCategory notAllowed = checkNotNull(screen.findPreference(NOT_ALLOWED_KEY));
+ assertThat(allowed.getPreferenceCount()).isEqualTo(0);
+ assertThat(notAllowed.getPreferenceCount()).isEqualTo(1);
+ assertThat(notAllowed.getPreference(0).getKey()).isEqualTo(shortCn.flattenToString());
+ }
+
+ private static ServiceInfo newServiceInfo(String packageName, String serviceName, int uid) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = packageName;
+ serviceInfo.name = serviceName;
+ serviceInfo.applicationInfo = new ApplicationInfo();
+ serviceInfo.applicationInfo.uid = uid;
+ return serviceInfo;
+ }
+}

View File

@ -1,124 +0,0 @@
From fa5ec443d94922424112fe8a7c7f9d3b36dca67d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= <matiashe@google.com>
Date: Thu, 15 Jun 2023 18:37:52 +0200
Subject: [PATCH] Settings: don't try to allow NLSes with too-long component
names
* NotificationAccessConfirmationActivity (triggered through CompanionDeviceManager) -> Don't show the dialog, bail out early similarly to other invalid inputs.
* NotificationAccessSettings (from Special App Access) -> No changes, but use the canonical constant now.
* ApprovalPreferenceController (used in NotificationAccessDetails) -> Disable the toggle, unless the NLS was previously approved (in which case it can still be removed).
Fixes: 260570119
Fixes: 286043036
Test: atest + manually
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b88fbf932a1631792a422f8ac34e83e1d6ae74d7)
Merged-In: Ifc048311746c027e3683cdcf65f1079d04cf7c56
Change-Id: Ifc048311746c027e3683cdcf65f1079d04cf7c56
---
.../ApprovalPreferenceController.java | 5 +++-
...otificationAccessConfirmationActivity.java | 4 ++-
.../NotificationAccessSettings.java | 4 +--
.../ApprovalPreferenceControllerTest.java | 30 +++++++++++++++++++
4 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java
index 0767e65bbcb..6bee62cc688 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java
@@ -81,6 +81,8 @@ public void updateState(Preference pref) {
final RestrictedSwitchPreference preference =
(RestrictedSwitchPreference) pref;
final CharSequence label = mPkgInfo.applicationInfo.loadLabel(mPm);
+ final boolean isAllowedCn = mCn.flattenToShortString().length()
+ <= NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH;
final boolean isEnabled = isServiceEnabled(mCn);
preference.setChecked(isEnabled);
preference.setOnPreferenceChangeListener((p, newValue) -> {
@@ -105,7 +107,8 @@ public void updateState(Preference pref) {
return false;
}
});
- preference.updateState(mCn.getPackageName(), mPkgInfo.applicationInfo.uid, isEnabled);
+ preference.updateState(
+ mCn.getPackageName(), mPkgInfo.applicationInfo.uid, isAllowedCn, isEnabled);
}
public void disable(final ComponentName cn) {
diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
index dfe6df2a5ca..a6b565ae6ba 100644
--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
+++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
@@ -67,7 +67,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
mUserId = getIntent().getIntExtra(EXTRA_USER_ID, UserHandle.USER_NULL);
CharSequence mAppLabel;
- if (mComponentName == null || mComponentName.getPackageName() == null) {
+ if (mComponentName == null || mComponentName.getPackageName() == null
+ || mComponentName.flattenToString().length()
+ > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
finish();
return;
}
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 369c4f6dfaf..e2ef0ddccb4 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -66,7 +66,6 @@ public class NotificationAccessSettings extends EmptyTextSettings {
private static final String TAG = "NotifAccessSettings";
static final String ALLOWED_KEY = "allowed";
static final String NOT_ALLOWED_KEY = "not_allowed";
- private static final int MAX_CN_LENGTH = 500;
private static final ManagedServiceSettings.Config CONFIG =
new ManagedServiceSettings.Config.Builder()
@@ -150,7 +149,8 @@ void updateList(List<ServiceInfo> services) {
for (ServiceInfo service : services) {
final ComponentName cn = new ComponentName(service.packageName, service.name);
boolean isAllowed = mNm.isNotificationListenerAccessGranted(cn);
- if (!isAllowed && cn.flattenToString().length() > MAX_CN_LENGTH) {
+ if (!isAllowed && cn.flattenToString().length()
+ > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
continue;
}
diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java
index 249b713987c..4601a1cfbaa 100644
--- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java
@@ -83,6 +83,36 @@ public void setUp() {
}
+ @Test
+ public void updateState_enabled() {
+ when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(
+ AppOpsManager.MODE_ALLOWED);
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ RestrictedSwitchPreference pref = new RestrictedSwitchPreference(
+ mContext);
+ pref.setAppOps(mAppOpsManager);
+
+ mController.updateState(pref);
+
+ assertThat(pref.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_invalidCn_disabled() {
+ ComponentName longCn = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+ mController.setCn(longCn);
+ when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(
+ AppOpsManager.MODE_ALLOWED);
+ RestrictedSwitchPreference pref = new RestrictedSwitchPreference(
+ mContext);
+ pref.setAppOps(mAppOpsManager);
+
+ mController.updateState(pref);
+
+ assertThat(pref.isEnabled()).isFalse();
+ }
+
@Test
public void updateState_checked() {
when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(

View File

@ -1,228 +0,0 @@
From ba4da9c7b3a711a5e1c73dcf361b0c14fe02ebf4 Mon Sep 17 00:00:00 2001
From: Taran Singh <tarandeep@google.com>
Date: Fri, 19 May 2023 23:17:47 +0000
Subject: [PATCH] DO NOT MERGE: Prevent non-system IME from becoming device
admin
Currently selected IME can inject KeyEvent on DeviceAdminAdd screen to
activate itself as device admin and cause various DoS attacks.
This CL ensures KeyEvent on "Activate" button can only come from system
apps.
Bug: 280793427
Test: atest DeviceAdminActivationTest
(cherry picked from commit 70a501d02e0a6aefd874767a15378ba998759373)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0976cd789d3bfb593e73237b5b0adc39933a1c1c)
Merged-In: I6470d1684d707f4b1e86f8b456be0b4e0af5f188
Change-Id: I6470d1684d707f4b1e86f8b456be0b4e0af5f188
---
.../deviceadmin/DeviceAdminAdd.java | 129 +++++++++---------
1 file changed, 68 insertions(+), 61 deletions(-)
diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
index fa76a948c06..5746d13666a 100644
--- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
+++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
@@ -66,6 +66,7 @@
import android.util.EventLog;
import android.util.Log;
import android.view.Display;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -156,12 +157,12 @@ protected void onCreate(Bundle icicle) {
mHandler = new Handler(getMainLooper());
- mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
- mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
- mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mDPM = getSystemService(DevicePolicyManager.class);
+ mAppOps = getSystemService(AppOpsManager.class);
+ mLayoutInflaternflater = getSystemService(LayoutInflater.class);
PackageManager packageManager = getPackageManager();
- if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task");
finish();
return;
@@ -171,7 +172,7 @@ protected void onCreate(Bundle icicle) {
EXTRA_CALLED_FROM_SUPPORT_DIALOG, false);
String action = getIntent().getAction();
- ComponentName who = (ComponentName)getIntent().getParcelableExtra(
+ ComponentName who = (ComponentName) getIntent().getParcelableExtra(
DevicePolicyManager.EXTRA_DEVICE_ADMIN);
if (who == null) {
String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME);
@@ -229,7 +230,7 @@ protected void onCreate(Bundle icicle) {
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
int count = avail == null ? 0 : avail.size();
boolean found = false;
- for (int i=0; i<count; i++) {
+ for (int i = 0; i < count; i++) {
ResolveInfo ri = avail.get(i);
if (ai.packageName.equals(ri.activityInfo.packageName)
&& ai.name.equals(ri.activityInfo.name)) {
@@ -345,22 +346,22 @@ public void onDismiss(DialogInterface dialogInterface) {
mAdminWarning = dialog.findViewById(R.id.admin_warning_simplified);
mAdminWarning.setText(
mDPM.getResources().getString(NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED, () ->
- getString(R.string.device_admin_warning_simplified,
- mProfileOwnerName), mProfileOwnerName));
+ getString(R.string.device_admin_warning_simplified,
+ mProfileOwnerName), mProfileOwnerName));
return;
}
setContentView(R.layout.device_admin_add);
- mAdminIcon = (ImageView)findViewById(R.id.admin_icon);
- mAdminName = (TextView)findViewById(R.id.admin_name);
- mAdminDescription = (TextView)findViewById(R.id.admin_description);
+ mAdminIcon = (ImageView) findViewById(R.id.admin_icon);
+ mAdminName = (TextView) findViewById(R.id.admin_name);
+ mAdminDescription = (TextView) findViewById(R.id.admin_description);
mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning);
mProfileOwnerWarning.setText(
mDPM.getResources().getString(SET_PROFILE_OWNER_POSTSETUP_WARNING,
() -> getString(R.string.adding_profile_owner_warning)));
- mAddMsg = (TextView)findViewById(R.id.add_msg);
+ mAddMsg = (TextView) findViewById(R.id.add_msg);
mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander);
final View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
@@ -381,7 +382,7 @@ public void onGlobalLayout() {
boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines;
mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE);
if (hideMsgExpander) {
- ((View)mAddMsgExpander.getParent()).invalidate();
+ ((View) mAddMsgExpander.getParent()).invalidate();
}
mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
@@ -399,7 +400,7 @@ public void onGlobalLayout() {
mCancelButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER,
- mDeviceAdmin.getActivityInfo().applicationInfo.uid);
+ mDeviceAdmin.getActivityInfo().applicationInfo.uid);
finish();
}
});
@@ -421,58 +422,64 @@ public void onClick(View v) {
final View restrictedAction = findViewById(R.id.restricted_action);
restrictedAction.setFilterTouchesWhenObscured(true);
- restrictedAction.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- if (!mActionButton.isEnabled()) {
- showPolicyTransparencyDialogIfRequired();
- return;
- }
- if (mAdding) {
- addAndFinish();
- } else if (isManagedProfile(mDeviceAdmin)
- && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) {
- final int userId = UserHandle.myUserId();
- UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- UserManager um = UserManager.get(DeviceAdminAdd.this);
- um.removeUser(userId);
- finish();
- }
+
+ final View.OnClickListener restrictedActionClickListener = v -> {
+ if (!mActionButton.isEnabled()) {
+ showPolicyTransparencyDialogIfRequired();
+ return;
+ }
+ if (mAdding) {
+ addAndFinish();
+ } else if (isManagedProfile(mDeviceAdmin)
+ && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) {
+ final int userId = UserHandle.myUserId();
+ UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ UserManager um = UserManager.get(DeviceAdminAdd.this);
+ um.removeUser(userId);
+ finish();
}
- ).show();
- } else if (mUninstalling) {
- mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName());
- finish();
- } else if (!mWaitingForRemoveMsg) {
- try {
- // Don't allow the admin to put a dialog up in front
- // of us while we interact with the user.
- ActivityManager.getService().stopAppSwitches();
- } catch (RemoteException e) {
- }
- mWaitingForRemoveMsg = true;
- mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
- new RemoteCallback(new RemoteCallback.OnResultListener() {
- @Override
- public void onResult(Bundle result) {
- CharSequence msg = result != null
- ? result.getCharSequence(
- DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
- : null;
- continueRemoveAction(msg);
- }
- }, mHandler));
- // Don't want to wait too long.
- getWindow().getDecorView().getHandler().postDelayed(new Runnable() {
- @Override public void run() {
- continueRemoveAction(null);
}
- }, 2*1000);
+ ).show();
+ } else if (mUninstalling) {
+ mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName());
+ finish();
+ } else if (!mWaitingForRemoveMsg) {
+ try {
+ // Don't allow the admin to put a dialog up in front
+ // of us while we interact with the user.
+ ActivityManager.getService().stopAppSwitches();
+ } catch (RemoteException e) {
}
+ mWaitingForRemoveMsg = true;
+ mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
+ new RemoteCallback(new RemoteCallback.OnResultListener() {
+ @Override
+ public void onResult(Bundle result) {
+ CharSequence msg = result != null
+ ? result.getCharSequence(
+ DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
+ : null;
+ continueRemoveAction(msg);
+ }
+ }, mHandler));
+ // Don't want to wait too long.
+ getWindow().getDecorView().getHandler().postDelayed(
+ () -> continueRemoveAction(null), 2 * 1000);
+ }
+ };
+ restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> {
+ if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) {
+ Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app.");
+ // Consume event to suppress click.
+ return true;
}
+ // Fallback to view click handler.
+ return false;
});
+ restrictedAction.setOnClickListener(restrictedActionClickListener);
}
/**

View File

@ -1,168 +0,0 @@
From b96ee4a2d1ec8c552af40820077fe85f9b2fa01f Mon Sep 17 00:00:00 2001
From: Ashish Kumar <akgaurav@google.com>
Date: Fri, 26 May 2023 14:18:46 +0000
Subject: [PATCH] Fixed leak of cross user data in multiple settings.
- Any app is allowed to receive GET_CONTENT intent. Using this, an user puts back in the intent an uri with data of another user.
- Telephony service has INTERACT_ACROSS_USER permission. Using this, it reads and shows the deta to the evil user.
Fix: When telephony service gets the intent result, it checks if the uri is from the current user or not.
Bug: b/256591023 , b/256819787
Test: The malicious behaviour was not being reproduced. Unable to import contact from other users data.
Test2: Able to import contact from the primary user or uri with no user id
(These settings are not available for secondary users)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ab593467e900d4a6d25a34024a06195ae863f6dc)
Merged-In: I1e3a643f17948153aecc1d0df9ffd9619ad678c1
Change-Id: I1e3a643f17948153aecc1d0df9ffd9619ad678c1
---
src/com/android/phone/CdmaCallForwardOptions.java | 12 ++++++++++++
.../android/phone/GsmUmtsCallForwardOptions.java | 12 ++++++++++++
.../phone/settings/VoicemailSettingsActivity.java | 14 ++++++++++++++
.../phone/settings/fdn/EditFdnContactScreen.java | 11 +++++++++++
4 files changed, 49 insertions(+)
diff --git a/src/com/android/phone/CdmaCallForwardOptions.java b/src/com/android/phone/CdmaCallForwardOptions.java
index a8d2e93d69..d70e7099b4 100644
--- a/src/com/android/phone/CdmaCallForwardOptions.java
+++ b/src/com/android/phone/CdmaCallForwardOptions.java
@@ -17,10 +17,13 @@
package com.android.phone;
import android.app.ActionBar;
+import android.content.ContentProvider;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.telephony.CarrierConfigManager;
@@ -212,6 +215,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
Cursor cursor = null;
try {
+ // check if the URI returned by the user belongs to the user
+ final int currentUser = UserHandle.getUserId(Process.myUid());
+ if (currentUser
+ != ContentProvider.getUserIdFromUri(data.getData(), currentUser)) {
+
+ Log.w(LOG_TAG, "onActivityResult: Contact data of different user, "
+ + "cannot access");
+ return;
+ }
cursor = getContentResolver().query(data.getData(),
NUM_PROJECTION, null, null, null);
if ((cursor == null) || (!cursor.moveToFirst())) {
diff --git a/src/com/android/phone/GsmUmtsCallForwardOptions.java b/src/com/android/phone/GsmUmtsCallForwardOptions.java
index fda0ea5265..db830deb66 100644
--- a/src/com/android/phone/GsmUmtsCallForwardOptions.java
+++ b/src/com/android/phone/GsmUmtsCallForwardOptions.java
@@ -1,10 +1,13 @@
package com.android.phone;
import android.app.ActionBar;
+import android.content.ContentProvider;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.telephony.CarrierConfigManager;
@@ -203,6 +206,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
Cursor cursor = null;
try {
+ // check if the URI returned by the user belongs to the user
+ final int currentUser = UserHandle.getUserId(Process.myUid());
+ if (currentUser
+ != ContentProvider.getUserIdFromUri(data.getData(), currentUser)) {
+
+ Log.w(LOG_TAG, "onActivityResult: Contact data of different user, "
+ + "cannot access");
+ return;
+ }
cursor = getContentResolver().query(data.getData(),
NUM_PROJECTION, null, null, null);
if ((cursor == null) || (!cursor.moveToFirst())) {
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index 02bf4b25d8..c940748a35 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -17,6 +17,7 @@
package com.android.phone.settings;
import android.app.Dialog;
+import android.content.ContentProvider;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
@@ -25,6 +26,8 @@
import android.os.Handler;
import android.os.Message;
import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceActivity;
@@ -520,6 +523,17 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Cursor cursor = null;
try {
+ // check if the URI returned by the user belongs to the user
+ final int currentUser = UserHandle.getUserId(Process.myUid());
+ if (currentUser
+ != ContentProvider.getUserIdFromUri(data.getData(), currentUser)) {
+
+ if (DBG) {
+ log("onActivityResult: Contact data of different user, "
+ + "cannot access");
+ }
+ return;
+ }
cursor = getContentResolver().query(data.getData(),
new String[] { CommonDataKinds.Phone.NUMBER }, null, null, null);
if ((cursor == null) || (!cursor.moveToFirst())) {
diff --git a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
index 468d38f65d..0884e1262d 100644
--- a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
@@ -19,6 +19,7 @@
import static android.app.Activity.RESULT_OK;
+import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Resources;
@@ -26,6 +27,8 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
import android.provider.ContactsContract.CommonDataKinds;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
@@ -137,6 +140,14 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
}
Cursor cursor = null;
try {
+ // check if the URI returned by the user belongs to the user
+ final int currentUser = UserHandle.getUserId(Process.myUid());
+ if (currentUser
+ != ContentProvider.getUserIdFromUri(intent.getData(), currentUser)) {
+ Log.w(LOG_TAG, "onActivityResult: Contact data of different user, "
+ + "cannot access");
+ return;
+ }
cursor = getContentResolver().query(intent.getData(),
NUM_PROJECTION, null, null, null);
if ((cursor == null) || (!cursor.moveToFirst())) {

View File

@ -85,10 +85,9 @@ patchWorkspaceReal() {
verifyAllPlatformTags; verifyAllPlatformTags;
gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview"; gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview";
source build/envsetup.sh; #source build/envsetup.sh;
#repopick -ift twelve-bt-sbc-hd-dualchannel; #repopick -ift twelve-bt-sbc-hd-dualchannel;
#repopick -it twelve-colors; #repopick -it twelve-colors;
repopick -it S_asb_2023-09;
sh "$DOS_SCRIPTS/Patch.sh"; sh "$DOS_SCRIPTS/Patch.sh";
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh"; sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";

View File

@ -127,12 +127,7 @@ if enterAndClear "external/webp"; then
applyPatch "$DOS_PATCHES/android_external_webp/CVE-2023-4863.patch"; #Fix OOB write in BuildHuffmanTable. applyPatch "$DOS_PATCHES/android_external_webp/CVE-2023-4863.patch"; #Fix OOB write in BuildHuffmanTable.
fi; fi;
if enterAndClear "frameworks/av"; then
git am $DOS_PATCHES/ASB2023-09/av-*.patch;
fi;
if enterAndClear "frameworks/base"; then if enterAndClear "frameworks/base"; then
git am $DOS_PATCHES/ASB2023-09/fwb-*.patch;
git revert --no-edit d36faad3267522c6d3ff91ba9dcca8f6274bccd1; #Reverts "JobScheduler: Respect allow-in-power-save perm" in favor of below patch git revert --no-edit d36faad3267522c6d3ff91ba9dcca8f6274bccd1; #Reverts "JobScheduler: Respect allow-in-power-save perm" in favor of below patch
git revert --no-edit 90d6826548189ca850d91692e71fcc1be426f453; #Reverts "Remove sensitive info from SUPL requests" in favor of below patch git revert --no-edit 90d6826548189ca850d91692e71fcc1be426f453; #Reverts "Remove sensitive info from SUPL requests" in favor of below patch
applyPatch "$DOS_PATCHES/android_frameworks_base/0007-Always_Restict_Serial.patch"; #Always restrict access to Build.SERIAL (GrapheneOS) applyPatch "$DOS_PATCHES/android_frameworks_base/0007-Always_Restict_Serial.patch"; #Always restrict access to Build.SERIAL (GrapheneOS)
@ -223,7 +218,6 @@ applyPatch "$DOS_PATCHES/android_frameworks_libs_systemui/0001-Icon_Cache.patch"
fi; fi;
if enterAndClear "frameworks/native"; then if enterAndClear "frameworks/native"; then
git am $DOS_PATCHES/ASB2023-09/native-*.patch;
applyPatch "$DOS_PATCHES/android_frameworks_native/0001-Sensors_Permission.patch"; #Require OTHER_SENSORS permission for sensors (GrapheneOS) applyPatch "$DOS_PATCHES/android_frameworks_native/0001-Sensors_Permission.patch"; #Require OTHER_SENSORS permission for sensors (GrapheneOS)
applyPatch "$DOS_PATCHES/android_frameworks_native/0001-Sensors_Permission-a1.patch"; #Protect step sensors with OTHER_SENSORS permission for targetSdk<29 apps (GrapheneOS) applyPatch "$DOS_PATCHES/android_frameworks_native/0001-Sensors_Permission-a1.patch"; #Protect step sensors with OTHER_SENSORS permission for targetSdk<29 apps (GrapheneOS)
fi; fi;
@ -304,7 +298,6 @@ cp -f "$DOS_PATCHES_COMMON/contributors.db" assets/contributors.db; #Update cont
fi; fi;
if enterAndClear "packages/apps/Nfc"; then if enterAndClear "packages/apps/Nfc"; then
git am $DOS_PATCHES/ASB2023-09/nfc-*.patch;
if [ "$DOS_GRAPHENE_CONSTIFY" = true ]; then applyPatch "$DOS_PATCHES/android_packages_apps_Nfc/0001-constify_JNINativeMethod.patch"; fi; #Constify JNINativeMethod tables (GrapheneOS) if [ "$DOS_GRAPHENE_CONSTIFY" = true ]; then applyPatch "$DOS_PATCHES/android_packages_apps_Nfc/0001-constify_JNINativeMethod.patch"; fi; #Constify JNINativeMethod tables (GrapheneOS)
fi; fi;
@ -313,7 +306,6 @@ applyPatch "$DOS_PATCHES/android_packages_apps_OpenEUICC/0001-hacky-fix.patch";
fi; fi;
if enterAndClear "packages/apps/Settings"; then if enterAndClear "packages/apps/Settings"; then
git am $DOS_PATCHES/ASB2023-09/settings-*.patch;
git revert --no-edit 41b4ed345a91da1dd46c00ee11a151c2b5ff4f43; git revert --no-edit 41b4ed345a91da1dd46c00ee11a151c2b5ff4f43;
applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0004-Private_DNS.patch"; #More 'Private DNS' options (heavily based off of a CalyxOS patch) applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0004-Private_DNS.patch"; #More 'Private DNS' options (heavily based off of a CalyxOS patch)
applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0005-Automatic_Reboot.patch"; #Timeout for reboot (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_apps_Settings/0005-Automatic_Reboot.patch"; #Timeout for reboot (GrapheneOS)
@ -342,7 +334,6 @@ git revert --no-edit fcf658d2005dc557a95d5a7fb89cb90d06b31d33; #grant permission
fi; fi;
if enterAndClear "packages/apps/Trebuchet"; then if enterAndClear "packages/apps/Trebuchet"; then
git am $DOS_PATCHES/ASB2023-09/launcher-*.patch;
cp $DOS_BUILD_BASE/vendor/divested/overlay/common/packages/apps/Trebuchet/res/xml/default_workspace_*.xml res/xml/; #XXX: Likely no longer needed cp $DOS_BUILD_BASE/vendor/divested/overlay/common/packages/apps/Trebuchet/res/xml/default_workspace_*.xml res/xml/; #XXX: Likely no longer needed
fi; fi;
@ -358,10 +349,6 @@ applyPatch "$DOS_PATCHES/android_packages_inputmethods_LatinIME/0001-Voice.patch
applyPatch "$DOS_PATCHES/android_packages_inputmethods_LatinIME/0002-Disable_Personalization.patch"; #Disable personalization dictionary by default (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_inputmethods_LatinIME/0002-Disable_Personalization.patch"; #Disable personalization dictionary by default (GrapheneOS)
fi; fi;
if enterAndClear "packages/modules/Bluetooth"; then
git am $DOS_PATCHES/ASB2023-09/bt-*.patch;
fi;
if enterAndClear "packages/modules/Connectivity"; then if enterAndClear "packages/modules/Connectivity"; then
applyPatch "$DOS_PATCHES/android_packages_modules_Connectivity/0001-Network_Permission-1.patch"; #Skip reportNetworkConnectivity() when permission is revoked (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_modules_Connectivity/0001-Network_Permission-1.patch"; #Skip reportNetworkConnectivity() when permission is revoked (GrapheneOS)
applyPatch "$DOS_PATCHES/android_packages_modules_Connectivity/0001-Network_Permission-2.patch"; #Enforce INTERNET permission per-uid instead of per-appId (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_modules_Connectivity/0001-Network_Permission-2.patch"; #Enforce INTERNET permission per-uid instead of per-appId (GrapheneOS)
@ -380,10 +367,6 @@ if enterAndClear "packages/modules/NetworkStack"; then
applyPatch "$DOS_PATCHES/android_packages_modules_NetworkStack/0001-Random_MAC.patch"; #Avoid reusing DHCP state for full MAC randomization (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_modules_NetworkStack/0001-Random_MAC.patch"; #Avoid reusing DHCP state for full MAC randomization (GrapheneOS)
fi; fi;
if enterAndClear "packages/modules/NeuralNetworks"; then
git am $DOS_PATCHES/ASB2023-09/nn-*.patch;
fi;
if enterAndClear "packages/modules/Permission"; then if enterAndClear "packages/modules/Permission"; then
applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0004-Special_Permissions-1.patch"; #Add special handling for INTERNET/OTHER_SENSORS (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0004-Special_Permissions-1.patch"; #Add special handling for INTERNET/OTHER_SENSORS (GrapheneOS)
applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0004-Special_Permissions-2.patch"; #Fix usage UI summary for Network/Sensors (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_modules_Permission/0004-Special_Permissions-2.patch"; #Fix usage UI summary for Network/Sensors (GrapheneOS)
@ -400,18 +383,10 @@ if enterAndClear "packages/providers/DownloadProvider"; then
applyPatch "$DOS_PATCHES/android_packages_providers_DownloadProvider/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS) applyPatch "$DOS_PATCHES/android_packages_providers_DownloadProvider/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS)
fi; fi;
if enterAndClear "packages/providers/MediaProvider"; then
git am $DOS_PATCHES/ASB2023-09/media-*.patch;
fi;
#if enterAndClear "packages/providers/TelephonyProvider"; then #if enterAndClear "packages/providers/TelephonyProvider"; then
#cp $DOS_PATCHES_COMMON/android_packages_providers_TelephonyProvider/carrier_list.* assets/latest_carrier_id/; #cp $DOS_PATCHES_COMMON/android_packages_providers_TelephonyProvider/carrier_list.* assets/latest_carrier_id/;
#fi; #fi;
if enterAndClear "packages/services/Telephony"; then
git am $DOS_PATCHES/ASB2023-09/telephony-*.patch;
fi;
if enterAndClear "system/ca-certificates"; then if enterAndClear "system/ca-certificates"; then
rm -rf files; #Remove old certs rm -rf files; #Remove old certs
cp -r "$DOS_PATCHES_COMMON/android_system_ca-certificates/files" .; #Copy the new ones into place cp -r "$DOS_PATCHES_COMMON/android_system_ca-certificates/files" .; #Copy the new ones into place