🐛 Do not read beyond arraybuffer bounds

This commit is contained in:
C-3PO 2018-07-05 02:17:28 +02:00
parent 397e1fd172
commit 4fb3d1322c
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
4 changed files with 6 additions and 8 deletions

View file

@ -13,15 +13,12 @@ export default async function getSolidpkg(product: Product, from: number, to: nu
if (!verifyProductName(product)) { if (!verifyProductName(product)) {
throw new TypeError(`"${product}" is not a valid product.`); throw new TypeError(`"${product}" is not a valid product.`);
} }
if (typeof from !== 'number' || (from | 0) !== from || from < -1) { if (typeof from !== 'number' || (from | 0) !== from || from < -1 || from > 999) {
throw new TypeError(`from must be an integer greater than or equal to -1 but it is "${from}"`); throw new TypeError(`from must be an integer greater than or equal to -1 but it is "${from}"`);
} }
if (typeof to !== 'number' || (to | 0) !== to || to < 0) { if (typeof to !== 'number' || (to | 0) !== to || to < 0 || to > 999) {
throw new TypeError(`to must be an integer greater than or equal to 0 but it is "${to}"`); throw new TypeError(`to must be an integer greater than or equal to 0 but it is "${to}"`);
} }
if (from >= to) {
throw new TypeError(`from must be less than to but "${from}" is not less than "${to}".`);
}
//Download .solidpkg file //Download .solidpkg file
const ssnFile = await getUrlContents({ host: 'cdn-patch.swtor.com', path: `/patch/${product}/${product}_${from}to${to}.solidpkg` }); const ssnFile = await getUrlContents({ host: 'cdn-patch.swtor.com', path: `/patch/${product}/${product}_${from}to${to}.solidpkg` });

View file

@ -4,14 +4,14 @@ const BUFFER_SIZE = 16 * 1024;
export default function arrayBufferToStream(arrayBuffer: ArrayBuffer, offset = 0): stream.Readable { export default function arrayBufferToStream(arrayBuffer: ArrayBuffer, offset = 0): stream.Readable {
if (offset < 0 || offset + 1 >= arrayBuffer.byteLength) { if (offset < 0 || offset + 1 >= arrayBuffer.byteLength) {
throw new Error('Could not convert ArrayBuffer to ReadableStream; out of bounds.'); throw new RangeError('Could not convert ArrayBuffer to ReadableStream; out of bounds.');
} }
let position = offset; let position = offset;
const outStream = new stream.Readable({ const outStream = new stream.Readable({
encoding: 'binary', encoding: 'binary',
read(size) { read(size) {
const chunkSize = size || BUFFER_SIZE; //TODO: we can probably remove BUFFER_SIZE const chunkSize = Math.min(size || BUFFER_SIZE, arrayBuffer.byteLength - position); //TODO: we can probably remove BUFFER_SIZE
let needMoreData: boolean; let needMoreData: boolean;
do { do {
//If end is reached //If end is reached

View file

@ -3,7 +3,7 @@ import * as stream from 'stream';
/** Takes the given ReadableStream and returns a ReadableStream with the same contents but that terminates after the given length. */ /** Takes the given ReadableStream and returns a ReadableStream with the same contents but that terminates after the given length. */
export default function streamSetMaxLength(inputStream: stream.Readable, maxLength: number): stream.Readable { export default function streamSetMaxLength(inputStream: stream.Readable, maxLength: number): stream.Readable {
if (maxLength <= 0) { if (maxLength <= 0) {
throw new Error('maxLength is out of bounds.'); throw new RangeError('maxLength is out of bounds.');
} }
let remaining = maxLength; let remaining = maxLength;

View file

@ -53,6 +53,7 @@ export default function verifySolidpkg(file: ISolid, { product, from, to }: {pro
} }
} }
//64kb, 256kb, 512kb, 4mb
if (!([0x1_0000, 0x4_0000, 0x8_0000, 0x40_0000]).includes(file.info['piece length'])) { if (!([0x1_0000, 0x4_0000, 0x8_0000, 0x40_0000]).includes(file.info['piece length'])) {
throw new Error(`Expected piece length to be "65536", "262144", 524288" or "4194304" but it was "${file.info['piece length']}".`); throw new Error(`Expected piece length to be "65536", "262144", 524288" or "4194304" but it was "${file.info['piece length']}".`);
} }