From 9ccd35fb5f55a6c4f1902ac5b0f270f675750c27 Mon Sep 17 00:00:00 2001 From: Sohom Datta Date: Fri, 3 Jun 2022 20:10:52 +0530 Subject: [PATCH] fix: validate sampling factors (#106) --- lib/decoder.js | 9 ++++++++- test/index.js | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/decoder.js b/lib/decoder.js index d61a8b5..1982481 100644 --- a/lib/decoder.js +++ b/lib/decoder.js @@ -576,7 +576,9 @@ var JpegImage = (function jpegImage() { return array; } function prepareComponents(frame) { - var maxH = 0, maxV = 0; + // According to the JPEG standard, the sampling factor must be between 1 and 4 + // See https://github.com/libjpeg-turbo/libjpeg-turbo/blob/9abeff46d87bd201a952e276f3e4339556a403a3/libjpeg.txt#L1138-L1146 + var maxH = 1, maxV = 1; var component, componentId; for (componentId in frame.components) { if (frame.components.hasOwnProperty(componentId)) { @@ -745,6 +747,11 @@ var JpegImage = (function jpegImage() { var h = data[offset + 1] >> 4; var v = data[offset + 1] & 15; var qId = data[offset + 2]; + + if ( h <= 0 || v <= 0 ) { + throw new Error('Invalid sampling factor, expected values above 0'); + } + frame.componentsOrder.push(componentId); frame.components[componentId] = { h: h, diff --git a/test/index.js b/test/index.js index fd1339a..7f0edbb 100644 --- a/test/index.js +++ b/test/index.js @@ -7,10 +7,12 @@ function fixture(name) { return fs.readFileSync(path.join(__dirname, 'fixtures', name)); } -const SUPER_LARGE_JPEG_BASE64 = - '/9j/wJ39sP//DlKWvX+7xPlXkJa9f7v8DoDVAAD//zb6QAEAI2cBv3P/r4ADpX8Jf14AAAAAgCPE+VeQlr1/uwCAAAAVALNOjAGP2lIS'; +const SUPER_LARGE_JPEG_BASE64 = '/9j/wfFRBf//BdgC/9p/2P/E4d4='; + +const SUPER_LARGE_RESOLUTION_JPEG_BASE64 = '/9j/wfFR2PDh3g=='; const SUPER_LARGE_JPEG_BUFFER = Buffer.from(SUPER_LARGE_JPEG_BASE64, 'base64'); +const SUPER_LARGE_RESOLUTION_JPEG_BUFFER = Buffer.from(SUPER_LARGE_RESOLUTION_JPEG_BASE64, 'base64'); it('should be able read image with a bad e1 marker not preceeded by ff', function () { var jpegData = fixture('table-with-bad-e1.jpg'); @@ -274,8 +276,8 @@ it('should be able to decode large images within memory limits', () => { // See https://github.com/eugeneware/jpeg-js/issues/53 it('should limit resolution exposure', function () { - expect(() => jpeg.decode(SUPER_LARGE_JPEG_BUFFER)).toThrow( - 'maxResolutionInMP limit exceeded by 141MP', + expect(() => jpeg.decode(SUPER_LARGE_RESOLUTION_JPEG_BUFFER)).toThrow( + 'maxResolutionInMP limit exceeded by 3405MP', ); }); @@ -288,3 +290,9 @@ it('should limit memory exposure', function () { var jpegData = fixture('grumpycat.jpg'); expect(() => jpeg.decode(jpegData)).not.toThrow(); }, 30000); + +// See https://github.com/jpeg-js/jpeg-js/issues/105 +it('invalid sampling factor should error out', function () { + expect(() => jpeg.decode(Buffer.from('/9j/wfFR2AD/UdgA/9r/3g==', 'base64')).toThrow( + 'Invalid sampling factor, expected values above 0')) +});