Skip to content

Commit 35d4184

Browse files
committed
[GR-33183] Improve wasm memory bounds check.
PullRequest: graal/9564
2 parents 4c707c1 + 702580b commit 35d4184

File tree

7 files changed

+171
-137
lines changed

7 files changed

+171
-137
lines changed

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,8 +1333,8 @@ private void readDataSection(WasmContext linkedContext, WasmInstance linkedInsta
13331333
// directly.
13341334
final WasmMemory memory = linkedInstance.memory();
13351335

1336-
Assert.assertUnsignedIntLessOrEqual(offsetAddress, memory.byteSize(), Failure.DATA_SEGMENT_DOES_NOT_FIT);
1337-
Assert.assertUnsignedIntLessOrEqual(offsetAddress + byteLength, memory.byteSize(), Failure.DATA_SEGMENT_DOES_NOT_FIT);
1336+
Assert.assertUnsignedIntLessOrEqual(offsetAddress, WasmMath.toUnsignedIntExact(memory.byteSize()), Failure.DATA_SEGMENT_DOES_NOT_FIT);
1337+
Assert.assertUnsignedIntLessOrEqual(offsetAddress + byteLength, WasmMath.toUnsignedIntExact(memory.byteSize()), Failure.DATA_SEGMENT_DOES_NOT_FIT);
13381338

13391339
for (int writeOffset = 0; writeOffset != byteLength; ++writeOffset) {
13401340
final byte b = read1();

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ void resolveDataSegment(WasmContext context, WasmInstance instance, int dataSegm
364364
baseAddress = offsetAddress;
365365
}
366366

367-
Assert.assertUnsignedIntLessOrEqual(baseAddress, memory.byteSize(), Failure.DATA_SEGMENT_DOES_NOT_FIT);
368-
Assert.assertUnsignedIntLessOrEqual(baseAddress + byteLength, memory.byteSize(), Failure.DATA_SEGMENT_DOES_NOT_FIT);
367+
Assert.assertUnsignedIntLessOrEqual(baseAddress, WasmMath.toUnsignedIntExact(memory.byteSize()), Failure.DATA_SEGMENT_DOES_NOT_FIT);
368+
Assert.assertUnsignedIntLessOrEqual(baseAddress + byteLength, WasmMath.toUnsignedIntExact(memory.byteSize()), Failure.DATA_SEGMENT_DOES_NOT_FIT);
369369

370370
for (int writeOffset = 0; writeOffset != byteLength; ++writeOffset) {
371371
byte b = data[writeOffset];

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmMath.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ public static int maxUnsigned(int a, int b) {
108108
return compareUnsigned(a, b) > 0 ? a : b;
109109
}
110110

111+
/**
112+
* Returns the value of the {@code long} argument as an {@code int}; throwing an exception if
113+
* the value overflows an unsigned {@code int}.
114+
*
115+
* @throws ArithmeticException if the argument is outside of the unsigned int32 range
116+
* @since 1.8
117+
*/
118+
public static int toUnsignedIntExact(long value) {
119+
if (value < 0 || value > 0xffff_ffffL) {
120+
throw new ArithmeticException("unsigned int overflow");
121+
}
122+
return (int) value;
123+
}
124+
111125
/**
112126
* Converts the given unsigned {@code int} to the closest {@code float} value.
113127
*/

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java

Lines changed: 77 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,13 @@ public ByteArrayWasmMemory(int declaredMinSize, int declaredMaxSize, int maxAllo
103103
this(declaredMinSize, declaredMaxSize, declaredMinSize, maxAllowedSize);
104104
}
105105

106-
@TruffleBoundary
107-
private WasmException trapOutOfBounds(Node node, int address, long size) {
108-
final String message = String.format("%d-byte memory access at address 0x%016X (%d) is out-of-bounds (memory size %d bytes).",
109-
size, address, address, byteSize());
110-
return WasmException.create(Failure.OUT_OF_BOUNDS_MEMORY_ACCESS, node, message);
106+
private int validateAddress(Node node, long address, int length) {
107+
assert length >= 1;
108+
if (address < 0 || address > Integer.MAX_VALUE) {
109+
CompilerDirectives.transferToInterpreterAndInvalidate();
110+
throw trapOutOfBounds(node, address, length);
111+
}
112+
return (int) address;
111113
}
112114

113115
@Override
@@ -126,7 +128,7 @@ public int size() {
126128
}
127129

128130
@Override
129-
public int byteSize() {
131+
public long byteSize() {
130132
return buffer.length;
131133
}
132134

@@ -168,208 +170,231 @@ public void reset() {
168170
}
169171

170172
@Override
171-
public int load_i32(Node node, int address) {
173+
public int load_i32(Node node, long address) {
174+
int intAddress = validateAddress(node, address, 4);
172175
try {
173-
return ByteArraySupport.littleEndian().getInt(buffer, address);
176+
return ByteArraySupport.littleEndian().getInt(buffer, intAddress);
174177
} catch (final IndexOutOfBoundsException e) {
175178
throw trapOutOfBounds(node, address, 4);
176179
}
177180
}
178181

179182
@Override
180-
public long load_i64(Node node, int address) {
183+
public long load_i64(Node node, long address) {
184+
int intAddress = validateAddress(node, address, 8);
181185
try {
182-
return ByteArraySupport.littleEndian().getLong(buffer, address);
186+
return ByteArraySupport.littleEndian().getLong(buffer, intAddress);
183187
} catch (final IndexOutOfBoundsException e) {
184188
throw trapOutOfBounds(node, address, 8);
185189
}
186190
}
187191

188192
@Override
189-
public float load_f32(Node node, int address) {
193+
public float load_f32(Node node, long address) {
194+
int intAddress = validateAddress(node, address, 4);
190195
try {
191-
return ByteArraySupport.littleEndian().getFloat(buffer, address);
196+
return ByteArraySupport.littleEndian().getFloat(buffer, intAddress);
192197
} catch (final IndexOutOfBoundsException e) {
193198
throw trapOutOfBounds(node, address, 4);
194199
}
195200
}
196201

197202
@Override
198-
public double load_f64(Node node, int address) {
203+
public double load_f64(Node node, long address) {
204+
int intAddress = validateAddress(node, address, 8);
199205
try {
200-
return ByteArraySupport.littleEndian().getDouble(buffer, address);
206+
return ByteArraySupport.littleEndian().getDouble(buffer, intAddress);
201207
} catch (final IndexOutOfBoundsException e) {
202208
throw trapOutOfBounds(node, address, 8);
203209
}
204210
}
205211

206212
@Override
207-
public int load_i32_8s(Node node, int address) {
213+
public int load_i32_8s(Node node, long address) {
214+
int intAddress = validateAddress(node, address, 1);
208215
try {
209-
return ByteArraySupport.littleEndian().getByte(buffer, address);
216+
return ByteArraySupport.littleEndian().getByte(buffer, intAddress);
210217
} catch (final IndexOutOfBoundsException e) {
211218
throw trapOutOfBounds(node, address, 1);
212219
}
213220
}
214221

215222
@Override
216-
public int load_i32_8u(Node node, int address) {
223+
public int load_i32_8u(Node node, long address) {
224+
int intAddress = validateAddress(node, address, 1);
217225
try {
218-
return 0x0000_00ff & ByteArraySupport.littleEndian().getByte(buffer, address);
226+
return 0x0000_00ff & ByteArraySupport.littleEndian().getByte(buffer, intAddress);
219227
} catch (final IndexOutOfBoundsException e) {
220228
throw trapOutOfBounds(node, address, 1);
221229
}
222230
}
223231

224232
@Override
225-
public int load_i32_16s(Node node, int address) {
233+
public int load_i32_16s(Node node, long address) {
234+
int intAddress = validateAddress(node, address, 2);
226235
try {
227-
return ByteArraySupport.littleEndian().getShort(buffer, address);
236+
return ByteArraySupport.littleEndian().getShort(buffer, intAddress);
228237
} catch (final IndexOutOfBoundsException e) {
229238
throw trapOutOfBounds(node, address, 2);
230239
}
231240
}
232241

233242
@Override
234-
public int load_i32_16u(Node node, int address) {
243+
public int load_i32_16u(Node node, long address) {
244+
int intAddress = validateAddress(node, address, 2);
235245
try {
236-
return 0x0000_ffff & ByteArraySupport.littleEndian().getShort(buffer, address);
246+
return 0x0000_ffff & ByteArraySupport.littleEndian().getShort(buffer, intAddress);
237247
} catch (final IndexOutOfBoundsException e) {
238248
throw trapOutOfBounds(node, address, 2);
239249
}
240250
}
241251

242252
@Override
243-
public long load_i64_8s(Node node, int address) {
253+
public long load_i64_8s(Node node, long address) {
254+
int intAddress = validateAddress(node, address, 1);
244255
try {
245-
return ByteArraySupport.littleEndian().getByte(buffer, address);
256+
return ByteArraySupport.littleEndian().getByte(buffer, intAddress);
246257
} catch (final IndexOutOfBoundsException e) {
247258
throw trapOutOfBounds(node, address, 1);
248259
}
249260
}
250261

251262
@Override
252-
public long load_i64_8u(Node node, int address) {
263+
public long load_i64_8u(Node node, long address) {
264+
int intAddress = validateAddress(node, address, 1);
253265
try {
254-
return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByte(buffer, address);
266+
return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByte(buffer, intAddress);
255267
} catch (final IndexOutOfBoundsException e) {
256268
throw trapOutOfBounds(node, address, 1);
257269
}
258270
}
259271

260272
@Override
261-
public long load_i64_16s(Node node, int address) {
273+
public long load_i64_16s(Node node, long address) {
274+
int intAddress = validateAddress(node, address, 2);
262275
try {
263-
return ByteArraySupport.littleEndian().getShort(buffer, address);
276+
return ByteArraySupport.littleEndian().getShort(buffer, intAddress);
264277
} catch (final IndexOutOfBoundsException e) {
265278
throw trapOutOfBounds(node, address, 2);
266279
}
267280
}
268281

269282
@Override
270-
public long load_i64_16u(Node node, int address) {
283+
public long load_i64_16u(Node node, long address) {
284+
int intAddress = validateAddress(node, address, 2);
271285
try {
272-
return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShort(buffer, address);
286+
return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShort(buffer, intAddress);
273287
} catch (final IndexOutOfBoundsException e) {
274288
throw trapOutOfBounds(node, address, 2);
275289
}
276290
}
277291

278292
@Override
279-
public long load_i64_32s(Node node, int address) {
293+
public long load_i64_32s(Node node, long address) {
294+
int intAddress = validateAddress(node, address, 4);
280295
try {
281-
return ByteArraySupport.littleEndian().getInt(buffer, address);
296+
return ByteArraySupport.littleEndian().getInt(buffer, intAddress);
282297
} catch (final IndexOutOfBoundsException e) {
283298
throw trapOutOfBounds(node, address, 4);
284299
}
285300
}
286301

287302
@Override
288-
public long load_i64_32u(Node node, int address) {
303+
public long load_i64_32u(Node node, long address) {
304+
int intAddress = validateAddress(node, address, 4);
289305
try {
290-
return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getInt(buffer, address);
306+
return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getInt(buffer, intAddress);
291307
} catch (final IndexOutOfBoundsException e) {
292308
throw trapOutOfBounds(node, address, 4);
293309
}
294310
}
295311

296312
@Override
297-
public void store_i32(Node node, int address, int value) {
313+
public void store_i32(Node node, long address, int value) {
314+
int intAddress = validateAddress(node, address, 4);
298315
try {
299-
ByteArraySupport.littleEndian().putInt(buffer, address, value);
316+
ByteArraySupport.littleEndian().putInt(buffer, intAddress, value);
300317
} catch (final IndexOutOfBoundsException e) {
301318
throw trapOutOfBounds(node, address, 4);
302319
}
303320
}
304321

305322
@Override
306-
public void store_i64(Node node, int address, long value) {
323+
public void store_i64(Node node, long address, long value) {
324+
int intAddress = validateAddress(node, address, 8);
307325
try {
308-
ByteArraySupport.littleEndian().putLong(buffer, address, value);
326+
ByteArraySupport.littleEndian().putLong(buffer, intAddress, value);
309327
} catch (final IndexOutOfBoundsException e) {
310328
throw trapOutOfBounds(node, address, 8);
311329
}
312330

313331
}
314332

315333
@Override
316-
public void store_f32(Node node, int address, float value) {
334+
public void store_f32(Node node, long address, float value) {
335+
int intAddress = validateAddress(node, address, 4);
317336
try {
318-
ByteArraySupport.littleEndian().putFloat(buffer, address, value);
337+
ByteArraySupport.littleEndian().putFloat(buffer, intAddress, value);
319338
} catch (final IndexOutOfBoundsException e) {
320339
throw trapOutOfBounds(node, address, 4);
321340
}
322341
}
323342

324343
@Override
325-
public void store_f64(Node node, int address, double value) {
344+
public void store_f64(Node node, long address, double value) {
345+
int intAddress = validateAddress(node, address, 8);
326346
try {
327-
ByteArraySupport.littleEndian().putDouble(buffer, address, value);
347+
ByteArraySupport.littleEndian().putDouble(buffer, intAddress, value);
328348
} catch (final IndexOutOfBoundsException e) {
329349
throw trapOutOfBounds(node, address, 8);
330350
}
331351
}
332352

333353
@Override
334-
public void store_i32_8(Node node, int address, byte value) {
354+
public void store_i32_8(Node node, long address, byte value) {
355+
int intAddress = validateAddress(node, address, 1);
335356
try {
336-
ByteArraySupport.littleEndian().putByte(buffer, address, value);
357+
ByteArraySupport.littleEndian().putByte(buffer, intAddress, value);
337358
} catch (final IndexOutOfBoundsException e) {
338359
throw trapOutOfBounds(node, address, 1);
339360
}
340361
}
341362

342363
@Override
343-
public void store_i32_16(Node node, int address, short value) {
364+
public void store_i32_16(Node node, long address, short value) {
365+
int intAddress = validateAddress(node, address, 2);
344366
try {
345-
ByteArraySupport.littleEndian().putShort(buffer, address, value);
367+
ByteArraySupport.littleEndian().putShort(buffer, intAddress, value);
346368
} catch (final IndexOutOfBoundsException e) {
347369
throw trapOutOfBounds(node, address, 2);
348370
}
349371
}
350372

351373
@Override
352-
public void store_i64_8(Node node, int address, byte value) {
374+
public void store_i64_8(Node node, long address, byte value) {
375+
int intAddress = validateAddress(node, address, 1);
353376
try {
354-
ByteArraySupport.littleEndian().putByte(buffer, address, value);
377+
ByteArraySupport.littleEndian().putByte(buffer, intAddress, value);
355378
} catch (final IndexOutOfBoundsException e) {
356379
throw trapOutOfBounds(node, address, 1);
357380
}
358381
}
359382

360383
@Override
361-
public void store_i64_16(Node node, int address, short value) {
384+
public void store_i64_16(Node node, long address, short value) {
385+
int intAddress = validateAddress(node, address, 2);
362386
try {
363-
ByteArraySupport.littleEndian().putShort(buffer, address, value);
387+
ByteArraySupport.littleEndian().putShort(buffer, intAddress, value);
364388
} catch (final IndexOutOfBoundsException e) {
365389
throw trapOutOfBounds(node, address, 2);
366390
}
367391
}
368392

369393
@Override
370-
public void store_i64_32(Node node, int address, int value) {
394+
public void store_i64_32(Node node, long address, int value) {
395+
int intAddress = validateAddress(node, address, 4);
371396
try {
372-
ByteArraySupport.littleEndian().putInt(buffer, address, value);
397+
ByteArraySupport.littleEndian().putInt(buffer, intAddress, value);
373398
} catch (final IndexOutOfBoundsException e) {
374399
throw trapOutOfBounds(node, address, 4);
375400
}

0 commit comments

Comments
 (0)