Files
message_q/src/com/android/messaging/datamodel/media/GifImageResource.java
T
Tom Taylor 467361dbcf 37742976 - Catch bad gifs
* A security researcher crafted a gif that would cause the Android
Bitmap code to throw an NPE. That would cause messaging to crash when
decoding the NPE. The frameworks team is changing the underlying code to
throw an OutOfMemoryError instead of a NullPointerException.
In order to catch both errors, the code needs to catch Throwable.

Test: I added code to GifImageResource.getDrawable to throw a new
OutOfMemoryError and then used the debugger to verify it was caught by the
new catch Throwable statement. I did the same test with NullPointerException.
I tested attaching gif images and sending them to verify the gif path still
worked.

BUG=37742976

Change-Id: If71a7e65f8c0b083fe6c4b79f78358666338d59d
2017-10-05 11:27:21 -07:00

119 lines
3.6 KiB
Java

/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.datamodel.media;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.support.rastermill.FrameSequence;
import android.support.rastermill.FrameSequenceDrawable;
import com.android.messaging.util.Assert;
import com.android.messaging.util.LogUtil;
import java.io.IOException;
import java.io.InputStream;
public class GifImageResource extends ImageResource {
private FrameSequence mFrameSequence;
public GifImageResource(String key, FrameSequence frameSequence) {
// GIF does not support exif tags
super(key, ExifInterface.ORIENTATION_NORMAL);
mFrameSequence = frameSequence;
}
public static GifImageResource createGifImageResource(String key, InputStream inputStream) {
final FrameSequence frameSequence;
try {
frameSequence = FrameSequence.decodeStream(inputStream);
} finally {
try {
inputStream.close();
} catch (IOException e) {
// Nothing to do if we fail closing the stream
}
}
if (frameSequence == null) {
return null;
}
return new GifImageResource(key, frameSequence);
}
@Override
public Drawable getDrawable(Resources resources) {
try {
return new FrameSequenceDrawable(mFrameSequence);
} catch (final Throwable t) {
// Malicious gif images can make the platform throw different kind of throwables, such
// as OutOfMemoryError and NullPointerException. Catch them all.
LogUtil.e(LogUtil.BUGLE_TAG, "Error getting drawable for GIF", t);
return null;
}
}
@Override
public Bitmap getBitmap() {
Assert.fail("GetBitmap() should never be called on a gif.");
return null;
}
@Override
public byte[] getBytes() {
Assert.fail("GetBytes() should never be called on a gif.");
return null;
}
@Override
public Bitmap reuseBitmap() {
return null;
}
@Override
public boolean supportsBitmapReuse() {
// FrameSequenceDrawable a.) takes two bitmaps and thus does not fit into the current
// bitmap pool architecture b.) will rarely use bitmaps from one FrameSequenceDrawable to
// the next that are the same sizes since they are used by attachments.
return false;
}
@Override
public int getMediaSize() {
Assert.fail("GifImageResource should not be used by a media cache");
// Only used by the media cache, which this does not use.
return 0;
}
@Override
public boolean isCacheable() {
return false;
}
@Override
protected void close() {
acquireLock();
try {
if (mFrameSequence != null) {
mFrameSequence = null;
}
} finally {
releaseLock();
}
}
}