diff --git a/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/MetadataParserImpl.java b/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/MetadataParserImpl.java index 0b12cde4a9d..14e28b4411d 100644 --- a/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/MetadataParserImpl.java +++ b/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/MetadataParserImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,6 +108,10 @@ protected void addMetadataItem(String tag, Object value) { metadata.put(tag, value); } + protected void disposeMetadata() { + metadata.clear(); + } + protected void done() { synchronized (listeners) { if (!metadata.isEmpty()) { @@ -130,6 +134,10 @@ protected int getStreamPosition() { return streamPosition; } + protected long getStreamLength() { + return locator.getContentLength(); + } + protected void startRawMetadata(int sizeHint) { rawMetaBlob = ByteBuffer.allocate(sizeHint); } diff --git a/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/platform/java/ID3MetadataParser.java b/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/platform/java/ID3MetadataParser.java index 03c904af6e9..8910328c2ac 100644 --- a/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/platform/java/ID3MetadataParser.java +++ b/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/platform/java/ID3MetadataParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,11 @@ final class ID3MetadataParser extends MetadataParserImpl { private static final int ID3_VERSION_MIN = 2; private static final int ID3_VERSION_MAX = 4; + // Max tag size cannot be more than 256 MB + private static final int MAX_TAG_SIZE = 256 * 1024 * 1024; + // Max frame size cannot be more than 16 MB + private static final int MAX_FRAME_SIZE = 16 * 1024 * 1024; + private static final String CHARSET_UTF_8 = "UTF-8"; private static final String CHARSET_ISO_8859_1 = "ISO-8859-1"; private static final String CHARSET_UTF_16 = "UTF-16"; @@ -46,6 +51,7 @@ final class ID3MetadataParser extends MetadataParserImpl { private int COMMCount = 0; private int TXXXCount = 0; private int version = 3; // Default to 3 + private int tagSize = 0; private boolean unsynchronized = false; public ID3MetadataParser(Locator locator) { @@ -82,12 +88,15 @@ protected void parse() { unsynchronized = true; } - int tagSize = 0; for (int i = 6, shift = 21; i < 10; i++) { tagSize += (buf[i] & 0x7f) << shift; shift -= 7; } + if (!validateTagSize()) { + return; // Abort parser if tag size is invalid. + } + startRawMetadata(tagSize + 10); stuffRawMetadata(buf, 0, 10); // put the header back in the raw metadata blob readRawMetadata(tagSize); @@ -108,6 +117,14 @@ protected void parse() { skipBytes(2); } + if (!validateFrameSize(frameSize)) { + // Dispose any parsed or partially parsed metadata + disposeMetadata(); + setParseRawMetadata(false); + disposeRawMetadata(); + return; // Abort parser if frame size is invalid. + } + if (0 == idBytes[0]) { // terminate on zero padding, NULL characters not allowed in frame ID if (Logger.canLog(Logger.DEBUG)) { @@ -239,6 +256,30 @@ protected void parse() { } } + // Tag size should be <= MAX_TAG_SIZE and stream length. + private boolean validateTagSize() { + long streamLength = getStreamLength(); // Can be -1 if unknown + if ((streamLength > 0 && tagSize > streamLength) || + tagSize > MAX_TAG_SIZE) { + Logger.logMsg(Logger.ERROR, "Unexpected ID3 tag size(" + + tagSize +"). ID3 metadata will be ignored."); + return false; + } + + return true; + } + + // Frame size should be <= MAX_FRAME_SIZE and tag size. + private boolean validateFrameSize(int frameSize) { + if (frameSize > tagSize || frameSize > MAX_FRAME_SIZE) { + Logger.logMsg(Logger.ERROR, "Unexpected ID3 frame size(" + + frameSize +"). ID3 metadata will be ignored."); + return false; + } + + return true; + } + private int getFrameSize() throws IOException { if (version == 4) { byte[] buf = getBytes(4); diff --git a/modules/javafx.media/src/main/native/gstreamer/plugins/dshowwrapper/dshowwrapper.cpp b/modules/javafx.media/src/main/native/gstreamer/plugins/dshowwrapper/dshowwrapper.cpp index 431219b4ad8..8320cb9954b 100644 --- a/modules/javafx.media/src/main/native/gstreamer/plugins/dshowwrapper/dshowwrapper.cpp +++ b/modules/javafx.media/src/main/native/gstreamer/plugins/dshowwrapper/dshowwrapper.cpp @@ -59,6 +59,7 @@ using namespace std; #define AAC_PTS_INPUT_DEBUG 0 #define EOS_DEBUG 0 +// MAX_HEADER_SIZE is valid max size for H.264 and AAC, however AAC header is actually smaller. #define MAX_HEADER_SIZE 256 #define INPUT_BUFFERS_BEFORE_ERROR 500 @@ -635,17 +636,25 @@ void dshowwrapper_deliver_post_process_mp2t(GstBuffer *pBuffer, GstDShowWrapper data = info.data; size = info.size; - if (data == NULL || size < 3) + // PES header 6 bytes + optional extension + payload + // We should have at least 7 bytes (header + 1 byte for payload) + if (data == NULL || size < 7) + { + gst_buffer_unmap(pBuffer, &info); return; + } if (data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01) // PES header start { - if ((data[6] & 0x80) == 0x80) // Optional PES header + // Check for optional PES header and make sure we have enough bytes + // to continue parsing optional PES header which is 3 bytes. + if ((data[6] & 0x80) == 0x80 && size >= 9) // Optional PES header { __int64 PTS = 0; GstClockTime gst_pts = GST_CLOCK_TIME_NONE; - if ((data[7] & 0x80) == 0x80) // Get PTS + // Make sure we have enough bytes to read PTS + if ((data[7] & 0x80) == 0x80 && size >= 14) // Get PTS { PTS |= ((__int64)(data[9] & 0x0E) << 29); PTS |= (data[10] << 22); @@ -694,11 +703,21 @@ void dshowwrapper_deliver_post_process_mp2t(GstBuffer *pBuffer, GstDShowWrapper } guint8 optional_remaining_header_size = data[8]; - size -= (PES_HEADER_SIZE + PES_OPTIONAL_HEADER_SIZE + optional_remaining_header_size); - offset = (PES_HEADER_SIZE + PES_OPTIONAL_HEADER_SIZE + optional_remaining_header_size); + if ((PES_HEADER_SIZE + PES_OPTIONAL_HEADER_SIZE + optional_remaining_header_size) < size) + { + size -= (PES_HEADER_SIZE + PES_OPTIONAL_HEADER_SIZE + optional_remaining_header_size); + offset = (PES_HEADER_SIZE + PES_OPTIONAL_HEADER_SIZE + optional_remaining_header_size); + } + else + { + // Something wrong. + gst_buffer_unmap(pBuffer, &info); + return; + } } else { + // Skip 6 bytes of PES header size -= PES_HEADER_SIZE; offset = PES_HEADER_SIZE; } @@ -1551,7 +1570,14 @@ static gboolean dshowwrapper_load_decoder_aac(GstStructure *s, GstDShowWrapper * codec_data = gst_value_get_buffer(v); if (codec_data != NULL) if (gst_buffer_map(codec_data, &info, GST_MAP_READ)) - codec_data_size = info.size; + codec_data_size = (gint)info.size; + } + + // Make sure header has reasonable size + if (codec_data_size < 0 || codec_data_size > MAX_HEADER_SIZE) + { + gst_buffer_unmap(codec_data, &info); + return FALSE; } inputFormat.type = MEDIATYPE_Audio; @@ -2071,13 +2097,14 @@ static gboolean dshowwrapper_load_decoder_h264(GstStructure *s, GstDShowWrapper if (gst_buffer_map(codec_data, &codec_data_info, GST_MAP_READ)) { if (codec_data_info.size <= MAX_HEADER_SIZE) - header_size = dshowwrapper_get_avc_config(codec_data_info.data, codec_data_info.size, header, MAX_HEADER_SIZE, &decoder->lengthSizeMinusOne); + header_size = (gint)dshowwrapper_get_avc_config(codec_data_info.data, codec_data_info.size, header, MAX_HEADER_SIZE, &decoder->lengthSizeMinusOne); gst_buffer_unmap(codec_data, &codec_data_info); } } else return FALSE; + // dshowwrapper_get_avc_config() will make sure that (header_size <= MAX_HEADER_SIZE) if (header_size <= 0) return FALSE;