-
Bug
-
Resolution: Fixed
-
P3
-
8, 11, 16, 17
-
b19
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
Tested on Linux Ubuntu 20.04.2.0, MacBook 2019,
JDK version: 1.8.0_291, 11.0.11
A DESCRIPTION OF THE PROBLEM :
The problem was raised by our customers that particularly crafted GIF files processed by Jira instance cause high CPU usage and "hang" Jira instance. During our investigation, we found that problem is caused by GIF file created in Adobe Photoshop 2019 (I can provide a problematic file). Due to a bug in Adobe Photoshop (https://prepression.blogspot.com/2017/06/metadata-bloat-photoshopdocumentancestors.html), the file contains an extensive amount of metadata.
Our software uses javax.imageio library to read and manipulate GIF files which uses `com.sun.imageio.plugins.gif.GIFImageReader` class for operations on GIF files.
This class tries to read all metadata from GIF files and in the process, it allocates big byte arrays and copies data between them multiple times. It causes high CPU usage and even hangs JVM application. We crafted a small program to confirm that problem is indeed in JVM implementation and not in our software. Java code included.
GIFImageReader ignores the flag "ignoreMetadata" of `javax.imageio.ImageReader` so there is no way to avoid problems with malicious metadata.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create or download malicious GIF file
2. Run a java program that opens the file and reads its metadata
3. Observe results
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program successfully reads metadata (or don't read metadata at all) and don't cause high CPU usage
ACTUAL -
The program hangs and causes high CPU usage
---------- BEGIN SOURCE ----------
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
class Scratch {
public static void main(String[] args) throws IOException {
String workingFolder = "<directory>";
String imageFilename = "btn_offer_wall_animation.gif";
ImageInputStream imageInputStream = ImageIO.createImageInputStream(
new BufferedInputStream(
new FileInputStream(
new File(workingFolder + imageFilename))));
ImageReader reader = ImageIO.getImageReaders(imageInputStream).next();
reader.setInput(imageInputStream, false, true);
final ImageReadParam param = reader.getDefaultReadParam();
param.setSourceSubsampling(1, 1, 0, 0);
System.out.println(LocalDateTime.now().toString());
final BufferedImage scaledImage = reader.read(0, param);
File output = new File(workingFolder + "scaled.gif");
if(output.exists()){
output.delete();
}
ImageIO.write(scaledImage, "gif", output);
System.out.println(LocalDateTime.now().toString());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
1. Remove metadata from the file using an external tool/library before processing the file
2. Craft a modified version of GIFImageReader that instead of reading application metadata, skips it. Then use this modified version instead of original GIFImageReader
FREQUENCY : always
Tested on Linux Ubuntu 20.04.2.0, MacBook 2019,
JDK version: 1.8.0_291, 11.0.11
A DESCRIPTION OF THE PROBLEM :
The problem was raised by our customers that particularly crafted GIF files processed by Jira instance cause high CPU usage and "hang" Jira instance. During our investigation, we found that problem is caused by GIF file created in Adobe Photoshop 2019 (I can provide a problematic file). Due to a bug in Adobe Photoshop (https://prepression.blogspot.com/2017/06/metadata-bloat-photoshopdocumentancestors.html), the file contains an extensive amount of metadata.
Our software uses javax.imageio library to read and manipulate GIF files which uses `com.sun.imageio.plugins.gif.GIFImageReader` class for operations on GIF files.
This class tries to read all metadata from GIF files and in the process, it allocates big byte arrays and copies data between them multiple times. It causes high CPU usage and even hangs JVM application. We crafted a small program to confirm that problem is indeed in JVM implementation and not in our software. Java code included.
GIFImageReader ignores the flag "ignoreMetadata" of `javax.imageio.ImageReader` so there is no way to avoid problems with malicious metadata.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create or download malicious GIF file
2. Run a java program that opens the file and reads its metadata
3. Observe results
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program successfully reads metadata (or don't read metadata at all) and don't cause high CPU usage
ACTUAL -
The program hangs and causes high CPU usage
---------- BEGIN SOURCE ----------
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
class Scratch {
public static void main(String[] args) throws IOException {
String workingFolder = "<directory>";
String imageFilename = "btn_offer_wall_animation.gif";
ImageInputStream imageInputStream = ImageIO.createImageInputStream(
new BufferedInputStream(
new FileInputStream(
new File(workingFolder + imageFilename))));
ImageReader reader = ImageIO.getImageReaders(imageInputStream).next();
reader.setInput(imageInputStream, false, true);
final ImageReadParam param = reader.getDefaultReadParam();
param.setSourceSubsampling(1, 1, 0, 0);
System.out.println(LocalDateTime.now().toString());
final BufferedImage scaledImage = reader.read(0, param);
File output = new File(workingFolder + "scaled.gif");
if(output.exists()){
output.delete();
}
ImageIO.write(scaledImage, "gif", output);
System.out.println(LocalDateTime.now().toString());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
1. Remove metadata from the file using an external tool/library before processing the file
2. Craft a modified version of GIFImageReader that instead of reading application metadata, skips it. Then use this modified version instead of original GIFImageReader
FREQUENCY : always