Commit 1e41aa4
authored
fix: bound untrusted GeoJSON input to prevent parser resource exhaustion (#1733)
* fix: bound untrusted GeoJSON input to prevent parser resource exhaustion
#1699 and #1710 added nesting-depth guards, but they run on the tree that
Json.parseToJsonElement() has already fully materialised, so they act too late:
GeoJsonParser.parse() reads and materialises the whole untrusted document
before any check. A hostile layer can therefore still
- overflow the parser stack with deep nesting (StackOverflowError) before the
MAX_GEOMETRY_DEPTH=20 guard runs (contrast KmlParser, which bounds depth
*during* streaming via DepthLimitingReader);
- exhaust the heap with a wide, shallow document (OutOfMemoryError), which no
depth guard addresses;
- forward non-finite coordinates ("Infinity"/"NaN", accepted by
String.toDouble()) straight into LatLng/LatLngBounds.
The first two throw java.lang.Error subclasses, so the catch (Exception) in
DataLayerLoader does not contain them and the host app crashes on load.
Bound the input up front, before parseToJsonElement:
- readTextBounded() caps the characters read (configurable, default 10 MiB);
- checkStructuralDepth() rejects raw '{'/'[' nesting beyond a limit in a
single string-aware pass (configurable, default 512 - safe on small Android
stacks, far above any legitimate GeoJSON);
- parseCoordinates() rejects non-finite values.
Limits are constructor parameters with safe defaults, mirroring KmzParser.
Existing behaviour is preserved (incl. the #1699 depth-200 GeometryCollection
test); adds tests for each case.
* test: make the deep-nesting test reproduce the overflow deterministically
The previous version of this test could pass on unpatched code for an
unrelated reason: with the nesting inside "coordinates", a parse that
survives the stack reaches parseCoordinates(), which calls jsonPrimitive
on a JsonArray and throws IllegalArgumentException - the very type the
test asserts.
Move the nesting under "bbox", a member the parser never dereferences,
so nothing can reject the document first, and run the parse on a thread
with an explicit 1 MB stack so the outcome does not depend on the stack
size of the thread the test framework happens to use. 50 000 levels
overflow that stack whether or not the parser is JIT-compiled, while the
structural-depth check rejects the document at nesting level 513 without
recursing at all. A small document is parsed first so that class loading
is not charged to the bounded stack.
On main this test now fails with StackOverflowError instead of passing.1 parent fe802a4 commit 1e41aa4
2 files changed
Lines changed: 168 additions & 2 deletions
File tree
- data/src
- main/java/com/google/maps/android/data/parser/geojson
- test/java/com/google/maps/android/data/parser/geojson
Lines changed: 87 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
29 | 32 | | |
30 | | - | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
31 | 39 | | |
32 | 40 | | |
33 | 41 | | |
| |||
53 | 61 | | |
54 | 62 | | |
55 | 63 | | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
56 | 83 | | |
57 | 84 | | |
58 | 85 | | |
59 | 86 | | |
60 | 87 | | |
61 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
62 | 142 | | |
63 | 143 | | |
64 | 144 | | |
| |||
118 | 198 | | |
119 | 199 | | |
120 | 200 | | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
121 | 206 | | |
122 | 207 | | |
123 | 208 | | |
| |||
Lines changed: 81 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
326 | 326 | | |
327 | 327 | | |
328 | 328 | | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
329 | 410 | | |
330 | 411 | | |
331 | 412 | | |
| |||
0 commit comments