From ec6f109b23d5c3680a3ca50f6c36dda4d30ec255 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sun, 25 Sep 2016 02:55:18 +0300 Subject: [PATCH] 8166288: Au file format can be validated better Reviewed-by: amenkov --- .../com/sun/media/sound/AuFileReader.java | 19 +++++- .../com/sun/media/sound/SunFileReader.java | 6 +- .../AudioFileReader/ReadersExceptions.java | 59 +++++++++++++++++-- .../AudioFileReader/RepeatedFormatReader.java | 4 +- 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java index 097b64b4746..8ca5e796f04 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java @@ -44,7 +44,7 @@ import javax.sound.sampled.UnsupportedAudioFileException; public final class AuFileReader extends SunFileReader { @Override - public StandardFileFormat getAudioFileFormatImpl(final InputStream stream) + StandardFileFormat getAudioFileFormatImpl(final InputStream stream) throws UnsupportedAudioFileException, IOException { final DataInputStream dis = new DataInputStream(stream); final int magic = dis.readInt(); @@ -55,9 +55,15 @@ public final class AuFileReader extends SunFileReader { } final int headerSize = dis.readInt(); + if (headerSize < AuFileFormat.AU_HEADERSIZE) { + throw new UnsupportedAudioFileException("Invalid header size"); + } final long /* unsigned int */ dataSize = dis.readInt() & 0xffffffffL; final int auType = dis.readInt(); final int sampleRate = dis.readInt(); + if (sampleRate <= 0) { + throw new UnsupportedAudioFileException("Invalid sample rate"); + } final int channels = dis.readInt(); if (channels <= 0) { throw new UnsupportedAudioFileException("Invalid number of channels"); @@ -119,10 +125,19 @@ public final class AuFileReader extends SunFileReader { // unsupported filetype, throw exception throw new UnsupportedAudioFileException("not a valid AU file"); } - // now seek past the header + + // Skip the variable-length annotation field. The content of this field + // is currently undefined by AU specification and is unsupported by + // JavaSound, so seek past the header dis.skipBytes(headerSize - AuFileFormat.AU_HEADERSIZE); + // Even if the sampleSizeInBits and channels are supported we can get an + // unsupported frameSize because of overflow final int frameSize = calculatePCMFrameSize(sampleSizeInBits, channels); + if (frameSize <= 0) { + throw new UnsupportedAudioFileException("Invalid frame size"); + } + //$$fb 2002-11-02: fix for 4629669: AU file reader: problems with empty files //$$fb 2003-10-20: fix for 4940459: AudioInputStream.getFrameLength() returns 0 instead of NOT_SPECIFIED long frameLength = AudioSystem.NOT_SPECIFIED; diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java index 01307d59514..7553353153a 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java @@ -252,6 +252,10 @@ abstract class SunFileReader extends AudioFileReader { * @return the size of a PCM frame in bytes. */ static final int calculatePCMFrameSize(int sampleSizeInBits, int channels) { - return ((sampleSizeInBits + 7) / 8) * channels; + try { + return Math.multiplyExact((sampleSizeInBits + 7) / 8, channels); + } catch (final ArithmeticException ignored) { + return 0; + } } } diff --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java index 604c703423a..39bd757cd77 100644 --- a/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -74,11 +74,56 @@ public final class ReadersExceptions { // empty channels static byte[] wrongAUCh = {0x2e, 0x73, 0x6e, 0x64,//AiffFileFormat.AU_SUN_MAGIC - 0, 0, 0, 0, // headerSize + 0, 0, 0, 24, // headerSize + 0, 0, 0, 0, // dataSize + 0, 0, 0, 1, // encoding_local AuFileFormat.AU_ULAW_8 + 0, 0, 0, 1, // sampleRate + 0, 0, 0, 0 // channels + }; + // empty sample rate + static byte[] wrongAUSR = + {0x2e, 0x73, 0x6e, 0x64,//AiffFileFormat.AU_SUN_MAGIC + 0, 0, 0, 24, // headerSize 0, 0, 0, 0, // dataSize 0, 0, 0, 1, // encoding_local AuFileFormat.AU_ULAW_8 0, 0, 0, 0, // sampleRate - 0, 0, 0, 0 // channels + 0, 0, 0, 1 // channels + }; + // empty header size + static byte[] wrongAUEmptyHeader = + {0x2e, 0x73, 0x6e, 0x64,//AiffFileFormat.AU_SUN_MAGIC + 0, 0, 0, 0, // headerSize + 0, 0, 0, 0, // dataSize + 0, 0, 0, 1, // encoding_local AuFileFormat.AU_ULAW_8 + 0, 0, 0, 1, // sampleRate + 0, 0, 0, 1 // channels + }; + // small header size + static byte[] wrongAUSmallHeader = + {0x2e, 0x73, 0x6e, 0x64,//AiffFileFormat.AU_SUN_MAGIC + 0, 0, 0, 7, // headerSize + 0, 0, 0, 0, // dataSize + 0, 0, 0, 1, // encoding_local AuFileFormat.AU_ULAW_8 + 0, 0, 0, 1, // sampleRate + 0, 0, 0, 1 // channels + }; + // frame size overflow, when result negative + static byte[] wrongAUFrameSizeOverflowNegativeResult = + {0x2e, 0x73, 0x6e, 0x64,//AiffFileFormat.AU_SUN_MAGIC + 0, 0, 0, 24, // headerSize + 0, 0, 0, 0, // dataSize + 0, 0, 0, 5, // encoding_local AuFileFormat.AU_LINEAR_32 + 0, 0, 0, 1, // sampleRate + 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF // channels + }; + // frame size overflow, when result positive + static byte[] wrongAUFrameSizeOverflowPositiveResult = + {0x2e, 0x73, 0x6e, 0x64,//AiffFileFormat.AU_SUN_MAGIC + 0, 0, 0, 24, // headerSize + 0, 0, 0, 0, // dataSize + 0, 0, 0, 4, // encoding_local AuFileFormat.AU_LINEAR_24 + 0, 0, 0, 1, // sampleRate + 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF // channels }; // empty channels static byte[] wrongWAVCh = @@ -113,8 +158,12 @@ public final class ReadersExceptions { 0, 0, 0, 0, // dataLength }; - static byte[][] data = {wrongAIFFCh, wrongAIFFSSL, wrongAIFFSSH, wrongAUCh, - wrongWAVCh, wrongWAVSSB}; + static byte[][] data = { + wrongAIFFCh, wrongAIFFSSL, wrongAIFFSSH, wrongAUCh, wrongAUSR, + wrongAUEmptyHeader, wrongAUSmallHeader, + wrongAUFrameSizeOverflowNegativeResult, + wrongAUFrameSizeOverflowPositiveResult, wrongWAVCh, wrongWAVSSB + }; public static void main(final String[] args) throws IOException { for (final byte[] bytes : data) { diff --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java index 2ac37e8490d..f349c8a1ba1 100644 --- a/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java @@ -45,10 +45,10 @@ public final class RepeatedFormatReader { }; private static byte[] headerAU = {0x2e, 0x73, 0x6e, 0x64, // AU_SUN_MAGIC - 0, 0, 0, 0, // headerSize + 0, 0, 0, 24, // headerSize 0, 0, 0, 0, // dataSize 0, 0, 0, 1, // encoding - 0, 0, 0, 0, // sampleRate + 0, 0, 0, 1, // sampleRate 0, 0, 0, 1 // channels };