Archive

Archive for March, 2013

CVE-2013-1493 analysis.

March 21, 2013 Leave a comment

I have recived the sample from a friend of mine. some of them are highly obfuscated and some are not. when i tested them with my latest java version, they were causing jvm to crash. so i decided to digg further. first thing i did was decompiled the jar file and modified the code to print debug statments so that i can trace out and understand the code while debugging. then i removed uncessessary code and compiled and ran the code in eclipse. then i see following:

ScreenHunter_50 Mar. 21 23.34

on further debugging i come to know that this is crashing in icctransform.colorconvert function. if you check the code you can see that this function is defined here:

http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/image/ColorConvertOp.html

“This class performs a pixel-by-pixel color conversion of the data in the source image. The resulting color values are scaled to the precision of the destination image. Color conversion can be specified via an array of ColorSpace objects or an array of ICC_Profile objects.

If the source is a BufferedImage with premultiplied alpha, the color components are divided by the alpha component before color conversion. If the destination is a BufferedImage with premultiplied alpha, the color components are multiplied by the alpha component after conversion. Rasters are treated as having no alpha channel, i.e. all bands are color bands.

If a RenderingHints object is specified in the constructor, the color rendering hint and the dithering hint may be used to control color conversion.

Note that Source and Destination may be the same object.”

it was crashing on making following call from the jar file:

ScreenHunter_51 Mar. 21 23.39

so there might be some kind of overflow. when i attached debugger, i see that its crashing inside cmm.dll .

if we check the code there are some values which are more then integer.MAX size:

ScreenHunter_52 Mar. 21 23.40

if you check in the above image, doffsets has a very large value which is 50000000.

This can be confirmed from the patch from open jdk from url:

http://icedtea.classpath.org/hg/release/icedtea7-forest-2.3/jdk/rev/4f97a6256473

line diff
     1.1 --- a/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Thu Feb 14 19:51:51 2013 +0400
     1.2 +++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Thu Feb 21 11:25:43 2013 +0400
     1.3 @@ -99,50 +99,75 @@
     1.4      int offset;
     1.5  
     1.6      Object dataArray;
     1.7 -    private LCMSImageLayout(int np, int pixelType, int pixelSize) {
     1.8 +    private int dataArrayLength; /* in bytes */
     1.9 +
    1.10 +    private LCMSImageLayout(int np, int pixelType, int pixelSize)
    1.11 +            throws ImageLayoutException
    1.12 +    {
    1.13          this.pixelType = pixelType;
    1.14          width = np;
    1.15          height = 1;
    1.16 -        nextRowOffset = np*pixelSize;
    1.17 +        nextRowOffset = safeMult(pixelSize, np);
    1.18          offset = 0;
    1.19      }
    1.20  
    1.21      private LCMSImageLayout(int width, int height, int pixelType,
    1.22 -                            int pixelSize) {
    1.23 +                            int pixelSize)
    1.24 +            throws ImageLayoutException
    1.25 +    {
    1.26          this.pixelType = pixelType;
    1.27          this.width = width;
    1.28          this.height = height;
    1.29 -        nextRowOffset = width*pixelSize;
    1.30 +        nextRowOffset = safeMult(pixelSize, width);
    1.31          offset = 0;
    1.32      }
    1.33  
    1.34  
    1.35 -    public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
    1.36 +    public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize)
    1.37 +            throws ImageLayoutException
    1.38 +    {
    1.39          this(np, pixelType, pixelSize);
    1.40          dataType = DT_BYTE;
    1.41          dataArray = data;
    1.42 +        dataArrayLength = data.length;
    1.43 +
    1.44 +        verify();
    1.45      }
    1.46  
    1.47 -    public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) {
    1.48 +    public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize)
    1.49 +            throws ImageLayoutException
    1.50 +    {
    1.51          this(np, pixelType, pixelSize);
    1.52          dataType = DT_SHORT;
    1.53          dataArray = data;
    1.54 +        dataArrayLength = 2 * data.length;
    1.55 +
    1.56 +        verify();
    1.57      }
    1.58  
    1.59 -    public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) {
    1.60 +    public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize)
    1.61 +            throws ImageLayoutException
    1.62 +    {
    1.63          this(np, pixelType, pixelSize);
    1.64          dataType = DT_INT;
    1.65          dataArray = data;
    1.66 +        dataArrayLength = 4 * data.length;
    1.67 +
    1.68 +        verify();
    1.69      }
    1.70  
    1.71      public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
    1.72 +            throws ImageLayoutException
    1.73      {
    1.74          this(np, pixelType, pixelSize);
    1.75          dataType = DT_DOUBLE;
    1.76          dataArray = data;
    1.77 +        dataArrayLength = 8 * data.length;
    1.78 +
    1.79 +        verify();
    1.80      }
    1.81  
    1.82 -    public LCMSImageLayout(BufferedImage image) {
    1.83 +    public LCMSImageLayout(BufferedImage image) throws ImageLayoutException {
    1.84          ShortComponentRaster shortRaster;
    1.85          IntegerComponentRaster intRaster;
    1.86          ByteComponentRaster byteRaster;
    1.87 @@ -186,9 +211,13 @@
    1.88              case BufferedImage.TYPE_INT_ARGB:
    1.89              case BufferedImage.TYPE_INT_BGR:
    1.90                  intRaster = (IntegerComponentRaster)image.getRaster();
    1.91 -                nextRowOffset = intRaster.getScanlineStride()*4;
    1.92 -                offset = intRaster.getDataOffset(0)*4;
    1.93 +
    1.94 +                nextRowOffset = safeMult(4, intRaster.getScanlineStride());
    1.95 +
    1.96 +                offset = safeMult(4, intRaster.getDataOffset(0));
    1.97 +
    1.98                  dataArray = intRaster.getDataStorage();
    1.99 +                dataArrayLength = 4 * intRaster.getDataStorage().length;
   1.100                  dataType = DT_INT;
   1.101                  break;
   1.102  
   1.103 @@ -196,8 +225,10 @@
   1.104              case BufferedImage.TYPE_4BYTE_ABGR:
   1.105                  byteRaster = (ByteComponentRaster)image.getRaster();
   1.106                  nextRowOffset = byteRaster.getScanlineStride();
   1.107 -                offset = byteRaster.getDataOffset(0);
   1.108 +                int firstBand = image.getSampleModel().getNumBands() - 1;
   1.109 +                offset = byteRaster.getDataOffset(firstBand);
   1.110                  dataArray = byteRaster.getDataStorage();
   1.111 +                dataArrayLength = byteRaster.getDataStorage().length;
   1.112                  dataType = DT_BYTE;
   1.113                  break;
   1.114  
   1.115 @@ -206,17 +237,20 @@
   1.116                  nextRowOffset = byteRaster.getScanlineStride();
   1.117                  offset = byteRaster.getDataOffset(0);
   1.118                  dataArray = byteRaster.getDataStorage();
   1.119 +                dataArrayLength = byteRaster.getDataStorage().length;
   1.120                  dataType = DT_BYTE;
   1.121                  break;
   1.122  
   1.123              case BufferedImage.TYPE_USHORT_GRAY:
   1.124                  shortRaster = (ShortComponentRaster)image.getRaster();
   1.125 -                nextRowOffset = shortRaster.getScanlineStride()*2;
   1.126 -                offset = shortRaster.getDataOffset(0) * 2;
   1.127 +                nextRowOffset = safeMult(2, shortRaster.getScanlineStride());
   1.128 +                offset = safeMult(2, shortRaster.getDataOffset(0));
   1.129                  dataArray = shortRaster.getDataStorage();
   1.130 +                dataArrayLength = 2 * shortRaster.getDataStorage().length;
   1.131                  dataType = DT_SHORT;
   1.132                  break;
   1.133          }
   1.134 +        verify();
   1.135      }
   1.136  
   1.137      public static boolean isSupported(BufferedImage image) {
   1.138 @@ -232,4 +266,45 @@
   1.139          }
   1.140          return false;
   1.141      }
   1.142 +
   1.143 +    private void verify() throws ImageLayoutException {
   1.144 +
   1.145 +        if (offset < 0 || offset >= dataArrayLength) {
   1.146 +            throw new ImageLayoutException("Invalid image layout");
   1.147 +        }
   1.148 +
   1.149 +        int lastPixelOffset = safeMult(nextRowOffset, (height - 1));
   1.150 +
   1.151 +        lastPixelOffset = safeAdd(lastPixelOffset, (width - 1));
   1.152 +
   1.153 +        int off = safeAdd(offset, lastPixelOffset);
   1.154 +
   1.155 +        if (off < 0 || off >= dataArrayLength) {
   1.156 +            throw new ImageLayoutException("Invalid image layout");
   1.157 +        }
   1.158 +    }
   1.159 +
   1.160 +    static int safeAdd(int a, int b) throws ImageLayoutException {
   1.161 +        long res = a;
   1.162 +        res += b;
   1.163 +        if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
   1.164 +            throw new ImageLayoutException("Invalid image layout");
   1.165 +        }
   1.166 +        return (int)res;
   1.167 +    }
   1.168 +
   1.169 +    static int safeMult(int a, int b) throws ImageLayoutException {
   1.170 +        long res = a;
   1.171 +        res *= b;
   1.172 +        if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
   1.173 +            throw new ImageLayoutException("Invalid image layout");
   1.174 +        }
   1.175 +        return (int)res;
   1.176 +    }
   1.177 +
   1.178 +    public static class ImageLayoutException extends Exception {
   1.179 +        public ImageLayoutException(String message) {
   1.180 +            super(message);
   1.181 +        }
   1.182 +    }
   1.183  }
     2.1 --- a/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Thu Feb 14 19:51:51 2013 +0400
     2.2 +++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Thu Feb 21 11:25:43 2013 +0400
     2.3 @@ -51,6 +51,7 @@
     2.4  import java.awt.image.ComponentSampleModel;
     2.5  import sun.java2d.cmm.*;
     2.6  import sun.java2d.cmm.lcms.*;
     2.7 +import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException;
     2.8  
     2.9  
    2.10  public class LCMSTransform implements ColorTransform {
    2.11 @@ -157,8 +158,12 @@
    2.12          if (LCMSImageLayout.isSupported(src) &&
    2.13              LCMSImageLayout.isSupported(dst))
    2.14          {
    2.15 -            doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
    2.16 -            return;
    2.17 +            try {
    2.18 +                doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
    2.19 +                return;
    2.20 +            } catch (ImageLayoutException e) {
    2.21 +                throw new CMMException("Unable to convert images");
    2.22 +            }
    2.23          }
    2.24          LCMSImageLayout srcIL, dstIL;
    2.25          Raster srcRas = src.getRaster();
    2.26 @@ -216,14 +221,18 @@
    2.27              }
    2.28              int idx;
    2.29              // TODO check for src npixels = dst npixels
    2.30 -            srcIL = new LCMSImageLayout(
    2.31 -                srcLine, srcLine.length/getNumInComponents(),
    2.32 -                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
    2.33 -                LCMSImageLayout.BYTES_SH(1), getNumInComponents());
    2.34 -            dstIL = new LCMSImageLayout(
    2.35 -                dstLine, dstLine.length/getNumOutComponents(),
    2.36 -                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
    2.37 -                LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
    2.38 +            try {
    2.39 +                srcIL = new LCMSImageLayout(
    2.40 +                        srcLine, srcLine.length/getNumInComponents(),
    2.41 +                        LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
    2.42 +                        LCMSImageLayout.BYTES_SH(1), getNumInComponents());
    2.43 +                dstIL = new LCMSImageLayout(
    2.44 +                        dstLine, dstLine.length/getNumOutComponents(),
    2.45 +                        LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
    2.46 +                        LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
    2.47 +            } catch (ImageLayoutException e) {
    2.48 +                throw new CMMException("Unable to convert images");
    2.49 +            }
    2.50              // process each scanline
    2.51              for (int y = 0; y < h; y++) {
    2.52                  // convert src scanline
    2.53 @@ -272,16 +281,19 @@
    2.54                  alpha = new float[w];
    2.55              }
    2.56              int idx;
    2.57 -            srcIL = new LCMSImageLayout(
    2.58 -                srcLine, srcLine.length/getNumInComponents(),
    2.59 -                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
    2.60 -                LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
    2.61 +            try {
    2.62 +                srcIL = new LCMSImageLayout(
    2.63 +                    srcLine, srcLine.length/getNumInComponents(),
    2.64 +                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
    2.65 +                    LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
    2.66  
    2.67 -            dstIL = new LCMSImageLayout(
    2.68 -                dstLine, dstLine.length/getNumOutComponents(),
    2.69 -                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
    2.70 -                LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
    2.71 -
    2.72 +                dstIL = new LCMSImageLayout(
    2.73 +                    dstLine, dstLine.length/getNumOutComponents(),
    2.74 +                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
    2.75 +                    LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
    2.76 +            } catch (ImageLayoutException e) {
    2.77 +                throw new CMMException("Unable to convert images");
    2.78 +            }
    2.79              // process each scanline
    2.80              for (int y = 0; y < h; y++) {
    2.81                  // convert src scanline
    2.82 @@ -390,16 +402,19 @@
    2.83          short[] srcLine = new short[w * srcNumBands];
    2.84          short[] dstLine = new short[w * dstNumBands];
    2.85          int idx;
    2.86 -        srcIL = new LCMSImageLayout(
    2.87 -            srcLine, srcLine.length/getNumInComponents(),
    2.88 -            LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
    2.89 -            LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
    2.90 +        try {
    2.91 +            srcIL = new LCMSImageLayout(
    2.92 +                    srcLine, srcLine.length/getNumInComponents(),
    2.93 +                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
    2.94 +                    LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
    2.95  
    2.96 -        dstIL = new LCMSImageLayout(
    2.97 -            dstLine, dstLine.length/getNumOutComponents(),
    2.98 -            LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
    2.99 -            LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
   2.100 -
   2.101 +            dstIL = new LCMSImageLayout(
   2.102 +                    dstLine, dstLine.length/getNumOutComponents(),
   2.103 +                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.104 +                    LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
   2.105 +        } catch (ImageLayoutException e) {
   2.106 +            throw new CMMException("Unable to convert rasters");
   2.107 +        }
   2.108          // process each scanline
   2.109          for (int y = 0; y < h; y++, ys++, yd++) {
   2.110              // get src scanline
   2.111 @@ -482,15 +497,18 @@
   2.112              byte[] dstLine = new byte[w * dstNumBands];
   2.113              int idx;
   2.114              // TODO check for src npixels = dst npixels
   2.115 -            srcIL = new LCMSImageLayout(
   2.116 -                srcLine, srcLine.length/getNumInComponents(),
   2.117 -                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.118 -                LCMSImageLayout.BYTES_SH(1), getNumInComponents());
   2.119 -            dstIL = new LCMSImageLayout(
   2.120 -                dstLine, dstLine.length/getNumOutComponents(),
   2.121 -                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.122 -                LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
   2.123 -
   2.124 +            try {
   2.125 +                srcIL = new LCMSImageLayout(
   2.126 +                        srcLine, srcLine.length/getNumInComponents(),
   2.127 +                        LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.128 +                        LCMSImageLayout.BYTES_SH(1), getNumInComponents());
   2.129 +                dstIL = new LCMSImageLayout(
   2.130 +                        dstLine, dstLine.length/getNumOutComponents(),
   2.131 +                        LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.132 +                        LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
   2.133 +            } catch (ImageLayoutException e) {
   2.134 +                throw new CMMException("Unable to convert rasters");
   2.135 +            }
   2.136              // process each scanline
   2.137              for (int y = 0; y < h; y++, ys++, yd++) {
   2.138                  // get src scanline
   2.139 @@ -522,16 +540,20 @@
   2.140              short[] srcLine = new short[w * srcNumBands];
   2.141              short[] dstLine = new short[w * dstNumBands];
   2.142              int idx;
   2.143 -            srcIL = new LCMSImageLayout(
   2.144 -                srcLine, srcLine.length/getNumInComponents(),
   2.145 -                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.146 -                LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
   2.147  
   2.148 -            dstIL = new LCMSImageLayout(
   2.149 -                dstLine, dstLine.length/getNumOutComponents(),
   2.150 -                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.151 -                LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
   2.152 +            try {
   2.153 +                srcIL = new LCMSImageLayout(
   2.154 +                        srcLine, srcLine.length/getNumInComponents(),
   2.155 +                        LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.156 +                        LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
   2.157  
   2.158 +                dstIL = new LCMSImageLayout(
   2.159 +                        dstLine, dstLine.length/getNumOutComponents(),
   2.160 +                        LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.161 +                        LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
   2.162 +            } catch (ImageLayoutException e) {
   2.163 +                throw new CMMException("Unable to convert rasters");
   2.164 +            }
   2.165              // process each scanline
   2.166              for (int y = 0; y < h; y++, ys++, yd++) {
   2.167                  // get src scanline
   2.168 @@ -572,19 +594,23 @@
   2.169              dst = new short [(src.length/getNumInComponents())*getNumOutComponents()];
   2.170          }
   2.171  
   2.172 -        LCMSImageLayout srcIL = new LCMSImageLayout(
   2.173 -            src, src.length/getNumInComponents(),
   2.174 -            LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.175 -            LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
   2.176 +        try {
   2.177 +            LCMSImageLayout srcIL = new LCMSImageLayout(
   2.178 +                    src, src.length/getNumInComponents(),
   2.179 +                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.180 +                    LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
   2.181  
   2.182 -        LCMSImageLayout dstIL = new LCMSImageLayout(
   2.183 -            dst, dst.length/getNumOutComponents(),
   2.184 -            LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.185 -            LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
   2.186 +            LCMSImageLayout dstIL = new LCMSImageLayout(
   2.187 +                    dst, dst.length/getNumOutComponents(),
   2.188 +                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.189 +                    LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
   2.190  
   2.191 -        doTransform(srcIL, dstIL);
   2.192 +            doTransform(srcIL, dstIL);
   2.193  
   2.194 -        return dst;
   2.195 +            return dst;
   2.196 +        } catch (ImageLayoutException e) {
   2.197 +            throw new CMMException("Unable to convert data");
   2.198 +        }
   2.199      }
   2.200  
   2.201      public byte[] colorConvert(byte[] src, byte[] dst) {
   2.202 @@ -592,18 +618,22 @@
   2.203              dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()];
   2.204          }
   2.205  
   2.206 -        LCMSImageLayout srcIL = new LCMSImageLayout(
   2.207 -            src, src.length/getNumInComponents(),
   2.208 -            LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.209 -            LCMSImageLayout.BYTES_SH(1), getNumInComponents());
   2.210 +        try {
   2.211 +            LCMSImageLayout srcIL = new LCMSImageLayout(
   2.212 +                    src, src.length/getNumInComponents(),
   2.213 +                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
   2.214 +                    LCMSImageLayout.BYTES_SH(1), getNumInComponents());
   2.215  
   2.216 -        LCMSImageLayout dstIL = new LCMSImageLayout(
   2.217 -            dst, dst.length/getNumOutComponents(),
   2.218 -            LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.219 -            LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
   2.220 +            LCMSImageLayout dstIL = new LCMSImageLayout(
   2.221 +                    dst, dst.length/getNumOutComponents(),
   2.222 +                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
   2.223 +                    LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
   2.224  
   2.225 -        doTransform(srcIL, dstIL);
   2.226 +            doTransform(srcIL, dstIL);
   2.227  
   2.228 -        return dst;
   2.229 +            return dst;
   2.230 +        } catch (ImageLayoutException e) {
   2.231 +            throw new CMMException("Unable to convert data");
   2.232 +        }
   2.233      }
   2.234  }

thanks,
Hardik
Advertisements
%d bloggers like this: