xcf: Make sure offsets are not negative

It's not a huge problem since QIODevice::seek() is a noop on negative values but it's
just better to bail out as soon as possible when we realize the file is
broken
This commit is contained in:
Albert Astals Cid 2021-05-05 17:21:29 +02:00
parent 780f342825
commit ff53d3d7e9

View File

@ -627,12 +627,17 @@ bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
QStack<qint64> layer_offsets;
while (true) {
qint64 layer_offset = readOffsetPtr(xcf_io);
const qint64 layer_offset = readOffsetPtr(xcf_io);
if (layer_offset == 0) {
break;
}
if (layer_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer offset";
return false;
}
layer_offsets.push(layer_offset);
}
@ -889,6 +894,16 @@ bool XCFImageFormat::loadLayer(QDataStream &xcf_io, XCFImage &xcf_image)
layer.hierarchy_offset = readOffsetPtr(xcf_io);
layer.mask_offset = readOffsetPtr(xcf_io);
if (layer.hierarchy_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer hierarchy_offset";
return false;
}
if (layer.mask_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer mask_offset";
return false;
}
// Allocate the individual tile QImages based on the size and type
// of this layer.
@ -1304,10 +1319,15 @@ bool XCFImageFormat::loadHierarchy(QDataStream &xcf_io, Layer &layer)
quint32 bpp;
xcf_io >> width >> height >> bpp;
qint64 offset = readOffsetPtr(xcf_io);
const qint64 offset = readOffsetPtr(xcf_io);
qCDebug(XCFPLUGIN) << "width" << width << "height" << height << "bpp" << bpp << "offset" << offset;
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative hierarchy offset";
return false;
}
const bool isMask = layer.assignBytes == assignMaskBytes;
// make sure bpp is correct and complain if it is not
@ -1408,6 +1428,11 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
xcf_io >> width >> height;
qint64 offset = readOffsetPtr(xcf_io);
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
if (offset == 0) {
// offset 0 with rowsxcols != 0 is probably an error since it means we have tiles
// without data but just clear the bits for now instead of returning false
@ -1432,6 +1457,11 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
qint64 saved_pos = xcf_io.device()->pos();
qint64 offset2 = readOffsetPtr(xcf_io);
if (offset2 < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
// Evidently, RLE can occasionally expand a tile instead of compressing it!
if (offset2 == 0) {
offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
@ -1477,6 +1507,11 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
xcf_io.device()->seek(saved_pos);
offset = readOffsetPtr(xcf_io);
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
}
}
@ -1503,7 +1538,12 @@ bool XCFImageFormat::loadMask(QDataStream &xcf_io, Layer &layer)
return false;
}
qint64 hierarchy_offset = readOffsetPtr(xcf_io);
const qint64 hierarchy_offset = readOffsetPtr(xcf_io);
if (hierarchy_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative mask hierarchy_offset";
return false;
}
xcf_io.device()->seek(hierarchy_offset);
layer.assignBytes = assignMaskBytes;