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; QStack<qint64> layer_offsets;
while (true) { while (true) {
qint64 layer_offset = readOffsetPtr(xcf_io); const qint64 layer_offset = readOffsetPtr(xcf_io);
if (layer_offset == 0) { if (layer_offset == 0) {
break; break;
} }
if (layer_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer offset";
return false;
}
layer_offsets.push(layer_offset); 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.hierarchy_offset = readOffsetPtr(xcf_io);
layer.mask_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 // Allocate the individual tile QImages based on the size and type
// of this layer. // of this layer.
@ -1304,10 +1319,15 @@ bool XCFImageFormat::loadHierarchy(QDataStream &xcf_io, Layer &layer)
quint32 bpp; quint32 bpp;
xcf_io >> width >> height >> 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; 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; const bool isMask = layer.assignBytes == assignMaskBytes;
// make sure bpp is correct and complain if it is not // 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; xcf_io >> width >> height;
qint64 offset = readOffsetPtr(xcf_io); qint64 offset = readOffsetPtr(xcf_io);
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
if (offset == 0) { if (offset == 0) {
// offset 0 with rowsxcols != 0 is probably an error since it means we have tiles // 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 // 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 saved_pos = xcf_io.device()->pos();
qint64 offset2 = readOffsetPtr(xcf_io); 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! // Evidently, RLE can occasionally expand a tile instead of compressing it!
if (offset2 == 0) { if (offset2 == 0) {
offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5); 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); xcf_io.device()->seek(saved_pos);
offset = readOffsetPtr(xcf_io); 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; 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); xcf_io.device()->seek(hierarchy_offset);
layer.assignBytes = assignMaskBytes; layer.assignBytes = assignMaskBytes;