Skip to content

Commit e636212

Browse files
jan-sutterJan Sutter
andauthored
check for cycles during indirect reference resolution (UglyToad#1097)
Co-authored-by: Jan Sutter <jan@suttermail.de>
1 parent 3b318e1 commit e636212

File tree

1 file changed

+19
-10
lines changed

1 file changed

+19
-10
lines changed

src/UglyToad.PdfPig/PdfExtensions.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public static Memory<byte> Decode(this StreamToken stream, IFilterProvider filte
6666
{
6767
var filter = filters[i];
6868
totalMaxEstSize *= GetEstimatedSizeMultiplier(filter);
69-
69+
7070
transform = filter.Decode(transform, stream.StreamDictionary, filterProvider, i);
7171

7272
if (i < filters.Count - 1 && transform.Length > totalMaxEstSize)
@@ -93,9 +93,9 @@ public static Memory<byte> Decode(this StreamToken stream, ILookupFilterProvider
9393
{
9494
var filter = filters[i];
9595
totalMaxEstSize *= GetEstimatedSizeMultiplier(filter);
96-
96+
9797
transform = filter.Decode(transform, stream.StreamDictionary, filterProvider, i);
98-
98+
9999
if (i < filters.Count - 1 && transform.Length > totalMaxEstSize)
100100
{
101101
// Try to prevent malicious decompression, leading to OOM issues
@@ -122,25 +122,34 @@ private static double GetEstimatedSizeMultiplier(IFilter filter)
122122
/// Returns an equivalent token where any indirect references of child objects are
123123
/// recursively traversed and resolved.
124124
/// </summary>
125-
internal static T? Resolve<T>(this T? token, IPdfTokenScanner scanner) where T : IToken
125+
internal static T? Resolve<T>(this T? token, IPdfTokenScanner scanner, List<long>? visited = null) where T : IToken
126126
{
127-
return (T?)ResolveInternal(token, scanner);
127+
return (T?)ResolveInternal(token, scanner, visited ?? []);
128128
}
129129

130-
private static IToken? ResolveInternal(this IToken? token, IPdfTokenScanner scanner)
130+
private static IToken? ResolveInternal(this IToken? token, IPdfTokenScanner scanner, List<long> visited)
131131
{
132132
if (token is StreamToken stream)
133133
{
134-
return new StreamToken(Resolve(stream.StreamDictionary, scanner), stream.Data);
134+
return new StreamToken(Resolve(stream.StreamDictionary, scanner, visited), stream.Data);
135135
}
136136

137137
if (token is DictionaryToken dict)
138138
{
139139
var resolvedItems = new Dictionary<NameToken, IToken>();
140140
foreach (var kvp in dict.Data)
141141
{
142-
var value = kvp.Value is IndirectReferenceToken reference ? scanner.Get(reference.Data)?.Data : kvp.Value;
143-
resolvedItems[NameToken.Create(kvp.Key)] = ResolveInternal(value, scanner);
142+
var value = kvp.Value;
143+
if (kvp.Value is IndirectReferenceToken reference)
144+
{
145+
if (visited.Contains(reference.Data.ObjectNumber))
146+
{
147+
continue;
148+
}
149+
value = scanner.Get(reference.Data)?.Data;
150+
visited.Add(reference.Data.ObjectNumber);
151+
}
152+
resolvedItems[NameToken.Create(kvp.Key)] = ResolveInternal(value, scanner, visited);
144153
}
145154

146155
return new DictionaryToken(resolvedItems);
@@ -152,7 +161,7 @@ private static double GetEstimatedSizeMultiplier(IFilter filter)
152161
for (int i = 0; i < arr.Length; i++)
153162
{
154163
var value = arr.Data[i] is IndirectReferenceToken reference ? scanner.Get(reference.Data)?.Data : arr.Data[i];
155-
resolvedItems.Add(ResolveInternal(value, scanner));
164+
resolvedItems.Add(ResolveInternal(value, scanner, visited));
156165
}
157166
return new ArrayToken(resolvedItems);
158167
}

0 commit comments

Comments
 (0)