2022-05-25 01:20:13

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 2/2] monitor/att: Fix parsing of notifications

From: Luiz Augusto von Dentz <[email protected]>

If there are multiple notifications in the same frame the callback may
alter it when using l2cap_frame_pull helpers, so instead this passes a
cloned frame with just the expected length so callbacks cannot alter
original frame.
---
monitor/att.c | 10 ++++++++++
monitor/l2cap.h | 16 ++++++++++++----
2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/monitor/att.c b/monitor/att.c
index 27d4730fc..f4caca4ca 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -1547,6 +1547,7 @@ static void print_notify(const struct l2cap_frame *frame, uint16_t handle,
{
struct gatt_db_attribute *attr;
struct gatt_handler *handler;
+ struct l2cap_frame clone;

print_handle(frame, handle, false);
print_hex_field(" Data", frame->data, len);
@@ -1564,6 +1565,15 @@ static void print_notify(const struct l2cap_frame *frame, uint16_t handle,
if (!handler)
return;

+ /* Use a clone if the callback is not expected to parse the whole
+ * frame.
+ */
+ if (len != frame->size) {
+ l2cap_frame_clone(&clone, frame);
+ clone.size = len;
+ frame = &clone;
+ }
+
handler->notify(frame);
}

diff --git a/monitor/l2cap.h b/monitor/l2cap.h
index 19e03637a..38d40716b 100644
--- a/monitor/l2cap.h
+++ b/monitor/l2cap.h
@@ -31,11 +31,9 @@ void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in,
uint16_t cid, uint16_t psm,
const void *data, uint16_t size);

-static inline void *l2cap_frame_pull(struct l2cap_frame *frame,
- const struct l2cap_frame *source, uint16_t len)
+static inline void l2cap_frame_clone(struct l2cap_frame *frame,
+ const struct l2cap_frame *source)
{
- void *data;
-
if (frame != source) {
frame->index = source->index;
frame->in = source->in;
@@ -45,7 +43,17 @@ static inline void *l2cap_frame_pull(struct l2cap_frame *frame,
frame->psm = source->psm;
frame->chan = source->chan;
frame->mode = source->mode;
+ frame->data = source->data;
+ frame->size = source->size;
}
+}
+
+static inline void *l2cap_frame_pull(struct l2cap_frame *frame,
+ const struct l2cap_frame *source, uint16_t len)
+{
+ void *data;
+
+ l2cap_frame_clone(frame, source);

if (source->size < len)
return NULL;
--
2.35.1