Browse Source

chore: [25-x-y] cherry-pick 2 changes from Release-3-M119 (#40671)

* b2d36b1c3bfc from libavif
* 922fca786b61a from libavif
Keeley Hammond 1 year ago
parent
commit
69fe268d4d

+ 2 - 0
patches/config.json

@@ -25,6 +25,8 @@
 
   "src/electron/patches/skia": "src/third_party/skia",
 
+  "src/electron/patches/libavif": "src/third_party/libavif/src",
+
   "src/electron/patches/libwebp": "src/third_party/libwebp/src",
 
   "src/electron/patches/libvpx": "src/third_party/libvpx/source/libvpx",

+ 2 - 0
patches/libavif/.patches

@@ -0,0 +1,2 @@
+remove_potential_out_of_bound_access_to_alphaitemindices.patch
+do_not_store_potentially_invalid_pointers.patch

+ 79 - 0
patches/libavif/do_not_store_potentially_invalid_pointers.patch

@@ -0,0 +1,79 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: VerteDinde <[email protected]>
+Date: Thu, 30 Nov 2023 20:39:28 -0800
+Subject: Do not store potentially invalid pointers
+
+Manual cherry-pick of PR #1757 into the chromium-m118 branch.
+
+diff --git a/src/read.c b/src/read.c
+index 756af390f451eb7e7422248ddc0b3e88e1640a94..5f2c527911f0896f78b26c7313db215671c217dd 100644
+--- a/src/read.c
++++ b/src/read.c
+@@ -752,6 +752,8 @@ static void avifMetaDestroy(avifMeta * meta)
+     avifFree(meta);
+ }
+ 
++// CAUTION: This function could potentially resize the meta->items array thereby invalidating all existing pointers that are being
++// stored locally. So if this function is being called, exercise caution in the caller to not use invalid pointers.
+ static avifDecoderItem * avifMetaFindItem(avifMeta * meta, uint32_t itemID)
+ {
+     if (itemID == 0) {
+@@ -1259,6 +1261,19 @@ static avifResult avifDecoderItemRead(avifDecoderItem * item,
+     return AVIF_RESULT_OK;
+ }
+ 
++// Returns the avifCodecType of the first tile of the gridItem.
++static avifCodecType avifDecoderItemGetGridCodecType(const avifDecoderItem * gridItem)
++{
++    for (uint32_t i = 0; i < gridItem->meta->items.count; ++i) {
++        avifDecoderItem * item = &gridItem->meta->items.item[i];
++        const avifCodecType tileCodecType = avifGetCodecType(item->type);
++        if ((item->dimgForID == gridItem->id) && (tileCodecType != AVIF_CODEC_TYPE_UNKNOWN)) {
++            return tileCodecType;
++        }
++    }
++    return AVIF_CODEC_TYPE_UNKNOWN;
++}
++
+ static avifBool avifDecoderGenerateImageGridTiles(avifDecoder * decoder, avifImageGrid * grid, avifDecoderItem * gridItem, avifBool alpha)
+ {
+     unsigned int tilesRequested = grid->rows * grid->columns;
+@@ -3843,16 +3858,28 @@ avifResult avifDecoderReset(avifDecoder * decoder)
+         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));
+-            AVIF_CHECKERR(avifParseImageGridBox(&data->alpha.grid,
+-                                                readData.data,
+-                                                readData.size,
+-                                                decoder->imageSizeLimit,
+-                                                decoder->imageDimensionLimit,
+-                                                data->diag),
+-                          AVIF_RESULT_INVALID_IMAGE_GRID);
++        avifCodecType alphaCodecType = AVIF_CODEC_TYPE_UNKNOWN;
++        if (alphaItem) {
++            if (!memcmp(alphaItem->type, "grid", 4)) {
++                if (isAlphaItemInInput) {
++                    avifROData readData;
++                    AVIF_CHECKRES(avifDecoderItemRead(alphaItem, decoder->io, &readData, 0, 0, data->diag));
++                    AVIF_CHECKERR(avifParseImageGridBox(&data->alpha.grid,
++                                                        readData.data,
++                                                        readData.size,
++                                                        decoder->imageSizeLimit,
++                                                        decoder->imageDimensionLimit,
++                                                        data->diag),
++                                  AVIF_RESULT_INVALID_IMAGE_GRID);
++                }
++                alphaCodecType = avifDecoderItemGetGridCodecType(alphaItem);
++                if (alphaCodecType == AVIF_CODEC_TYPE_UNKNOWN) {
++                    return AVIF_RESULT_INVALID_IMAGE_GRID;
++                }
++            } else {
++                alphaCodecType = avifGetCodecType(alphaItem->type);
++                assert(alphaCodecType != AVIF_CODEC_TYPE_UNKNOWN);
++            }
+         }
+ 
+         // Find Exif and/or XMP metadata, if any

+ 227 - 0
patches/libavif/remove_potential_out_of_bound_access_to_alphaitemindices.patch

@@ -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));