asm: scheme_read string buffer overflow (#GP fault on > 272 chars)
Reader's .sr_string used a fixed 256-byte stack buffer with no
bounds check. Strings longer than ~272 bytes (256 + saved
registers) corrupted the saved return address and produced a
general protection fault on ret.
Reproducer:
(display (string-length "AAAA...")) ; > 272 A's → #GP at .sr_string ret
Fix:
- bump stack buffer 256 → 4096 (one page)
- add bounds check (cmpq $4080) before every char write
- on overflow exit cleanly via new die_str_overflow rather than
smashing %rip
Discovered while diagnosing ecdsa task #34: lumbda asm tier
crashed when loading ecdsa/lumbda/mod-arith.lsp because one
mod-mul! docstring is 955 bytes. Post-fix, mod-arith.lsp loads
clean and ecdsa test-mod-arith.lsp passes 33/33 on asm-full;
upstream asm test.sh stays 158/158.
This commit is contained in:
parent
6262a24d47
commit
6b03516ecb
1 changed files with 23 additions and 2 deletions
25
asm/lumbda.s
25
asm/lumbda.s
|
|
@ -517,6 +517,8 @@ err_rng_short: .ascii "Error: random-state!: expected list of 8 integers\n"
|
|||
.equ err_rng_short_len, . - err_rng_short
|
||||
err_rng_urandom: .ascii "Error: random-seed-from-os!: /dev/urandom unavailable\n"
|
||||
.equ err_rng_urandom_len, . - err_rng_urandom
|
||||
err_str_overflow: .ascii "Error: scheme_read: string literal exceeds 4080-byte buffer\n"
|
||||
.equ err_str_overflow_len, . - err_str_overflow
|
||||
s_dev_urandom: .asciz "/dev/urandom"
|
||||
|
||||
# Print strings
|
||||
|
|
@ -1619,6 +1621,16 @@ die_oom:
|
|||
movq $1, %rdi
|
||||
syscall
|
||||
|
||||
die_str_overflow:
|
||||
movq $SYS_WRITE, %rax
|
||||
movq $2, %rdi
|
||||
leaq err_str_overflow(%rip), %rsi
|
||||
movq $err_str_overflow_len, %rdx
|
||||
syscall
|
||||
movq $SYS_EXIT, %rax
|
||||
movq $1, %rdi
|
||||
syscall
|
||||
|
||||
# ============================================================
|
||||
# Value constructors
|
||||
# ============================================================
|
||||
|
|
@ -2284,10 +2296,19 @@ list_to_vector_reader:
|
|||
ret
|
||||
|
||||
.sr_string:
|
||||
# Reads a "..." string literal into a 4080-byte stack buffer, then
|
||||
# heap-allocates the final string. Buffer bumped from 256B (which
|
||||
# smashed the saved return address on strings > 272 chars and
|
||||
# produced a #GP fault — see ecdsa lumbda task #34, 2026-06-04).
|
||||
# 4080 chosen to keep the frame size under 4096 (one page) while
|
||||
# bounding via cmpq below. If a string literal exceeds the cap,
|
||||
# exit cleanly via die_str_overflow rather than corrupting %rip.
|
||||
call read_char # eat opening "
|
||||
subq $256, %rsp
|
||||
subq $4096, %rsp
|
||||
xorq %rbx, %rbx # length
|
||||
.sr_str_loop:
|
||||
cmpq $4080, %rbx
|
||||
jge die_str_overflow
|
||||
call read_char
|
||||
cmpq $-1, %rax
|
||||
je .sr_str_end
|
||||
|
|
@ -2342,7 +2363,7 @@ list_to_vector_reader:
|
|||
incq %rcx
|
||||
jmp .sr_str_copy
|
||||
.sr_str_done:
|
||||
addq $256, %rsp
|
||||
addq $4096, %rsp
|
||||
orq $TAG_STRING, %rax
|
||||
popq %r12
|
||||
popq %rbx
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue