|
@@ -0,0 +1,227 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: VerteDinde <[email protected]>
|
|
|
+Date: Thu, 30 Nov 2023 20:33:02 -0800
|
|
|
+Subject: Remove potential out of bound access to alphaItemIndices
|
|
|
+
|
|
|
+Manual cherry-pick of PR #1756 into the chromium-m118 branch.
|
|
|
+
|
|
|
+diff --git a/include/avif/internal.h b/include/avif/internal.h
|
|
|
+index 0d3651fb4fb26baafc756b0033141e50495d9127..8562dce8bb93bee9f151b0321d41692f0a62ea9c 100644
|
|
|
+--- a/include/avif/internal.h
|
|
|
++++ b/include/avif/internal.h
|
|
|
+@@ -397,6 +397,19 @@ __attribute__((__format__(__printf__, 2, 3)))
|
|
|
+ #endif
|
|
|
+ void avifDiagnosticsPrintf(avifDiagnostics * diag, const char * format, ...);
|
|
|
+
|
|
|
++// ---------------------------------------------------------------------------
|
|
|
++// avifCodecType (underlying video format)
|
|
|
++
|
|
|
++// Alliance for Open Media video formats that can be used in the AVIF image format.
|
|
|
++typedef enum avifCodecType
|
|
|
++{
|
|
|
++ AVIF_CODEC_TYPE_UNKNOWN,
|
|
|
++ AVIF_CODEC_TYPE_AV1,
|
|
|
++#if defined(AVIF_CODEC_AVM)
|
|
|
++ AVIF_CODEC_TYPE_AV2, // Experimental.
|
|
|
++#endif
|
|
|
++} avifCodecType;
|
|
|
++
|
|
|
+ // ---------------------------------------------------------------------------
|
|
|
+ // avifStream
|
|
|
+ //
|
|
|
+diff --git a/src/read.c b/src/read.c
|
|
|
+index 36a9058abfda94b623609e5ffff5fac2e48d8701..756af390f451eb7e7422248ddc0b3e88e1640a94 100644
|
|
|
+--- a/src/read.c
|
|
|
++++ b/src/read.c
|
|
|
+@@ -37,6 +37,23 @@ static const size_t xmpContentTypeSize = sizeof(xmpContentType);
|
|
|
+ // can't be more than 4 unique tuples right now.
|
|
|
+ #define MAX_IPMA_VERSION_AND_FLAGS_SEEN 4
|
|
|
+
|
|
|
++// ---------------------------------------------------------------------------
|
|
|
++// AVIF codec type (AV1 or AV2)
|
|
|
++
|
|
|
++static avifCodecType avifGetCodecType(const uint8_t * fourcc)
|
|
|
++{
|
|
|
++ if (!memcmp(fourcc, "av01", 4)) {
|
|
|
++ return AVIF_CODEC_TYPE_AV1;
|
|
|
++ }
|
|
|
++#if defined(AVIF_CODEC_AVM)
|
|
|
++ if (!memcmp(fourcc, "av02", 4)) {
|
|
|
++ return AVIF_CODEC_TYPE_AV2;
|
|
|
++ }
|
|
|
++#endif
|
|
|
++ return AVIF_CODEC_TYPE_UNKNOWN;
|
|
|
++}
|
|
|
++
|
|
|
++
|
|
|
+ // ---------------------------------------------------------------------------
|
|
|
+ // Box data structures
|
|
|
+
|
|
|
+@@ -1267,7 +1284,7 @@ static avifBool avifDecoderGenerateImageGridTiles(avifDecoder * decoder, avifIma
|
|
|
+
|
|
|
+ if (tilesRequested != tilesAvailable) {
|
|
|
+ avifDiagnosticsPrintf(&decoder->diag,
|
|
|
+- "Grid image of dimensions %ux%u requires %u tiles, and only %u were found",
|
|
|
++ "Grid image of dimensions %ux%u requires %u tiles, but %u were found",
|
|
|
+ grid->columns,
|
|
|
+ grid->rows,
|
|
|
+ tilesRequested,
|
|
|
+@@ -3465,6 +3482,135 @@ static avifDecoderItem * avifDecoderDataFindItem(avifDecoderData * data, avifBoo
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
++// Returns AVIF_TRUE if item is an alpha auxiliary item of the parent color
|
|
|
++// item.
|
|
|
++static avifBool avifDecoderItemIsAlphaAux(avifDecoderItem * item, uint32_t colorItemId)
|
|
|
++{
|
|
|
++ if (item->auxForID != colorItemId)
|
|
|
++ return AVIF_FALSE;
|
|
|
++ const avifProperty * auxCProp = avifPropertyArrayFind(&item->properties, "auxC");
|
|
|
++ return auxCProp && isAlphaURN(auxCProp->u.auxC.auxType);
|
|
|
++}
|
|
|
++
|
|
|
++// Returns AVIF_TRUE if the item should be skipped. Items should be skipped for one of the following reasons:
|
|
|
++// * Size is 0.
|
|
|
++// * Has an essential property that isn't supported by libavif.
|
|
|
++// * Item is not a single image or a grid.
|
|
|
++// * Item is a thumbnail.
|
|
|
++static avifBool avifDecoderItemShouldBeSkipped(const avifDecoderItem * item)
|
|
|
++{
|
|
|
++ return !item->size || item->hasUnsupportedEssentialProperty ||
|
|
|
++ (avifGetCodecType(item->type) == AVIF_CODEC_TYPE_UNKNOWN && memcmp(item->type, "grid", 4)) || item->thumbnailForID != 0;
|
|
|
++}
|
|
|
++
|
|
|
++// Finds the alpha item whose parent item is *colorItemPtr and sets it in the alphaItem output parameter. Returns AVIF_RESULT_OK
|
|
|
++// on success. Note that *alphaItem can be NULL even if the return value is AVIF_RESULT_OK. If the *colorItemPtr is a grid and the
|
|
|
++// alpha item is represented as a set of auxl items to each color tile, then a fake item will be created and *isAlphaItemInInput
|
|
|
++// will be set to AVIF_FALSE. In this case, the alpha item merely exists to hold the locations of the alpha tile items. The data
|
|
|
++// of this item need not be read and the pixi property cannot be validated. Otherwise, *isAlphaItemInInput will be set to
|
|
|
++// AVIF_TRUE when *alphaItem is not NULL. If the data->meta->items array is resized, then the value in *colorItemPtr could become
|
|
|
++// invalid. This function also resets *colorItemPtr to the right value if an alpha item was found and added to the data->meta->items
|
|
|
++// array.
|
|
|
++static avifResult avifDecoderDataFindAlphaItem(avifDecoderData * data,
|
|
|
++ avifDecoderItem ** colorItemPtr,
|
|
|
++ avifDecoderItem ** alphaItem,
|
|
|
++ avifBool * isAlphaItemInInput)
|
|
|
++{
|
|
|
++ const avifDecoderItem * colorItem = *colorItemPtr;
|
|
|
++ for (uint32_t itemIndex = 0; itemIndex < data->meta->items.count; ++itemIndex) {
|
|
|
++ avifDecoderItem * item = &data->meta->items.item[itemIndex];
|
|
|
++ if (avifDecoderItemShouldBeSkipped(item)) {
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++ if (avifDecoderItemIsAlphaAux(item, colorItem->id)) {
|
|
|
++ *alphaItem = item;
|
|
|
++ *isAlphaItemInInput = AVIF_TRUE;
|
|
|
++ return AVIF_RESULT_OK;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ if (memcmp(colorItem->type, "grid", 4)) {
|
|
|
++ *alphaItem = NULL;
|
|
|
++ *isAlphaItemInInput = AVIF_FALSE;
|
|
|
++ return AVIF_RESULT_OK;
|
|
|
++ }
|
|
|
++ // If color item is a grid, check if there is an alpha channel which is represented as an auxl item to each color tile
|
|
|
++ // item.
|
|
|
++ uint32_t colorItemCount = data->color.grid.rows * data->color.grid.columns;
|
|
|
++ if (colorItemCount == 0) {
|
|
|
++ *alphaItem = NULL;
|
|
|
++ *isAlphaItemInInput = AVIF_FALSE;
|
|
|
++ return AVIF_RESULT_OK;
|
|
|
++ }
|
|
|
++ uint32_t * alphaItemIndices = avifAlloc(colorItemCount * sizeof(uint32_t));
|
|
|
++ AVIF_CHECKERR(alphaItemIndices, AVIF_RESULT_OUT_OF_MEMORY);
|
|
|
++ uint32_t alphaItemCount = 0;
|
|
|
++ uint32_t maxItemID = 0;
|
|
|
++ for (uint32_t i = 0; i < colorItem->meta->items.count; ++i) {
|
|
|
++ avifDecoderItem * item = &colorItem->meta->items.item[i];
|
|
|
++ if (item->id > maxItemID) {
|
|
|
++ maxItemID = item->id;
|
|
|
++ }
|
|
|
++ if (item->dimgForID == colorItem->id) {
|
|
|
++ avifBool seenAlphaForCurrentItem = AVIF_FALSE;
|
|
|
++ for (uint32_t j = 0; j < colorItem->meta->items.count; ++j) {
|
|
|
++ avifDecoderItem * auxlItem = &colorItem->meta->items.item[j];
|
|
|
++ if (avifDecoderItemIsAlphaAux(auxlItem, item->id)) {
|
|
|
++ if (seenAlphaForCurrentItem || auxlItem->dimgForID != 0) {
|
|
|
++ // One of the following invalid cases:
|
|
|
++ // * Multiple items are claiming to be the alpha auxiliary of the current item.
|
|
|
++ // * Alpha auxiliary is dimg for another item.
|
|
|
++ avifFree(alphaItemIndices);
|
|
|
++ *alphaItem = NULL;
|
|
|
++ *isAlphaItemInInput = AVIF_FALSE;
|
|
|
++ return AVIF_RESULT_INVALID_IMAGE_GRID;
|
|
|
++ }
|
|
|
++ alphaItemIndices[alphaItemCount++] = j;
|
|
|
++ seenAlphaForCurrentItem = AVIF_TRUE;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ if (!seenAlphaForCurrentItem) {
|
|
|
++ // No alpha auxiliary item was found for the current item. Treat this as an image without alpha.
|
|
|
++ avifFree(alphaItemIndices);
|
|
|
++ *alphaItem = NULL;
|
|
|
++ *isAlphaItemInInput = AVIF_FALSE;
|
|
|
++ return AVIF_RESULT_OK;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ }
|
|
|
++ assert(alphaItemCount == colorItemCount);
|
|
|
++
|
|
|
++ int colorItemIndex = -1;
|
|
|
++ for (uint32_t i = 0; i < data->meta->items.count; ++i) {
|
|
|
++ if (colorItem->id == data->meta->items.item[i].id) {
|
|
|
++ colorItemIndex = i;
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ assert(colorItemIndex >= 0);
|
|
|
++
|
|
|
++ *alphaItem = avifMetaFindItem(colorItem->meta, maxItemID + 1);
|
|
|
++ if (*alphaItem == NULL) {
|
|
|
++ avifFree(alphaItemIndices);
|
|
|
++ *isAlphaItemInInput = AVIF_FALSE;
|
|
|
++ return AVIF_RESULT_OUT_OF_MEMORY;
|
|
|
++ }
|
|
|
++ // avifMetaFindItem() could invalidate all existing item pointers. So reset the colorItem pointers.
|
|
|
++ *colorItemPtr = &data->meta->items.item[colorItemIndex];
|
|
|
++ colorItem = *colorItemPtr;
|
|
|
++
|
|
|
++ memcpy((*alphaItem)->type, "grid", 4);
|
|
|
++ (*alphaItem)->width = colorItem->width;
|
|
|
++ (*alphaItem)->height = colorItem->height;
|
|
|
++ for (uint32_t i = 0; i < alphaItemCount; ++i) {
|
|
|
++ avifDecoderItem * item = &colorItem->meta->items.item[alphaItemIndices[i]];
|
|
|
++ item->dimgForID = (*alphaItem)->id;
|
|
|
++ }
|
|
|
++ avifFree(alphaItemIndices);
|
|
|
++ *isAlphaItemInInput = AVIF_FALSE;
|
|
|
++ data->alpha.grid = data->color.grid;
|
|
|
++ return AVIF_RESULT_OK;
|
|
|
++}
|
|
|
++
|
|
|
+ static avifResult avifDecoderGenerateImageTiles(avifDecoder * decoder, avifTileInfo * info, avifDecoderItem * item, avifBool alpha)
|
|
|
+ {
|
|
|
+ const uint32_t previousTileCount = decoder->data->tiles.count;
|
|
|
+@@ -3682,9 +3828,21 @@ avifResult avifDecoderReset(avifDecoder * decoder)
|
|
|
+ decoder->imageDimensionLimit,
|
|
|
+ data->diag),
|
|
|
+ AVIF_RESULT_INVALID_IMAGE_GRID);
|
|
|
++ // Validate that there are exactly the same number of dimg items to form the grid.
|
|
|
++ uint32_t dimgItemCount = 0;
|
|
|
++ for (uint32_t i = 0; i < colorItem->meta->items.count; ++i) {
|
|
|
++ if (colorItem->meta->items.item[i].dimgForID == colorItem->id) {
|
|
|
++ ++dimgItemCount;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ if (dimgItemCount != data->color.grid.rows * data->color.grid.columns) {
|
|
|
++ return AVIF_RESULT_INVALID_IMAGE_GRID;
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+- avifDecoderItem * alphaItem = avifDecoderDataFindItem(data, /*alpha=*/AVIF_TRUE, /*parentItemID=*/colorItem->id);
|
|
|
++ avifBool isAlphaItemInInput;
|
|
|
++ avifDecoderItem * alphaItem;
|
|
|
++ AVIF_CHECKRES(avifDecoderDataFindAlphaItem(data, &colorItem, &alphaItem, &isAlphaItemInInput));
|
|
|
+ if (alphaItem && !memcmp(alphaItem->type, "grid", 4)) {
|
|
|
+ avifROData readData;
|
|
|
+ AVIF_CHECKRES(avifDecoderItemRead(alphaItem, decoder->io, &readData, 0, 0, data->diag));
|