From c93f79daa7f3098e842898ae9c5ddc8380657448 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 20 Jan 2015 10:38:44 +0000 Subject: [PATCH] Guard against InitImage failure #150 Protects against truncated image headers --- package.json | 2 +- src/metadata.cc | 10 +++++++++- src/resize.cc | 10 +++++++++- test/fixtures/corrupt-header.jpg | Bin 0 -> 1024 bytes test/fixtures/index.js | 1 + test/unit/io.js | 16 ++++++++++++++++ test/unit/metadata.js | 16 ++++++++++++++++ 7 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/corrupt-header.jpg diff --git a/package.json b/package.json index 34d75082..4c198cdd 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ ], "description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library", "scripts": { - "test": "node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=10000 ./test/unit/*.js" + "test": "VIPS_WARNING=0 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=10000 ./test/unit/*.js" }, "main": "index.js", "repository": { diff --git a/src/metadata.cc b/src/metadata.cc index 06c6ff0c..c6e00a00 100755 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -62,6 +62,10 @@ class MetadataWorker : public NanAsyncWorker { imageType = DetermineImageType(baton->bufferIn, baton->bufferInLength); if (imageType != ImageType::UNKNOWN) { image = InitImage(imageType, baton->bufferIn, baton->bufferInLength, VIPS_ACCESS_RANDOM); + if (image == NULL) { + (baton->err).append("Input buffer has corrupt header"); + imageType = ImageType::UNKNOWN; + } } else { (baton->err).append("Input buffer contains unsupported image format"); } @@ -70,8 +74,12 @@ class MetadataWorker : public NanAsyncWorker { imageType = DetermineImageType(baton->fileIn.c_str()); if (imageType != ImageType::UNKNOWN) { image = InitImage(imageType, baton->fileIn.c_str(), VIPS_ACCESS_RANDOM); + if (image == NULL) { + (baton->err).append("Input file has corrupt header"); + imageType = ImageType::UNKNOWN; + } } else { - (baton->err).append("File is of an unsupported image format"); + (baton->err).append("Input file is of an unsupported image format"); } } if (image != NULL && imageType != ImageType::UNKNOWN) { diff --git a/src/resize.cc b/src/resize.cc index 0053f0e9..a0ccdd0c 100755 --- a/src/resize.cc +++ b/src/resize.cc @@ -153,6 +153,10 @@ class ResizeWorker : public NanAsyncWorker { inputImageType = DetermineImageType(baton->bufferIn, baton->bufferInLength); if (inputImageType != ImageType::UNKNOWN) { image = InitImage(inputImageType, baton->bufferIn, baton->bufferInLength, baton->accessMethod); + if (image == NULL) { + (baton->err).append("Input buffer has corrupt header"); + inputImageType = ImageType::UNKNOWN; + } } else { (baton->err).append("Input buffer contains unsupported image format"); } @@ -161,8 +165,12 @@ class ResizeWorker : public NanAsyncWorker { inputImageType = DetermineImageType(baton->fileIn.c_str()); if (inputImageType != ImageType::UNKNOWN) { image = InitImage(inputImageType, baton->fileIn.c_str(), baton->accessMethod); + if (image == NULL) { + (baton->err).append("Input file has corrupt header"); + inputImageType = ImageType::UNKNOWN; + } } else { - (baton->err).append("File is of an unsupported image format"); + (baton->err).append("Input file is of an unsupported image format"); } } if (inputImageType == ImageType::UNKNOWN) { diff --git a/test/fixtures/corrupt-header.jpg b/test/fixtures/corrupt-header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e241eb02433b3363ffef42ffc9756f520c71b41 GIT binary patch literal 1024 zcmeH`Jxc>Y5Qb;(5))IHpkl!Iag9VQWbaH+u1fGT;1@=;R#Xy;oDd-vB4QCmM3NL1 zf)Z401RKH9+RoNe!JlAZ7vH_zXbOLV;pXPa(!LpqC5;Pvg zn_yO!8iuoIWtnqN#47>!JVmfpk?~WpR>jZ2UKPIt`zmr@FZOFz90CWF<`$Y_#YcYB zbq}Vhs?Fq_Rpr`R4SQ8(A3vef70-ZMu4E05=xtE(6F77w*NT+k2BvGDTR$YkZlnfC zS_A71+|TbMEpC`GJB}y*XUyFX`pt!Aycr#Ti5n2va2{Cw q`!HBW#V`LKdK;u&(V#>xrNw1pa&VutH;+JSb~=d=eb=ky!i?N)vO literal 0 HcmV?d00001 diff --git a/test/fixtures/index.js b/test/fixtures/index.js index 9d0e657e..d497430c 100755 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -14,6 +14,7 @@ module.exports = { inputJpgWithGammaHoliness: getPath('gamma_dalai_lama_gray.jpg'), // http://www.4p8.com/eric.brasseur/gamma.html inputJpgWithCmykProfile: getPath('Channel_digital_image_CMYK_color.jpg'), // http://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg inputJpgWithCmykNoProfile: getPath('Channel_digital_image_CMYK_color_no_profile.jpg'), + inputJpgWithCorruptHeader: getPath('corrupt-header.jpg'), inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png inputPngWithTransparency: getPath('blackbug.png'), // public domain diff --git a/test/unit/io.js b/test/unit/io.js index c531557e..994bb184 100755 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -292,6 +292,22 @@ describe('Input/output', function() { }); }); + it('File input with corrupt header fails gracefully', function(done) { + sharp(fixtures.inputJpgWithCorruptHeader) + .toBuffer(function(err) { + assert.strictEqual(true, !!err); + done(); + }); + }); + + it('Buffer input with corrupt header fails gracefully', function(done) { + sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) + .toBuffer(function(err) { + assert.strictEqual(true, !!err); + done(); + }); + }); + describe('Output filename without extension uses input format', function() { it('JPEG', function(done) { diff --git a/test/unit/metadata.js b/test/unit/metadata.js index db741d38..272e9162 100755 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -216,4 +216,20 @@ describe('Image metadata', function() { }); }); + it('File input with corrupt header fails gracefully', function(done) { + sharp(fixtures.inputJpgWithCorruptHeader) + .metadata(function(err) { + assert.strictEqual(true, !!err); + done(); + }); + }); + + it('Buffer input with corrupt header fails gracefully', function(done) { + sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) + .metadata(function(err) { + assert.strictEqual(true, !!err); + done(); + }); + }); + });