8166288: Au file format can be validated better
authorserb
Sun, 25 Sep 2016 02:55:18 +0300
changeset 41394 da0318151636
parent 41393 ebc8d972cd3f
child 41395 2a6f7eb1dc23
8166288: Au file format can be validated better Reviewed-by: amenkov
jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java
jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java
jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java
jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java	Fri Sep 23 10:36:32 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileReader.java	Sun Sep 25 02:55:18 2016 +0300
@@ -44,7 +44,7 @@
 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 @@
         }
 
         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 @@
                 // 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;
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java	Fri Sep 23 10:36:32 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java	Sun Sep 25 02:55:18 2016 +0300
@@ -252,6 +252,10 @@
      * @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;
+        }
     }
 }
--- a/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java	Fri Sep 23 10:36:32 2016 +0300
+++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java	Sun Sep 25 02:55:18 2016 +0300
@@ -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 @@
     // empty channels
     static byte[] wrongAUCh =
             {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, 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, 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, 0, // sampleRate
-             0, 0, 0, 0 // channels
+             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 @@
              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) {
--- a/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java	Fri Sep 23 10:36:32 2016 +0300
+++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java	Sun Sep 25 02:55:18 2016 +0300
@@ -45,10 +45,10 @@
     };
 
     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
     };