1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-22 16:18:08 +02:00

Validate even more dictionary properties

This checks primarily Arrays, but also some other properties, that we'll end up sending (sometimes indirectly) to the main-thread.
This commit is contained in:
Jonas Jenwald 2024-04-29 23:07:41 +02:00
parent 1b811ac113
commit 52f7ff155d
8 changed files with 125 additions and 64 deletions

View file

@ -43,6 +43,7 @@ import {
getInheritableProperty,
getRotationMatrix,
isAscii,
isNumberArray,
numberToString,
stringToUTF16String,
} from "./core_utils.js";
@ -550,7 +551,7 @@ function getQuadPoints(dict, rect) {
// Each quadrilateral must consist of eight coordinates.
const quadPoints = dict.getArray("QuadPoints");
if (
!Array.isArray(quadPoints) ||
!isNumberArray(quadPoints, null) ||
quadPoints.length === 0 ||
quadPoints.length % 8 > 0
) {
@ -914,10 +915,9 @@ class Annotation {
* @param {Array} rectangle - The rectangle array with exactly four entries
*/
setRectangle(rectangle) {
this.rectangle =
Array.isArray(rectangle) && rectangle.length === 4
? Util.normalizeRect(rectangle)
: [0, 0, 0, 0];
this.rectangle = isNumberArray(rectangle, 4)
? Util.normalizeRect(rectangle)
: [0, 0, 0, 0];
}
/**
@ -1150,8 +1150,14 @@ class Annotation {
["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"],
appearance
);
const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1];
const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0];
let bbox = appearanceDict.getArray("BBox");
if (!isNumberArray(bbox, 4)) {
bbox = [0, 0, 1, 1];
}
let matrix = appearanceDict.getArray("Matrix");
if (!isNumberArray(matrix, 6)) {
matrix = [1, 0, 0, 1, 0, 0];
}
const transform = getTransformMatrix(rect, bbox, matrix);
const opList = new OperatorList();
@ -1248,10 +1254,19 @@ class Annotation {
if (text.length > 1 || text[0]) {
const appearanceDict = this.appearance.dict;
let bbox = appearanceDict.getArray("BBox");
if (!isNumberArray(bbox, 4)) {
bbox = null;
}
let matrix = appearanceDict.getArray("Matrix");
if (!isNumberArray(matrix, 6)) {
matrix = null;
}
this.data.textPosition = this._transformPoint(
firstPosition,
appearanceDict.getArray("BBox"),
appearanceDict.getArray("Matrix")
bbox,
matrix
);
this.data.textContent = text;
}
@ -1401,7 +1416,7 @@ class AnnotationBorderStyle {
setWidth(width, rect = [0, 0, 0, 0]) {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
Array.isArray(rect) && rect.length === 4,
isNumberArray(rect, 4),
"A valid `rect` parameter must be provided."
);
}
@ -2972,7 +2987,8 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
: this.uncheckedAppearance;
if (appearance) {
const savedAppearance = this.appearance;
const savedMatrix = appearance.dict.getArray("Matrix") || IDENTITY_MATRIX;
const matrix = appearance.dict.getArray("Matrix");
const savedMatrix = isNumberArray(matrix, 6) ? matrix : IDENTITY_MATRIX;
if (rotation) {
appearance.dict.set(
@ -3739,10 +3755,9 @@ class PopupAnnotation extends Annotation {
}
const parentRect = parentItem.getArray("Rect");
this.data.parentRect =
Array.isArray(parentRect) && parentRect.length === 4
? Util.normalizeRect(parentRect)
: null;
this.data.parentRect = isNumberArray(parentRect, 4)
? Util.normalizeRect(parentRect)
: null;
const rt = parentItem.get("RT");
if (isName(rt, AnnotationReplyType.GROUP)) {
@ -4030,7 +4045,10 @@ class LineAnnotation extends MarkupAnnotation {
this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = false;
const lineCoordinates = dict.getArray("L");
let lineCoordinates = dict.getArray("L");
if (!isNumberArray(lineCoordinates, 4)) {
lineCoordinates = [0, 0, 0, 0];
}
this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
@ -4225,7 +4243,7 @@ class PolylineAnnotation extends MarkupAnnotation {
// horizontal and vertical coordinates, respectively, of each vertex.
// Convert this to an array of objects with x and y coordinates.
const rawVertices = dict.getArray("Vertices");
if (!Array.isArray(rawVertices)) {
if (!isNumberArray(rawVertices, null)) {
return;
}
for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
@ -4314,11 +4332,15 @@ class InkAnnotation extends MarkupAnnotation {
// of each vertex. Convert this to an array of objects with x and y
// coordinates.
this.data.inkLists.push([]);
if (!Array.isArray(rawInkLists[i])) {
continue;
}
for (let j = 0, jj = rawInkLists[i].length; j < jj; j += 2) {
this.data.inkLists[i].push({
x: xref.fetchIfRef(rawInkLists[i][j]),
y: xref.fetchIfRef(rawInkLists[i][j + 1]),
});
const x = xref.fetchIfRef(rawInkLists[i][j]),
y = xref.fetchIfRef(rawInkLists[i][j + 1]);
if (typeof x === "number" && typeof y === "number") {
this.data.inkLists[i].push({ x, y });
}
}
}

View file

@ -15,6 +15,7 @@
import {
collectActions,
isNumberArray,
MissingDataException,
PDF_VERSION_REGEXP,
recoverJsURL,
@ -388,8 +389,7 @@ class Catalog {
// We only need to parse the color when it's valid, and non-default.
if (
Array.isArray(color) &&
color.length === 3 &&
isNumberArray(color, 3) &&
(color[0] !== 0 || color[1] !== 0 || color[2] !== 0)
) {
rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);

View file

@ -218,6 +218,21 @@ function isWhiteSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
}
/**
* Checks if something is an Array containing only boolean values,
* and (optionally) checks its length.
* @param {any} arr
* @param {number | null} len
* @returns {boolean}
*/
function isBooleanArray(arr, len) {
return (
Array.isArray(arr) &&
(len === null || arr.length === len) &&
arr.every(x => typeof x === "boolean")
);
}
/**
* Checks if something is an Array containing only numbers,
* and (optionally) checks its length.
@ -652,6 +667,7 @@ export {
getRotationMatrix,
getSizeInBytes,
isAscii,
isBooleanArray,
isNumberArray,
isWhiteSpace,
log2,

View file

@ -39,6 +39,7 @@ import {
collectActions,
getInheritableProperty,
getNewAnnotationsMap,
isNumberArray,
isWhiteSpace,
MissingDataException,
PDF_VERSION_REGEXP,
@ -162,7 +163,7 @@ class Page {
}
let box = this._getInheritableProperty(name, /* getArray = */ true);
if (Array.isArray(box) && box.length === 4) {
if (isNumberArray(box, 4)) {
box = Util.normalizeRect(box);
if (box[2] - box[0] > 0 && box[3] - box[1] > 0) {
return box;

View file

@ -460,12 +460,12 @@ class PartialEvaluator {
localColorSpaceCache
) {
const dict = xobj.dict;
const matrix = dict.getArray("Matrix");
let matrix = dict.getArray("Matrix");
if (!isNumberArray(matrix, 6)) {
matrix = null;
}
let bbox = dict.getArray("BBox");
bbox =
Array.isArray(bbox) && bbox.length === 4
? Util.normalizeRect(bbox)
: null;
bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
let optionalContent, groupOptions;
if (dict.has("OC")) {
@ -1578,7 +1578,10 @@ class PartialEvaluator {
localShadingPatternCache,
});
if (objId) {
const matrix = dict.getArray("Matrix");
let matrix = dict.getArray("Matrix");
if (!isNumberArray(matrix, 6)) {
matrix = null;
}
operatorList.addOp(fn, ["Shading", objId, matrix]);
}
return undefined;
@ -3266,7 +3269,7 @@ class PartialEvaluator {
const xObjStateManager = new StateManager(currentState);
const matrix = xobj.dict.getArray("Matrix");
if (Array.isArray(matrix) && matrix.length === 6) {
if (isNumberArray(matrix, 6)) {
xObjStateManager.transform(matrix);
}

View file

@ -16,14 +16,19 @@
import {
assert,
FormatError,
IDENTITY_MATRIX,
info,
unreachable,
Util,
warn,
} from "../shared/util.js";
import {
isBooleanArray,
isNumberArray,
MissingDataException,
} from "./core_utils.js";
import { BaseStream } from "./base_stream.js";
import { ColorSpace } from "./colorspace.js";
import { MissingDataException } from "./core_utils.js";
const ShadingType = {
FUNCTION_BASED: 1,
@ -106,8 +111,17 @@ class BaseShading {
class RadialAxialShading extends BaseShading {
constructor(dict, xref, resources, pdfFunctionFactory, localColorSpaceCache) {
super();
this.coordsArr = dict.getArray("Coords");
this.shadingType = dict.get("ShadingType");
let coordsLen = 0;
if (this.shadingType === ShadingType.AXIAL) {
coordsLen = 4;
} else if (this.shadingType === ShadingType.RADIAL) {
coordsLen = 6;
}
this.coordsArr = dict.getArray("Coords");
if (!isNumberArray(this.coordsArr, coordsLen)) {
throw new FormatError("RadialAxialShading: Invalid /Coords array.");
}
const cs = ColorSpace.parse({
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
xref,
@ -116,25 +130,20 @@ class RadialAxialShading extends BaseShading {
localColorSpaceCache,
});
const bbox = dict.getArray("BBox");
this.bbox =
Array.isArray(bbox) && bbox.length === 4
? Util.normalizeRect(bbox)
: null;
this.bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
let t0 = 0.0,
t1 = 1.0;
if (dict.has("Domain")) {
const domainArr = dict.getArray("Domain");
t0 = domainArr[0];
t1 = domainArr[1];
const domainArr = dict.getArray("Domain");
if (isNumberArray(domainArr, 2)) {
[t0, t1] = domainArr;
}
let extendStart = false,
extendEnd = false;
if (dict.has("Extend")) {
const extendArr = dict.getArray("Extend");
extendStart = extendArr[0];
extendEnd = extendArr[1];
const extendArr = dict.getArray("Extend");
if (isBooleanArray(extendArr, 2)) {
[extendStart, extendEnd] = extendArr;
}
if (
@ -271,8 +280,7 @@ class RadialAxialShading extends BaseShading {
}
getIR() {
const coordsArr = this.coordsArr;
const shadingType = this.shadingType;
const { coordsArr, shadingType } = this;
let type, p0, p1, r0, r1;
if (shadingType === ShadingType.AXIAL) {
p0 = [coordsArr[0], coordsArr[1]];
@ -454,10 +462,7 @@ class MeshShading extends BaseShading {
const dict = stream.dict;
this.shadingType = dict.get("ShadingType");
const bbox = dict.getArray("BBox");
this.bbox =
Array.isArray(bbox) && bbox.length === 4
? Util.normalizeRect(bbox)
: null;
this.bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
const cs = ColorSpace.parse({
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
xref,
@ -983,17 +988,32 @@ class DummyShading extends BaseShading {
}
function getTilingPatternIR(operatorList, dict, color) {
const matrix = dict.getArray("Matrix");
const bbox = Util.normalizeRect(dict.getArray("BBox"));
const xstep = dict.get("XStep");
const ystep = dict.get("YStep");
const paintType = dict.get("PaintType");
const tilingType = dict.get("TilingType");
let matrix = dict.getArray("Matrix");
if (!isNumberArray(matrix, 6)) {
matrix = IDENTITY_MATRIX;
}
let bbox = dict.getArray("BBox");
bbox = isNumberArray(bbox, 4) ? Util.normalizeRect(bbox) : null;
// Ensure that the pattern has a non-zero width and height, to prevent errors
// in `pattern_helper.js` (fixes issue8330.pdf).
if (bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) {
throw new FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`);
if (!bbox || bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) {
throw new FormatError(`Invalid getTilingPatternIR /BBox array.`);
}
const xstep = dict.get("XStep");
if (typeof xstep !== "number") {
throw new FormatError(`Invalid getTilingPatternIR /XStep value.`);
}
const ystep = dict.get("YStep");
if (typeof ystep !== "number") {
throw new FormatError(`Invalid getTilingPatternIR /YStep value.`);
}
const paintType = dict.get("PaintType");
if (!Number.isInteger(paintType)) {
throw new FormatError(`Invalid getTilingPatternIR /PaintType value.`);
}
const tilingType = dict.get("TilingType");
if (!Number.isInteger(tilingType)) {
throw new FormatError(`Invalid getTilingPatternIR /TilingType value.`);
}
return [

View file

@ -2465,10 +2465,9 @@ class CanvasGraphics {
this.save();
this.baseTransformStack.push(this.baseTransform);
if (Array.isArray(matrix) && matrix.length === 6) {
if (matrix) {
this.transform(...matrix);
}
this.baseTransform = getCurrentTransform(this.ctx);
if (bbox) {
@ -2652,7 +2651,7 @@ class CanvasGraphics {
this.ctx.setTransform(...this.baseTransform);
}
if (Array.isArray(rect) && rect.length === 4) {
if (rect) {
const width = rect[2] - rect[0];
const height = rect[3] - rect[1];

View file

@ -455,7 +455,7 @@ class TilingPattern {
constructor(IR, color, ctx, canvasGraphicsFactory, baseTransform) {
this.operatorList = IR[2];
this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
this.matrix = IR[3];
this.bbox = IR[4];
this.xstep = IR[5];
this.ystep = IR[6];