diff --git a/APNGKit.xcodeproj/project.pbxproj b/APNGKit.xcodeproj/project.pbxproj index d50a8ed..e9c3081 100644 --- a/APNGKit.xcodeproj/project.pbxproj +++ b/APNGKit.xcodeproj/project.pbxproj @@ -48,6 +48,8 @@ 4B7D4ED61B9559BF005C0598 /* filter_neon_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B7D4ED41B9559BF005C0598 /* filter_neon_intrinsics.c */; }; 4B7D4ED71B9559BF005C0598 /* filter_neon.S in Sources */ = {isa = PBXBuildFile; fileRef = 4B7D4ED51B9559BF005C0598 /* filter_neon.S */; }; 4B7D4ED91B955CBF005C0598 /* arm_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B7D4ED81B955CBF005C0598 /* arm_init.c */; }; + 4BA1EFA7231767BE00D6D06C /* malformed-size.apng in Resources */ = {isa = PBXBuildFile; fileRef = 4BA1EFA6231767BD00D6D06C /* malformed-size.apng */; }; + 4BA1EFA8231767BE00D6D06C /* malformed-size.apng in Resources */ = {isa = PBXBuildFile; fileRef = 4BA1EFA6231767BD00D6D06C /* malformed-size.apng */; }; 4BF022041B94442800F00CDE /* APNGImageViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF022031B94442800F00CDE /* APNGImageViewTests.swift */; }; B25269641E8FD9840096A0A7 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B25269631E8FD9840096A0A7 /* libz.tbd */; }; B25269661E8FDA090096A0A7 /* GCDTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B19504F1E6D21670047B7DE /* GCDTimer.swift */; }; @@ -185,6 +187,7 @@ 4B7D4ED41B9559BF005C0598 /* filter_neon_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filter_neon_intrinsics.c; sourceTree = ""; }; 4B7D4ED51B9559BF005C0598 /* filter_neon.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = filter_neon.S; sourceTree = ""; }; 4B7D4ED81B955CBF005C0598 /* arm_init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arm_init.c; sourceTree = ""; }; + 4BA1EFA6231767BD00D6D06C /* malformed-size.apng */ = {isa = PBXFileReference; lastKnownFileType = file; name = "malformed-size.apng"; path = "TestImages/malformed-size.apng"; sourceTree = SOURCE_ROOT; }; 4BF022031B94442800F00CDE /* APNGImageViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APNGImageViewTests.swift; sourceTree = ""; }; B252695A1E8FD8EA0096A0A7 /* APNGKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = APNGKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B25269631E8FD9840096A0A7 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; @@ -371,6 +374,7 @@ D1614E1C1B91EDD700050104 /* TestImages */ = { isa = PBXGroup; children = ( + 4BA1EFA6231767BD00D6D06C /* malformed-size.apng */, 4B5DF6831B99718C00C4D421 /* demo.png */, D187FEE81B934F1B0013372D /* pyani.apng */, D190199F1B93351300E16EDB /* elephant_apng.apng */, @@ -575,6 +579,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -606,6 +611,7 @@ buildActionMask = 2147483647; files = ( D1614E251B91EDE200050104 /* over_previous.apng in Resources */, + 4BA1EFA7231767BE00D6D06C /* malformed-size.apng in Resources */, D1614E331B91EE0000050104 /* minimalAPNG.apng in Resources */, D19019A01B93351400E16EDB /* elephant_apng.apng in Resources */, D1614E261B91EDE200050104 /* spinfox.apng in Resources */, @@ -630,6 +636,7 @@ buildActionMask = 2147483647; files = ( B25310201E90AA3200A65CEA /* ball.apng in Resources */, + 4BA1EFA8231767BE00D6D06C /* malformed-size.apng in Resources */, B253101F1E90AA3200A65CEA /* minimalAPNG.apng in Resources */, B253101D1E90AA3200A65CEA /* elephant_apng.apng in Resources */, B25310231E90AA3200A65CEA /* over_previous.apng in Resources */, diff --git a/APNGKit/Disassembler.swift b/APNGKit/Disassembler.swift index cdf0678..02f2311 100644 --- a/APNGKit/Disassembler.swift +++ b/APNGKit/Disassembler.swift @@ -35,7 +35,8 @@ #endif let signatureOfPNGLength = 8 -let kMaxPNGSize: UInt32 = 1000000; +let kMaxPNGSize: UInt32 = 1000000 +let kUserAllocMaxBytes: UInt32 = 100*1024*1024 // Reading callback for libpng func readData(_ pngPointer: png_structp?, outBytes: png_bytep?, byteCountToRead: png_size_t) { @@ -60,8 +61,8 @@ struct APNGMeta { let firstFrameHidden: Bool - var length: UInt32 { - return height * rowBytes + var length: Int { + return Int(height) * Int(rowBytes) } var firstImageIndex: Int { @@ -291,6 +292,10 @@ class Disassembler { let height = png_get_image_height(pngPointer, infoPointer) let rowBytes = UInt32(png_get_rowbytes(pngPointer, infoPointer)) + if width > kMaxPNGSize || height > kMaxPNGSize { + throw DisassemblerError.fileSizeExceeded + } + // Decode acTL var frameCount: UInt32 = 0, playCount: UInt32 = 0 png_get_acTL(pngPointer, infoPointer, &frameCount, &playCount) @@ -312,7 +317,12 @@ class Disassembler { frameCount: frameCount, playCount: playCount, firstFrameHidden: firstFrameHidden) - + + if meta.length > kUserAllocMaxBytes { + throw DisassemblerError.fileSizeExceeded + + } + bufferFrame = Frame(length: meta.length, bytesInRow: meta.rowBytes) currentFrame = Frame(length: meta.length, bytesInRow: meta.rowBytes) apngMeta = meta diff --git a/APNGKit/Frame.swift b/APNGKit/Frame.swift index 4ea1154..43c6cda 100644 --- a/APNGKit/Frame.swift +++ b/APNGKit/Frame.swift @@ -88,8 +88,8 @@ class Frame { var duration: TimeInterval = 0 - init(length: UInt32, bytesInRow: UInt32) { - self.length = Int(length) + init(length: Int, bytesInRow: UInt32) { + self.length = length self.bytesInRow = Int(bytesInRow) self.bytes = UnsafeMutablePointer.allocate(capacity: self.length) diff --git a/APNGKitTests/APNGImageTests.swift b/APNGKitTests/APNGImageTests.swift index 5370535..b9e8f1a 100644 --- a/APNGKitTests/APNGImageTests.swift +++ b/APNGKitTests/APNGImageTests.swift @@ -198,6 +198,11 @@ class APNGImageTests: XCTestCase { let image = APNGImage(named: "", in: .testBundle) XCTAssertNil(image, "Empty string should result in nil") } + + func testOverflowImage() { + let image = APNGImage(named: "malformed-size", in: .testBundle) + XCTAssertNil(image) + } } private extension CocoaImage { diff --git a/TestImages/malformed-size.apng b/TestImages/malformed-size.apng new file mode 100644 index 0000000..48c75da Binary files /dev/null and b/TestImages/malformed-size.apng differ