diff options
author | Nico Weber <thakis@chromium.org> | 2023-02-25 20:22:01 -0500 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-26 15:54:22 +0100 |
commit | 0393a37843b65d2caea0582da16b02c0747da675 (patch) | |
tree | 6139547240b1045f5244f05a42c8396af6b1d777 /Userland/Libraries/LibGfx | |
parent | 9864963a08956227d18778edcd6e3784580fa2f2 (diff) | |
download | serenity-0393a37843b65d2caea0582da16b02c0747da675.zip |
LibGfx: Add some chunk validation to decode_webp_extended()
Diffstat (limited to 'Userland/Libraries/LibGfx')
-rw-r--r-- | Userland/Libraries/LibGfx/WebPLoader.cpp | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/Userland/Libraries/LibGfx/WebPLoader.cpp b/Userland/Libraries/LibGfx/WebPLoader.cpp index 99b33bae2a..646b6efb42 100644 --- a/Userland/Libraries/LibGfx/WebPLoader.cpp +++ b/Userland/Libraries/LibGfx/WebPLoader.cpp @@ -336,6 +336,8 @@ static ErrorOr<VP8XHeader> decode_webp_chunk_VP8X(WebPLoadingContext& context, C // https://developers.google.com/speed/webp/docs/riff_container#extended_file_format static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyBytes chunks) { + VERIFY(context.first_chunk->type == FourCC("VP8X")); + // FIXME: This isn't quite to spec, which says // "All chunks SHOULD be placed in the same order as listed above. // If a chunk appears in the wrong place, the file is invalid, but readers MAY parse the file, ignoring the chunks that are out of order." @@ -362,6 +364,37 @@ static ErrorOr<void> decode_webp_extended(WebPLoadingContext& context, ReadonlyB store(context.image_data_chunk, chunk); } + // Validate chunks. + + // https://developers.google.com/speed/webp/docs/riff_container#animation + // "ANIM Chunk: [...] This chunk MUST appear if the Animation flag in the VP8X chunk is set. If the Animation flag is not set and this chunk is present, it MUST be ignored." + if (context.vp8x_header.has_animation && !context.animation_header_chunk.has_value()) + return context.error("WebPImageDecoderPlugin: Header claims animation, but no ANIM chunk"); + if (!context.vp8x_header.has_animation && context.animation_header_chunk.has_value()) { + dbgln_if(WEBP_DEBUG, "WebPImageDecoderPlugin: Header claims no animation, but ANIM chunk present. Ignoring ANIM chunk."); + context.animation_header_chunk.clear(); + } + + // "ANMF Chunk: [...] If the Animation flag is not set, then this chunk SHOULD NOT be present." + if (!context.vp8x_header.has_animation && context.animation_header_chunk.has_value()) { + dbgln_if(WEBP_DEBUG, "WebPImageDecoderPlugin: Header claims no animation, but ANMF chunks present. Ignoring ANMF chunks."); + context.animation_frame_chunks.clear(); + } + + // https://developers.google.com/speed/webp/docs/riff_container#alpha + // "A frame containing a 'VP8L' chunk SHOULD NOT contain this chunk." + // FIXME: Also check in ANMF chunks. + if (context.alpha_chunk.has_value() && context.image_data_chunk.has_value() && context.image_data_chunk->type == FourCC("VP8L")) { + dbgln_if(WEBP_DEBUG, "WebPImageDecoderPlugin: VP8L frames should not have ALPH chunks. Ignoring ALPH chunk."); + context.alpha_chunk.clear(); + } + + // https://developers.google.com/speed/webp/docs/riff_container#color_profile + // "This chunk MUST appear before the image data." + // FIXME: Doesn't check animated files. + if (context.iccp_chunk.has_value() && context.image_data_chunk.has_value() && context.iccp_chunk->data.data() > context.image_data_chunk->data.data()) + return context.error("WebPImageDecoderPlugin: ICCP chunk is after image data"); + context.state = WebPLoadingContext::State::ChunksDecoded; return {}; } |