Changeset 206244 in webkit


Ignore:
Timestamp:
Sep 21, 2016 6:23:26 PM (8 years ago)
Author:
Brent Fulgham
Message:

Correct uses of 'safeCast'
https://bugs.webkit.org/show_bug.cgi?id=162301
<rdar://problem/28343658>

Reviewed by Antti Koivisto.

Source/WebCore:

A number of integer calculations in BitmapImage and PDFDocumentImage
are not properly checked for overflow. Correct this.

Tested by fast/images/large-size-image-crash.html

  • loader/cache/MemoryCache.cpp:

(WebCore::MemoryCache::adjustSize): RELEASE_ASSERT on overflow.

  • platform/graphics/BitmapImage.cpp:

(WebCore::BitmapImage::destroyMetadataAndNotify):
(WebCore::BitmapImage::cacheFrame):
(WebCore::BitmapImage::didDecodeProperties):
(WebCore::BitmapImage::dataChanged):
(WebCore::BitmapImage::ensureFrameAtIndexIsCached):
(WebCore::BitmapImage::frameImageAtIndex):

  • platform/graphics/BitmapImage.h:
  • platform/graphics/cg/PDFDocumentImage.cpp:

(WebCore::PDFDocumentImage::decodedSizeChanged):
(WebCore::PDFDocumentImage::updateCachedImageIfNeeded):

Source/WTF:

  • wtf/StdLibExtras.h:

(WTF::safeCast): RELEASE_ASSERT on overflow.

Location:
trunk/Source
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r206236 r206244  
     12016-09-20  Brent Fulgham  <bfulgham@apple.com>
     2
     3        Correct uses of 'safeCast'
     4        https://bugs.webkit.org/show_bug.cgi?id=162301
     5        <rdar://problem/28343658>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        * wtf/StdLibExtras.h:
     10        (WTF::safeCast): RELEASE_ASSERT on overflow.
     11
    1122016-09-21  Commit Queue  <commit-queue@webkit.org>
    213
  • trunk/Source/WTF/wtf/StdLibExtras.h

    r205794 r206244  
    160160inline ToType safeCast(FromType value)
    161161{
    162     ASSERT(isInBounds<ToType>(value));
     162    RELEASE_ASSERT(isInBounds<ToType>(value));
    163163    return static_cast<ToType>(value);
    164164}
  • trunk/Source/WebCore/ChangeLog

    r206243 r206244  
     12016-09-20  Brent Fulgham  <bfulgham@apple.com>
     2
     3        Correct uses of 'safeCast'
     4        https://bugs.webkit.org/show_bug.cgi?id=162301
     5        <rdar://problem/28343658>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        A number of integer calculations in BitmapImage and PDFDocumentImage
     10        are not properly checked for overflow. Correct this.
     11
     12        Tested by fast/images/large-size-image-crash.html
     13
     14        * loader/cache/MemoryCache.cpp:
     15        (WebCore::MemoryCache::adjustSize): RELEASE_ASSERT on overflow.
     16        * platform/graphics/BitmapImage.cpp:
     17        (WebCore::BitmapImage::destroyMetadataAndNotify):
     18        (WebCore::BitmapImage::cacheFrame):
     19        (WebCore::BitmapImage::didDecodeProperties):
     20        (WebCore::BitmapImage::dataChanged):
     21        (WebCore::BitmapImage::ensureFrameAtIndexIsCached):
     22        (WebCore::BitmapImage::frameImageAtIndex):
     23        * platform/graphics/BitmapImage.h:
     24        * platform/graphics/cg/PDFDocumentImage.cpp:
     25        (WebCore::PDFDocumentImage::decodedSizeChanged):
     26        (WebCore::PDFDocumentImage::updateCachedImageIfNeeded):
     27
    1282016-09-21  Chris Dumez  <cdumez@apple.com>
    229
  • trunk/Source/WebCore/loader/cache/MemoryCache.cpp

    r201603 r206244  
    645645{
    646646    if (live) {
    647         ASSERT(delta >= 0 || ((int)m_liveSize + delta >= 0));
     647        RELEASE_ASSERT(delta >= 0 || ((int)m_liveSize + delta >= 0));
    648648        m_liveSize += delta;
    649649    } else {
    650         ASSERT(delta >= 0 || ((int)m_deadSize + delta >= 0));
     650        RELEASE_ASSERT(delta >= 0 || ((int)m_deadSize + delta >= 0));
    651651        m_deadSize += delta;
    652652    }
  • trunk/Source/WebCore/platform/graphics/BitmapImage.cpp

    r206156 r206244  
    11/*
    22 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
    3  * Copyright (C) 2004, 2005, 2006, 2008, 2015 Apple Inc. All rights reserved.
     3 * Copyright (C) 2004-2006, 2008, 2015-2016 Apple Inc. All rights reserved.
    44 *
    55 * Redistribution and use in source and binary forms, with or without
     
    3737#include "TextStream.h"
    3838#include "Timer.h"
     39#include <wtf/CheckedArithmetic.h>
    3940#include <wtf/CurrentTime.h>
    4041#include <wtf/Vector.h>
     
    143144    invalidatePlatformData();
    144145
    145     ASSERT(m_decodedSize >= frameBytesCleared);
    146     m_decodedSize -= frameBytesCleared;
     146    if (!WTF::safeSub(m_decodedSize, frameBytesCleared, m_decodedSize))
     147        CRASH_WITH_SECURITY_IMPLICATION();
    147148
    148149    // Clearing the ImageSource destroys the extra decoded data used for determining image properties.
     150    long long adjustedFrameBytesCleared = frameBytesCleared;
    149151    if (clearedSource == ClearedSource::Yes) {
    150         frameBytesCleared += m_decodedPropertiesSize;
     152        adjustedFrameBytesCleared += m_decodedPropertiesSize;
    151153        m_decodedPropertiesSize = 0;
    152154    }
    153155
    154     if (frameBytesCleared && imageObserver())
    155         imageObserver()->decodedSizeChanged(this, -safeCast<int>(frameBytesCleared));
     156    if (adjustedFrameBytesCleared && imageObserver()) {
     157        Checked<int> checkedDelta = adjustedFrameBytesCleared;
     158        imageObserver()->decodedSizeChanged(this, -checkedDelta.unsafeGet());
     159    }
    156160}
    157161
     
    173177
    174178    if (m_frames[index].hasNativeImage()) {
    175         int deltaBytes = safeCast<int>(m_frames[index].frameBytes());
    176         m_decodedSize += deltaBytes;
     179        if (!WTF::safeAdd(m_decodedSize, m_frames[index].frameBytes(), m_decodedSize)) {
     180            LOG(Images, "BitmapImage %p cacheFrame m_decodedSize overflowed unsigned.", this);
     181            destroyDecodedData(false);
     182            return;
     183        }
     184
    177185        // The fully-decoded frame will subsume the partially decoded data used
    178186        // to determine image properties.
    179         deltaBytes -= m_decodedPropertiesSize;
     187        long long deltaBytes = m_frames[index].frameBytes() - m_decodedPropertiesSize;
    180188        m_decodedPropertiesSize = 0;
     189
     190        Checked<int, RecordOverflow> checkedDeltaBytes = deltaBytes;
     191        if (checkedDeltaBytes.hasOverflowed()) {
     192            LOG(Images, "BitmapImage %p cacheFrame deltaBytes=%lld overflowed integer.", this, deltaBytes);
     193            destroyDecodedData(false);
     194            return;
     195        }
     196
    181197        if (imageObserver())
    182             imageObserver()->decodedSizeChanged(this, deltaBytes);
     198            imageObserver()->decodedSizeChanged(this, checkedDeltaBytes.unsafeGet());
    183199    }
    184200}
     
    193209        return;
    194210
    195     int deltaBytes = updatedSize - m_decodedPropertiesSize;
     211    long long deltaBytes = updatedSize - m_decodedPropertiesSize;
    196212#if !ASSERT_DISABLED
    197213    bool overflow = updatedSize > m_decodedPropertiesSize && deltaBytes < 0;
     
    200216#endif
    201217    m_decodedPropertiesSize = updatedSize;
    202     if (imageObserver())
    203         imageObserver()->decodedSizeChanged(this, deltaBytes);
     218    if (imageObserver()) {
     219        Checked<int> checkedDeltaBytes = deltaBytes;
     220        imageObserver()->decodedSizeChanged(this, checkedDeltaBytes.unsafeGet());
     221    }
    204222}
    205223
     
    257275    // frame affected by appending new data here. Thus we have to clear all the
    258276    // incomplete frames to be safe.
    259     unsigned frameBytesCleared = 0;
     277    Checked<unsigned> frameBytesCleared = 0;
    260278    for (auto& frame : m_frames) {
    261279        // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to
     
    265283            frameBytesCleared += frame.clear();
    266284    }
    267     destroyMetadataAndNotify(frameBytesCleared, ClearedSource::No);
     285    destroyMetadataAndNotify(frameBytesCleared.unsafeGet(), ClearedSource::No);
    268286#else
    269287    // FIXME: why is this different for iOS?
    270     int deltaBytes = 0;
     288    Checked<int> deltaBytes = 0;
    271289    if (!m_frames.isEmpty()) {
    272290        if (int bytes = m_frames[m_frames.size() - 1].clear()) {
     
    276294        }
    277295    }
    278     destroyMetadataAndNotify(deltaBytes, ClearedSource::No);
     296    destroyMetadataAndNotify(deltaBytes.unsafeGet(), ClearedSource::No);
    279297#endif
    280298   
     
    357375
    358376        // If the image is already cached, but at too small a size, re-decode a larger version.
    359         int sizeChange = -m_frames[index].clear();
     377        unsigned sizeChange = m_frames[index].clear();
    360378        invalidatePlatformData();
    361         m_decodedSize += sizeChange;
     379
     380        if (WTF::safeSub(m_decodedSize, sizeChange, m_decodedSize)) {
     381            LOG(Images, "BitmapImage %p frameImageAtIndex m_decodedSize overflowed unsigned.", this);
     382            destroyDecodedData(false);
     383            return nullptr;
     384        }
     385
     386        Checked<int, RecordOverflow> checkedSizeChange = -sizeChange;
     387        if (checkedSizeChange.hasOverflowed()) {
     388            LOG(Images, "BitmapImage %p frameImageAtIndex sizeChange=%u overflowed integer.", this, -sizeChange);
     389            destroyDecodedData(false);
     390            return nullptr;
     391        }
     392
    362393        if (imageObserver())
    363             imageObserver()->decodedSizeChanged(this, sizeChange);
     394            imageObserver()->decodedSizeChanged(this, checkedSizeChange.unsafeGet());
    364395    }
    365396
  • trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp

    r204983 r206244  
    11/*
    2  * Copyright (C) 2004, 2005, 2006, 2013 Apple Inc.  All rights reserved.
     2 * Copyright (C) 2004-2016 Apple Inc.  All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3939#include "IntRect.h"
    4040#include "Length.h"
     41#include "Logging.h"
    4142#include "SharedBuffer.h"
    4243#include "TextStream.h"
    4344#include <CoreGraphics/CGContext.h>
    4445#include <CoreGraphics/CGPDFDocument.h>
     46#include <wtf/CheckedArithmetic.h>
    4547#include <wtf/MathExtras.h>
    4648#include <wtf/RAMSize.h>
     
    182184        return;
    183185
     186    long long deltaBytes = m_cachedBytes - newCachedBytes;
     187
     188    Checked<int> checkedDeltaBytes = deltaBytes;
    184189    if (imageObserver())
    185         imageObserver()->decodedSizeChanged(this, -safeCast<int>(m_cachedBytes) + newCachedBytes);
     190        imageObserver()->decodedSizeChanged(this, -checkedDeltaBytes.unsafeGet());
    186191
    187192    ASSERT(s_allDecodedDataSize >= m_cachedBytes);
    188193    // Update with the difference in two steps to avoid unsigned underflow subtraction.
    189     s_allDecodedDataSize -= m_cachedBytes;
    190     s_allDecodedDataSize += newCachedBytes;
     194    if (!WTF::safeSub(s_allDecodedDataSize, m_cachedBytes, s_allDecodedDataSize))
     195        CRASH_WITH_SECURITY_IMPLICATION();
     196
     197    if (!WTF::safeAdd(s_allDecodedDataSize, newCachedBytes, s_allDecodedDataSize))
     198        CRASH_WITH_SECURITY_IMPLICATION();
    191199
    192200    m_cachedBytes = newCachedBytes;
     
    236244    if (m_pdfImageCachingPolicy == PDFImageCachingBelowMemoryLimit) {
    237245        IntSize scaledSize = ImageBuffer::compatibleBufferSize(cachedImageSize, context);
    238         if (s_allDecodedDataSize + safeCast<size_t>(scaledSize.width()) * scaledSize.height() * 4 - m_cachedBytes > s_maxDecodedDataSize) {
     246        Checked<size_t, RecordOverflow> scaledBytes = scaledSize.area() * 4;
     247
     248        if (scaledBytes.hasOverflowed()) {
     249            LOG(Images, "PDFDocumentImage %p updateCachedImageIfNeeded scaledBytes overflowed size_t.", this);
     250            destroyDecodedData();
     251            return;
     252        }
     253
     254        Checked<size_t, RecordOverflow> potentialDecodedDataSize = s_allDecodedDataSize + scaledBytes - m_cachedBytes;
     255        if (potentialDecodedDataSize.hasOverflowed() || potentialDecodedDataSize.unsafeGet() > s_maxDecodedDataSize) {
     256            LOG(Images, "PDFDocumentImage %p updateCachedImageIfNeeded potentialDecodedDataSize overflowed size_t.", this);
    239257            destroyDecodedData();
    240258            return;
     
    260278
    261279    IntSize internalSize = m_cachedImageBuffer->internalSize();
    262     decodedSizeChanged(safeCast<size_t>(internalSize.width()) * internalSize.height() * 4);
     280    Checked<size_t, RecordOverflow> scaledBytes = internalSize.area() * 4;
     281    if (scaledBytes.hasOverflowed()) {
     282        LOG(Images, "PDFDocumentImage %p updateCachedImageIfNeeded scaledBytes overflowed size_t.", this);
     283        destroyDecodedData();
     284        return;
     285    }
     286
     287    decodedSizeChanged(scaledBytes.unsafeGet());
    263288}
    264289
Note: See TracChangeset for help on using the changeset viewer.