|
|
a3e2b5 |
From 38a5ae776dc62b42ef5ced8f9812771181af528b Mon Sep 17 00:00:00 2001
|
|
|
a3e2b5 |
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
|
|
a3e2b5 |
Date: Thu, 2 Aug 2018 14:25:11 +0200
|
|
|
a3e2b5 |
Subject: [PATCH] bus-message: fix calculation of offsets table
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
The offsets specify the ends of variable length data. We would trust the
|
|
|
a3e2b5 |
incoming data, putting the offsets specified in our message
|
|
|
a3e2b5 |
into the offsets tables after doing some superficial verification.
|
|
|
a3e2b5 |
But when actually reading the data we apply alignment, so we would take
|
|
|
a3e2b5 |
the previous offset, align it, making it bigger then current offset, and
|
|
|
a3e2b5 |
then we'd try to read data of negative length.
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
In the attached example, the message specifies the following offsets:
|
|
|
a3e2b5 |
[1, 4]
|
|
|
a3e2b5 |
but the alignment of those items is
|
|
|
a3e2b5 |
[1, 8]
|
|
|
a3e2b5 |
so we'd calculate the second item as starting at 8 and ending at 4.
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
(cherry picked from commit 12603b84d2fb07603e2ea94b240c6b78ad17510e)
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
Resolves: #1696224
|
|
|
a3e2b5 |
---
|
|
|
a3e2b5 |
src/libsystemd/sd-bus/bus-message.c | 36 +++++++++---------
|
|
|
a3e2b5 |
...h-e1b811da5ca494e494b77c6bd8e1c2f2989425c5 | Bin 0 -> 28 bytes
|
|
|
a3e2b5 |
2 files changed, 18 insertions(+), 18 deletions(-)
|
|
|
a3e2b5 |
create mode 100644 test/fuzz/fuzz-bus-message/crash-e1b811da5ca494e494b77c6bd8e1c2f2989425c5
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
|
|
|
a3e2b5 |
index 81aaa7f59f..d0af34f632 100644
|
|
|
a3e2b5 |
--- a/src/libsystemd/sd-bus/bus-message.c
|
|
|
a3e2b5 |
+++ b/src/libsystemd/sd-bus/bus-message.c
|
|
|
a3e2b5 |
@@ -3140,6 +3140,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
|
|
|
a3e2b5 |
assert(alignment > 0);
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
|
|
|
a3e2b5 |
+ assert(c->offsets[c->offset_index+1] >= *rindex);
|
|
|
a3e2b5 |
c->item_size = c->offsets[c->offset_index+1] - *rindex;
|
|
|
a3e2b5 |
} else {
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
@@ -3179,6 +3180,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
|
|
|
a3e2b5 |
assert(alignment > 0);
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
|
|
|
a3e2b5 |
+ assert(c->offsets[c->offset_index+1] >= *rindex);
|
|
|
a3e2b5 |
c->item_size = c->offsets[c->offset_index+1] - *rindex;
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
c->offset_index++;
|
|
|
a3e2b5 |
@@ -3725,7 +3727,7 @@ static int build_struct_offsets(
|
|
|
a3e2b5 |
size_t *n_offsets) {
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
unsigned n_variable = 0, n_total = 0, v;
|
|
|
a3e2b5 |
- size_t previous = 0, where;
|
|
|
a3e2b5 |
+ size_t previous, where;
|
|
|
a3e2b5 |
const char *p;
|
|
|
a3e2b5 |
size_t sz;
|
|
|
a3e2b5 |
void *q;
|
|
|
a3e2b5 |
@@ -3804,6 +3806,7 @@ static int build_struct_offsets(
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
/* Second, loop again and build an offset table */
|
|
|
a3e2b5 |
p = signature;
|
|
|
a3e2b5 |
+ previous = m->rindex;
|
|
|
a3e2b5 |
while (*p != 0) {
|
|
|
a3e2b5 |
size_t n, offset;
|
|
|
a3e2b5 |
int k;
|
|
|
a3e2b5 |
@@ -3817,37 +3820,34 @@ static int build_struct_offsets(
|
|
|
a3e2b5 |
memcpy(t, p, n);
|
|
|
a3e2b5 |
t[n] = 0;
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
+ size_t align = bus_gvariant_get_alignment(t);
|
|
|
a3e2b5 |
+ assert(align > 0);
|
|
|
a3e2b5 |
+
|
|
|
a3e2b5 |
+ /* The possible start of this member after including alignment */
|
|
|
a3e2b5 |
+ size_t start = ALIGN_TO(previous, align);
|
|
|
a3e2b5 |
+
|
|
|
a3e2b5 |
k = bus_gvariant_get_size(t);
|
|
|
a3e2b5 |
if (k < 0) {
|
|
|
a3e2b5 |
size_t x;
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
- /* variable size */
|
|
|
a3e2b5 |
+ /* Variable size */
|
|
|
a3e2b5 |
if (v > 0) {
|
|
|
a3e2b5 |
v--;
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
|
|
|
a3e2b5 |
if (x >= size)
|
|
|
a3e2b5 |
return -EBADMSG;
|
|
|
a3e2b5 |
- if (m->rindex + x < previous)
|
|
|
a3e2b5 |
- return -EBADMSG;
|
|
|
a3e2b5 |
} else
|
|
|
a3e2b5 |
- /* The last item's end
|
|
|
a3e2b5 |
- * is determined from
|
|
|
a3e2b5 |
- * the start of the
|
|
|
a3e2b5 |
- * offset array */
|
|
|
a3e2b5 |
+ /* The last item's end is determined
|
|
|
a3e2b5 |
+ * from the start of the offset array */
|
|
|
a3e2b5 |
x = size - (n_variable * sz);
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
offset = m->rindex + x;
|
|
|
a3e2b5 |
-
|
|
|
a3e2b5 |
- } else {
|
|
|
a3e2b5 |
- size_t align;
|
|
|
a3e2b5 |
-
|
|
|
a3e2b5 |
- /* fixed size */
|
|
|
a3e2b5 |
- align = bus_gvariant_get_alignment(t);
|
|
|
a3e2b5 |
- assert(align > 0);
|
|
|
a3e2b5 |
-
|
|
|
a3e2b5 |
- offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
|
|
|
a3e2b5 |
- }
|
|
|
a3e2b5 |
+ if (offset < start)
|
|
|
a3e2b5 |
+ return -EBADMSG;
|
|
|
a3e2b5 |
+ } else
|
|
|
a3e2b5 |
+ /* Fixed size */
|
|
|
a3e2b5 |
+ offset = start + k;
|
|
|
a3e2b5 |
}
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
previous = (*offsets)[(*n_offsets)++] = offset;
|
|
|
a3e2b5 |
diff --git a/test/fuzz/fuzz-bus-message/crash-e1b811da5ca494e494b77c6bd8e1c2f2989425c5 b/test/fuzz/fuzz-bus-message/crash-e1b811da5ca494e494b77c6bd8e1c2f2989425c5
|
|
|
a3e2b5 |
new file mode 100644
|
|
|
a3e2b5 |
index 0000000000000000000000000000000000000000..9d3fa0035fd360a37833e8b58cc4aea90df9de83
|
|
|
a3e2b5 |
GIT binary patch
|
|
|
a3e2b5 |
literal 28
|
|
|
a3e2b5 |
fcmd1#|DTDG0Z1?a!8`>PAeqj{pplqVrYQgbfcytC
|
|
|
a3e2b5 |
|
|
|
a3e2b5 |
literal 0
|
|
|
a3e2b5 |
HcmV?d00001
|
|
|
a3e2b5 |
|