Skip to content

Commit 06c3fa8

Browse files
authored
CABI: trap on misaligned error-context.debug-message ptr (#740)
canon_error_context_debug_message stored the debug string's (pointer, length) pair at the guest-supplied `ptr` with store_string, which writes through store_int without any alignment or bounds check. A misaligned `ptr` was thus accepted, and an out-of-bounds `ptr` silently grew the Python bytearray backing linear memory (appending at its current end) instead of trapping. Check `ptr` the same way lower_flat_values checks an out-param pointer before storing a spilled tuple: trap unless `ptr` is aligned to alignment(string) and `ptr + elem_size(string)` is within memory, then go through store, whose assertions these checks discharge. The checks run before opts.realloc is called. Assisted-by: claude:claude-opus-5-5
1 parent 6cd6393 commit 06c3fa8

3 files changed

Lines changed: 12 additions & 4 deletions

File tree

‎design/mvp/CanonicalABI.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4832,12 +4832,17 @@ def canon_error_context_debug_message(opts, i, ptr):
48324832
errctx = inst.handles.get(i)
48334833
trap_if(not isinstance(errctx, ErrorContext))
48344834
cx = LiftLowerContext(opts, inst)
4835-
store_string(cx, errctx.debug_message, ptr)
4835+
trap_if(ptr != align_to(ptr, alignment(StringType(), cx.opts.memory.ptr_type())))
4836+
trap_if(ptr + elem_size(StringType(), cx.opts.memory.ptr_type()) > len(cx.opts.memory))
4837+
store(cx, errctx.debug_message, StringType(), ptr)
48364838
return []
48374839
```
48384840
Note that `ptr` points to a region of memory (8 bytes for memory32, 16 bytes
48394841
for memory64) into which will be stored the pointer and length of the debug
4840-
string (allocated via `opts.realloc`).
4842+
string (allocated via `opts.realloc`). As with any `string` stored in linear
4843+
memory, `ptr` must be aligned to the pointer size (4 bytes for memory32, 8 bytes
4844+
for memory64) and the whole region must be in bounds, which is checked
4845+
(trapping otherwise) before `opts.realloc` is called.
48414846

48424847

48434848
### 📝 `canon error-context.drop`

‎design/mvp/Explainer.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2399,7 +2399,8 @@ The `error-context.debug-message` built-in returns the
23992399

24002400
In the Canonical ABI, it writes the debug message into `ptr` as an 8-byte or
24012401
16-byte (`ptr`, `length`) pair, according to the Canonical ABI for `string`,
2402-
given the `<canonopt>*` immediates.
2402+
given the `<canonopt>*` immediates, trapping if `ptr` is misaligned or out of
2403+
bounds.
24032404

24042405
For details, see [`canon_error_context_debug_message`] in the Canonical ABI
24052406
explainer.

‎design/mvp/canonical-abi/definitions.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2664,7 +2664,9 @@ def canon_error_context_debug_message(opts, i, ptr):
26642664
errctx = inst.handles.get(i)
26652665
trap_if(not isinstance(errctx, ErrorContext))
26662666
cx = LiftLowerContext(opts, inst)
2667-
store_string(cx, errctx.debug_message, ptr)
2667+
trap_if(ptr != align_to(ptr, alignment(StringType(), cx.opts.memory.ptr_type())))
2668+
trap_if(ptr + elem_size(StringType(), cx.opts.memory.ptr_type()) > len(cx.opts.memory))
2669+
store(cx, errctx.debug_message, StringType(), ptr)
26682670
return []
26692671

26702672
### 📝 `canon error-context.drop`

0 commit comments

Comments
 (0)