From 9b6325b6bca516a5c4c7b8dc7fc884fd0bc36eeb Mon Sep 17 00:00:00 2001 From: Sohom Date: Thu, 2 Jun 2022 23:34:05 +0530 Subject: [PATCH 1/2] Add limits on sampling factors Invalid sampling factors can lead to a divide by zero error which could eventually lead to a infinite loop. Also fixed failing tests + add a new test for invalid sampling factors. fixes #105 --- lib/decoder.js | 7 ++++++- test/index.js | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/decoder.js b/lib/decoder.js index d61a8b5..e03ef8e 100644 --- a/lib/decoder.js +++ b/lib/decoder.js @@ -576,7 +576,7 @@ var JpegImage = (function jpegImage() { return array; } function prepareComponents(frame) { - var maxH = 0, maxV = 0; + var maxH = 1, maxV = 1; var component, componentId; for (componentId in frame.components) { if (frame.components.hasOwnProperty(componentId)) { @@ -745,6 +745,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')) +}); From 04cb2dc95320f1afbd9d7c4b3ad095b23e3e264f Mon Sep 17 00:00:00 2001 From: Sohom Date: Fri, 3 Jun 2022 12:13:05 +0530 Subject: [PATCH 2/2] Add explainer link and comment for sampling factor initialization --- lib/decoder.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/decoder.js b/lib/decoder.js index e03ef8e..1982481 100644 --- a/lib/decoder.js +++ b/lib/decoder.js @@ -576,6 +576,8 @@ var JpegImage = (function jpegImage() { return array; } function prepareComponents(frame) { + // 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) {