(CVE-2023-29499) GVariant offset table entry size is not checked in is_normal()
Splitting out from this comment in issue #2121:
Another one:
For type aay the normal form serialization of
[[], [], [], ..., []]
with 128 zero-length arrays isb'\0\0\0...\0'
with 128 NUL characters. In Python this is:>>> GLib.Variant("aay", [[]] * 128).get_data_as_bytes().get_data() == '\0' * 128
This works fine. The serialised data consists of 128
guint8
framing offsets, each 1B long, all with the value 0. So there are 128 instances of "ay".Interestingly
'\0' * 256
is also[[]] * 128
. This is because it consists of 128guint16
framing offsets, each 2B long. So there are 128 instances of "ay". This is a valid representation of the data, but is not in normal form. The spec says:
When serialising, the proper framing offset size must be determined by “trial and error” — checking each size to determine if it will work. It is possible, since the size of the offsets is included in the size of the container, that having larger offsets might bump the size of the container up into the next category, which would then require larger offsets. Such containers, however, would not be considered to be in “normal form”. The smallest possible offset size must be used if the serialised data is to be in normal form.
The GLib GVariant implementation serializes correctly, but I think there is a bug in
g_variant_is_normal_form
. In Python:>>> GLib.Variant.new_from_bytes( ... GLib.VariantType.new("aay"), ... GLib.Bytes.new(b'\0' * 256), ... False).is_normal_form() True
This is incorrect, it should be
False
.Calling
g_variant_get_normal_form
doesn't help>>> len(GLib.Variant.new_from_bytes( ... GLib.VariantType.new("aay"), GLib.Bytes.new(b'\0' * 256), ... False).get_normal_form().get_data_as_bytes().get_data()) 256
I can confirm this is a bug and I have a fix underway.