Skip to content

Commit a10b201

Browse files
authored
Merge pull request #1843 from dhensby/fix/udt-parser
fix: improve geography/geometry parser robustness
2 parents f16650d + 7138b66 commit a10b201

2 files changed

Lines changed: 345 additions & 23 deletions

File tree

lib/udt.js

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ const SEGMENT = {
4444
FIRST_ARC: 0x03
4545
}; */
4646

47+
const ensureBytes = (buffer, needed) => {
48+
if (buffer.position + needed > buffer.length) {
49+
throw new Error(`Corrupt or truncated spatial data: expected ${needed} bytes at position ${buffer.position}, but only ${buffer.length - buffer.position} bytes remain`)
50+
}
51+
}
52+
4753
class Point {
4854
constructor () {
4955
this.x = 0
@@ -64,6 +70,8 @@ const parsePoints = (buffer, count, isGeometryPoint) => {
6470
return points
6571
}
6672

73+
ensureBytes(buffer, count * 16)
74+
6775
if (isGeometryPoint) {
6876
// GEOMETRY POINT (s2.1.6): x then y.
6977
for (let i = 1; i <= count; i++) {
@@ -101,6 +109,8 @@ const parseZ = (buffer, points) => {
101109
return
102110
}
103111

112+
ensureBytes(buffer, points.length * 8)
113+
104114
points.forEach(point => {
105115
point.z = buffer.readDoubleLE(buffer.position)
106116
buffer.position += 8
@@ -114,6 +124,8 @@ const parseM = (buffer, points) => {
114124
return
115125
}
116126

127+
ensureBytes(buffer, points.length * 8)
128+
117129
points.forEach(point => {
118130
point.m = buffer.readDoubleLE(buffer.position)
119131
buffer.position += 8
@@ -139,6 +151,8 @@ const parseFigures = (buffer, count, properties) => {
139151
pointOffset: 0
140152
})
141153
} else {
154+
ensureBytes(buffer, count * 5)
155+
142156
for (let i = 1; i <= count; i++) {
143157
figures.push({
144158
attribute: buffer.readUInt8(buffer.position),
@@ -173,6 +187,8 @@ const parseShapes = (buffer, count, properties) => {
173187
type: 0x02
174188
})
175189
} else {
190+
ensureBytes(buffer, count * 9)
191+
176192
for (let i = 1; i <= count; i++) {
177193
shapes.push({
178194
parentOffset: buffer.readInt32LE(buffer.position),
@@ -195,6 +211,8 @@ const parseSegments = (buffer, count) => {
195211
return segments
196212
}
197213

214+
ensureBytes(buffer, count)
215+
198216
for (let i = 1; i <= count; i++) {
199217
segments.push({ type: buffer.readUInt8(buffer.position) })
200218

@@ -207,6 +225,8 @@ const parseSegments = (buffer, count) => {
207225
const parseGeography = (buffer, isUsingGeometryPoints) => {
208226
// s2.1.1 + s.2.1.2
209227

228+
ensureBytes(buffer, 6)
229+
210230
const srid = buffer.readInt32LE(0)
211231
if (srid === -1) {
212232
return null
@@ -220,9 +240,6 @@ const parseGeography = (buffer, isUsingGeometryPoints) => {
220240
const flags = buffer.readUInt8(5)
221241
buffer.position = 6
222242

223-
// console.log("srid", srid)
224-
// console.log("version", version)
225-
226243
const properties = {
227244
Z: (flags & (1 << 0)) > 0,
228245
M: (flags & (1 << 1)) > 0,
@@ -232,23 +249,20 @@ const parseGeography = (buffer, isUsingGeometryPoints) => {
232249
}
233250

234251
if (value.version === 2) {
235-
properties.H = (flags & (1 << 3)) > 0
252+
properties.H = (flags & (1 << 5)) > 0
236253
}
237254

238-
// console.log("properties", properties);
239-
240255
let numberOfPoints
241256
if (properties.P) {
242257
numberOfPoints = 1
243258
} else if (properties.L) {
244259
numberOfPoints = 2
245260
} else {
261+
ensureBytes(buffer, 4)
246262
numberOfPoints = buffer.readUInt32LE(buffer.position)
247263
buffer.position += 4
248264
}
249265

250-
// console.log("numberOfPoints", numberOfPoints)
251-
252266
value.points = parsePoints(buffer, numberOfPoints, isUsingGeometryPoints)
253267

254268
if (properties.Z) {
@@ -259,49 +273,37 @@ const parseGeography = (buffer, isUsingGeometryPoints) => {
259273
parseM(buffer, value.points)
260274
}
261275

262-
// console.log("points", points)
263-
264276
let numberOfFigures
265277
if (properties.P) {
266278
numberOfFigures = 1
267279
} else if (properties.L) {
268280
numberOfFigures = 1
269281
} else {
282+
ensureBytes(buffer, 4)
270283
numberOfFigures = buffer.readUInt32LE(buffer.position)
271284
buffer.position += 4
272285
}
273286

274-
// console.log("numberOfFigures", numberOfFigures)
275-
276287
value.figures = parseFigures(buffer, numberOfFigures, properties)
277288

278-
// console.log("figures", figures)
279-
280289
let numberOfShapes
281290
if (properties.P) {
282291
numberOfShapes = 1
283292
} else if (properties.L) {
284293
numberOfShapes = 1
285294
} else {
295+
ensureBytes(buffer, 4)
286296
numberOfShapes = buffer.readUInt32LE(buffer.position)
287297
buffer.position += 4
288298
}
289299

290-
// console.log("numberOfShapes", numberOfShapes)
291-
292300
value.shapes = parseShapes(buffer, numberOfShapes, properties)
293301

294-
// console.log( "shapes", shapes)
295-
296-
if (value.version === 2 && buffer.position < buffer.length) {
302+
if (value.version === 2 && buffer.position + 4 <= buffer.length) {
297303
const numberOfSegments = buffer.readUInt32LE(buffer.position)
298304
buffer.position += 4
299305

300-
// console.log("numberOfSegments", numberOfSegments)
301-
302306
value.segments = parseSegments(buffer, numberOfSegments)
303-
304-
// console.log("segments", segments)
305307
} else {
306308
value.segments = []
307309
}

0 commit comments

Comments
 (0)