]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bus-message: fix negative offset with ~empty message
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 20 May 2020 07:05:17 +0000 (09:05 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 20 May 2020 07:33:54 +0000 (09:33 +0200)
In the linked reproducer, m->fields_size == 0, and we calculate ri == -1, which
of course doesn't end well. Skip the whole calculation if m->fields_size == 0,
and also check that we don't go negative even if it is non-zero.

Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19446 and #15583.

src/libsystemd/sd-bus/bus-message.c
test/fuzz/fuzz-bus-message/oss-fuzz-19446 [new file with mode: 0644]

index 0af9cedf5a14183be46ece70794305f33cf0c34e..0b6ea996ec2fcaff1ad2de1159ad526e1345e26c 100644 (file)
@@ -5202,29 +5202,34 @@ int bus_message_parse_fields(sd_bus_message *m) {
                  * table */
                 m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
 
-                /* Pull out the offset table for the fields array */
-                sz = bus_gvariant_determine_word_size(m->fields_size, 0);
-                if (sz > 0) {
-                        size_t framing;
-                        void *q;
+                /* Pull out the offset table for the fields array, if any */
+                if (m->fields_size > 0) {
+                        sz = bus_gvariant_determine_word_size(m->fields_size, 0);
+                        if (sz > 0) {
+                                size_t framing;
+                                void *q;
+
+                                if (m->fields_size < sz)
+                                        return -EBADMSG;
 
-                        ri = m->fields_size - sz;
-                        r = message_peek_fields(m, &ri, 1, sz, &q);
-                        if (r < 0)
-                                return r;
+                                ri = m->fields_size - sz;
+                                r = message_peek_fields(m, &ri, 1, sz, &q);
+                                if (r < 0)
+                                        return r;
 
-                        framing = bus_gvariant_read_word_le(q, sz);
-                        if (framing >= m->fields_size - sz)
-                                return -EBADMSG;
-                        if ((m->fields_size - framing) % sz != 0)
-                                return -EBADMSG;
+                                framing = bus_gvariant_read_word_le(q, sz);
+                                if (framing >= m->fields_size - sz)
+                                        return -EBADMSG;
+                                if ((m->fields_size - framing) % sz != 0)
+                                        return -EBADMSG;
 
-                        ri = framing;
-                        r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
-                        if (r < 0)
-                                return r;
+                                ri = framing;
+                                r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
+                                if (r < 0)
+                                        return r;
 
-                        n_offsets = (m->fields_size - framing) / sz;
+                                n_offsets = (m->fields_size - framing) / sz;
+                        }
                 }
         } else
                 m->user_body_size = m->body_size;
diff --git a/test/fuzz/fuzz-bus-message/oss-fuzz-19446 b/test/fuzz/fuzz-bus-message/oss-fuzz-19446
new file mode 100644 (file)
index 0000000..f937ef8
Binary files /dev/null and b/test/fuzz/fuzz-bus-message/oss-fuzz-19446 differ