Skip to content

Commit

Permalink
Add safety check for max allowed offset in xref table
Browse files Browse the repository at this point in the history
DEVSIX-8052

Autoported commit.
Original commit hash: [2c6c41403]
  • Loading branch information
guustysebie authored and iText-CI committed Jan 25, 2024
1 parent 165b316 commit 9643300
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
using System;
using iText.IO.Source;
using iText.Kernel.Exceptions;
using iText.Test;

Expand Down Expand Up @@ -108,5 +109,71 @@ public virtual void ZeroCapacityInConstructorWithHandlerTest() {
PdfXrefTable xrefTable = new PdfXrefTable(0, memoryLimitsAwareHandler);
NUnit.Framework.Assert.AreEqual(20, xrefTable.GetCapacity());
}

[NUnit.Framework.Test]
public virtual void XRefMaxValueLong() {
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
document.xref.Add(new PdfIndirectReferenceProxy(document, 11, long.MaxValue));
Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => {
document.Close();
}
);
NUnit.Framework.Assert.AreEqual(KernelExceptionMessageConstant.XREF_HAS_AN_ENTRY_WITH_TOO_BIG_OFFSET, e.Message
);
}

[NUnit.Framework.Test]
public virtual void MaxCrossReferenceOffSetReached() {
long justOver10gbLogical = 10_000_000_001L;
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
document.xref.Add(new PdfIndirectReferenceProxy(document, 11, justOver10gbLogical));
Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => {
document.Close();
}
);
NUnit.Framework.Assert.AreEqual(KernelExceptionMessageConstant.XREF_HAS_AN_ENTRY_WITH_TOO_BIG_OFFSET, e.Message
);
}

[NUnit.Framework.Test]
public virtual void MaxCrossReference() {
long justOver10gbLogical = 10_000_000_000L;
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
document.xref.Add(new PdfIndirectReferenceProxy(document, 11, justOver10gbLogical));
Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => {
document.Close();
}
);
NUnit.Framework.Assert.AreEqual(KernelExceptionMessageConstant.XREF_HAS_AN_ENTRY_WITH_TOO_BIG_OFFSET, e.Message
);
}

[NUnit.Framework.Test]
public virtual void JustBelowXrefThreshold() {
long maxAllowedOffset = 10_000_000_000L - 1L;
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
document.xref.Add(new PdfIndirectReferenceProxy(document, 11, maxAllowedOffset));
NUnit.Framework.Assert.DoesNotThrow(() => document.Close());
}

[NUnit.Framework.Test]
public virtual void XRefIntMax() {
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
document.xref.Add(new PdfIndirectReferenceProxy(document, 11, int.MaxValue));
NUnit.Framework.Assert.DoesNotThrow(() => document.Close());
}
}

internal class PdfIndirectReferenceProxy : PdfIndirectReference {
private readonly long offset;

public PdfIndirectReferenceProxy(PdfDocument document, int objNumber, long offset)
: base(document, objNumber) {
this.offset = offset;
}

public override long GetOffset() {
return offset;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,9 @@ public const String WHEN_ADDING_OBJECT_REFERENCE_TO_THE_TAG_TREE_IT_MUST_BE_CONN

public const String ARG_SHOULD_NOT_BE_NULL = "{0} should not be null.";

public const String XREF_HAS_AN_ENTRY_WITH_TOO_BIG_OFFSET = "Pdf document is to large to " + "use normal cross reference table. Use cross reference streams instead. To enable feature use com.itextpdf"
+ ".kernel.pdf.WriterProperties#setFullCompressionMode(true). ";

private KernelExceptionMessageConstant() {
}
}
Expand Down
14 changes: 14 additions & 0 deletions itext/itext.kernel/itext/kernel/pdf/PdfXrefTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ You should have received a copy of the GNU Affero General Public License
using iText.Commons.Utils;
using iText.IO.Source;
using iText.Kernel.Actions.Data;
using iText.Kernel.Exceptions;

namespace iText.Kernel.Pdf {
/// <summary>A representation of a cross-referenced table of a PDF document.</summary>
Expand All @@ -37,6 +38,16 @@ public class PdfXrefTable {

private const int MAX_GENERATION = 65535;

/// <summary>The maximum offset in a cross-reference stream.</summary>
/// <remarks>
/// The maximum offset in a cross-reference stream. This is a limitation of the PDF specification.
/// SPEC1.7: 7.5.4 Cross reference trailer
/// <para />
/// It states that the offset should be a 10-digit byte, so the maximum value is 9999999999.
/// This is the max value that can be represented in 10 bytes.
/// </remarks>
private const long MAX_OFFSET_IN_CROSS_REFERENCE_STREAM = 9_999_999_999L;

private static readonly byte[] freeXRefEntry = ByteUtils.GetIsoBytes("f \n");

private static readonly byte[] inUseXRefEntry = ByteUtils.GetIsoBytes("n \n");
Expand Down Expand Up @@ -352,6 +363,9 @@ protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, P
writer.WriteInteger(first).WriteSpace().WriteInteger(len).WriteByte((byte)'\n');
for (int i = first; i < first + len; i++) {
PdfIndirectReference reference = xrefTable.Get(i);
if (reference.GetOffset() > MAX_OFFSET_IN_CROSS_REFERENCE_STREAM) {
throw new PdfException(KernelExceptionMessageConstant.XREF_HAS_AN_ENTRY_WITH_TOO_BIG_OFFSET);
}
StringBuilder off = new StringBuilder("0000000000").Append(reference.GetOffset());
StringBuilder gen = new StringBuilder("00000").Append(reference.GetGenNumber());
writer.WriteString(off.JSubstring(off.Length - 10, off.Length)).WriteSpace().WriteString(gen.JSubstring(gen
Expand Down
2 changes: 1 addition & 1 deletion port-hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
916acd9b2d8d1906b9d5dd44634f9e7466b67125
2c6c41403156d1562a30281be5fa8c56e0b86c9a

0 comments on commit 9643300

Please sign in to comment.