| Descripción | ### Description
We discovered a Heap-buffer-overflow vulnerability in the Squirrel VM. The crash occurs when the VM enters an infinite recursion loop involving metamethod calls (_set/_get), leading to stack exhaustion or corruption.
The ASAN report shows a very deep call stack of Execute -> Call -> FallBackSet, eventually causing a memory access violation 8 bytes past the end of a 16KB allocated region (likely the VM's internal stack sqvector).
### Environment
- OS: Linux x86_64
- Complier: Clang
- Build Configuration: Release mode with ASan enabled.
### Vulnerability Details
- Target: Squirrel (squirrel-lang)
- Vulnerability Type: CWE-674: Uncontrolled Recursion / CWE-122: Heap-based Buffer Overflow
- Function: SQObjectPtr::operator=
- Location: squirrel/sqobject.h:269
- Root Cause Analysis: The crash is triggered by infinite recursion in the script execution.
1. The stack trace shows repeated calls to FallBackSet -> Set -> Execute, implying a property assignment that triggers a _set metamethod, which in turn triggers another assignment recursively.
2. The memory allocation trace shows sqvector<SQObjectPtr>::_realloc, suggesting this heap buffer is the VM's execution stack.
3. As the recursion deepens, the stack grows. The crash occurs at 0x529000004208, which is 8 bytes past the allocated chunk [...00004200).
4. This suggests that either the VM failed to check the stack limit properly, or a pointer to a stack element became invalid/out-of-bounds during the realloc process or subsequent access.
### Reproduce
1. Build squirrel with Release optimization and ASAN enabled.
2. Run with the crashing [file](https://github.com/oneafter/0122/blob/main/i310/repro):
```
./build/bin/sq repro
```
<details>
<summary>ASAN report</summary>
```
==45933==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x529000004208 at pc 0x7ff6dd660676 bp 0x7ffcbda3d170 sp 0x7ffcbda3d168
READ of size 8 at 0x529000004208 thread T0
#0 0x7ff6dd660675 in SQObjectPtr::operator=(SQObjectPtr const&) /src/squirrel/squirrel/sqobject.h:269:16
#1 0x7ff6dd660675 in SQVM::Return(long long, long long, SQObjectPtr&) /src/squirrel/squirrel/sqvm.cpp:475:19
#2 0x7ff6dd660675 in SQVM::StartCall(SQClosure*, long long, long long, long long, bool) /src/squirrel/squirrel/sqvm.cpp:446:9
#3 0x7ff6dd670cc0 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:709:17
#4 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#5 0x7ff6dd69366e in SQVM::FallBackGet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr&) /src/squirrel/squirrel/sqvm.cpp:1361:16
#6 0x7ff6dd666974 in SQVM::Get(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr&, unsigned long long, long long) /src/squirrel/squirrel/sqvm.cpp:1299:16
#7 0x7ff6dd6730ec in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:853:22
#8 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#9 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#10 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#11 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#12 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#13 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#14 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#15 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#16 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#17 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#18 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#19 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#20 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#21 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#22 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#23 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#24 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#25 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#26 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#27 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#28 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#29 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#30 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#31 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#32 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#33 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#34 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#35 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#36 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#37 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#38 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#39 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#40 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#41 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#42 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#43 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#44 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#45 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#46 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#47 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#48 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
#49 0x7ff6dd695526 in SQVM::FallBackSet(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&) /src/squirrel/squirrel/sqvm.cpp:1431:16
#50 0x7ff6dd667c84 in SQVM::Set(SQObjectPtr const&, SQObjectPtr const&, SQObjectPtr const&, long long) /src/squirrel/squirrel/sqvm.cpp:1402:12
#51 0x7ff6dd674149 in SQVM::Execute(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long, SQVM::ExecutionType) /src/squirrel/squirrel/sqvm.cpp:863:22
#52 0x7ff6dd66e96f in SQVM::Call(SQObjectPtr&, long long, long long, SQObjectPtr&, unsigned long long) /src/squirrel/squirrel/sqvm.cpp:1610:16
|
|---|