From 637b152b86f8676cbdb3dc85a5b55462f52428a4 Mon Sep 17 00:00:00 2001 From: Maxim Date: Sat, 3 Oct 2026 21:46:25 +0300 Subject: [PATCH] Add index data size validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../pd/font/cff/CFFFileBaseParser.java | 15 ++++- .../pd/font/cff/CFFFileBaseParserTest.java | 62 +++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/verapdf/pd/font/cff/CFFFileBaseParserTest.java diff --git a/src/main/java/org/verapdf/pd/font/cff/CFFFileBaseParser.java b/src/main/java/org/verapdf/pd/font/cff/CFFFileBaseParser.java index fab47307..53b17563 100644 --- a/src/main/java/org/verapdf/pd/font/cff/CFFFileBaseParser.java +++ b/src/main/java/org/verapdf/pd/font/cff/CFFFileBaseParser.java @@ -34,6 +34,8 @@ */ class CFFFileBaseParser { + private static final long MAX_INDEX_DATA_SIZE = 100_000_000; + protected SeekableInputStream source; protected CFFIndex definedNames; @@ -73,15 +75,22 @@ protected CFFIndex readIndex() throws IOException { return new CFFIndex(0, 0, new int[0], new byte[0]); } int offSize = readCard8(); - if (offSize == 0) { - throw new IOException("Bad offset size"); + if (offSize < 1 || offSize > 4) { + throw new IOException("Bad offset size " + offSize); } int[] offset = new int[count + 1]; for (int i = 0; i < count + 1; ++i) { offset[i] = (int) readOffset(offSize); } if (offset[count] < 1) { - throw new IOException("Wrong index data offset"); + throw new IOException("Wrong index data offset " + offset[count]); + } + long dataSize = offset[count] - 1L; + if (dataSize > MAX_INDEX_DATA_SIZE) { + throw new IOException("Index data size exceeds maximum allowed size"); + } + if (dataSize > source.getStreamLength() - source.getOffset()) { + throw new IOException("Index data size exceeds remaining stream length"); } byte[] data = new byte[offset[count] - 1]; if (data.length != 0 && source.read(data, data.length) != data.length) { diff --git a/src/test/java/org/verapdf/pd/font/cff/CFFFileBaseParserTest.java b/src/test/java/org/verapdf/pd/font/cff/CFFFileBaseParserTest.java new file mode 100644 index 00000000..5dbb31e7 --- /dev/null +++ b/src/test/java/org/verapdf/pd/font/cff/CFFFileBaseParserTest.java @@ -0,0 +1,62 @@ +/* + * This file is part of veraPDF Parser, a module of the veraPDF project. + * Copyright (c) 2015-2026, veraPDF Consortium + * All rights reserved. + * + * veraPDF Parser is free software: you can redistribute it and/or modify + * it under the terms of either: + * + * The GNU General public license GPLv3+. + * You should have received a copy of the GNU General Public License + * along with veraPDF Parser as the LICENSE.GPL file in the root of the source + * tree. If not, see http://www.gnu.org/licenses/ or + * https://www.gnu.org/licenses/gpl-3.0.en.html. + * + * The Mozilla Public License MPLv2+. + * You should have received a copy of the Mozilla Public License along with + * veraPDF Parser as the LICENSE.MPL file in the root of the source tree. + * If a copy of the MPL was not distributed with this file, you can obtain one at + * http://mozilla.org/MPL/2.0/. + */ +package org.verapdf.pd.font.cff; + +import org.junit.Test; +import org.verapdf.as.io.ASMemoryInStream; +import org.verapdf.io.SeekableInputStream; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class CFFFileBaseParserTest { + + private static CFFFileBaseParser parser(int... bytes) throws IOException { + byte[] data = new byte[bytes.length]; + for (int i = 0; i < bytes.length; ++i) { + data[i] = (byte) bytes[i]; + } + return new CFFFileBaseParser(SeekableInputStream.getSeekableStream(new ASMemoryInStream(data))); + } + + @Test(expected = IOException.class) + public void testReadIndexWithOversizedLastOffset() throws IOException { + parser(0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x3F, 0xFF, 0xFF, 0xFF).readIndex(); + } + + @Test(expected = IOException.class) + public void testReadIndexWithNegativeLastOffset() throws IOException { + parser(0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF).readIndex(); + } + + @Test(expected = IOException.class) + public void testReadIndexWithOversizedOffSize() throws IOException { + parser(0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04).readIndex(); + } + + @Test + public void testReadValidIndex() throws IOException { + CFFIndex index = parser(0x00, 0x01, 0x01, 0x01, 0x04, 'a', 'b', 'c').readIndex(); + assertEquals(1, index.size()); + assertEquals(3, index.getDataLength()); + } +}