| Título | janet-lang janet 883dde4 Heap-based Buffer Overflow |
|---|
| Descrição | ### Description
We discovered a Heap-buffer-overflow vulnerability in Janet. The crash occurs in janetc_pop_funcdef during the compilation linting phase (janet_compile_lint).
The ASAN report indicates a READ violation of size 4, occurring 24 bytes past the end of a tiny 4-byte region allocated just a few lines earlier in the same function.
Vendor confirmed and fixed this vulnerability in commit (4dd08a4
)[https://github.com/janet-lang/janet/commit/4dd08a4cdef5b1c42d9a2c19fc24412e97ef51d5].
### Environment
- OS: Linux x86_64
- Complier: Clang
- Build Configuration: Release mode with ASan enabled.
### Vulnerability Details
- Target: Janet (janet-lang)
- Vulnerability Type: CWE-125: Out-of-bounds Read
- Function: janetc_pop_funcdef
- Location: src/core/compile.c:965
- Allocation Site: src/core/compile.c:959
- Root Cause Analysis: The buffer causing the overflow is allocated at line 959 via calloc with a size of only 4 bytes (likely sizeof(int32_t) or similar). However, at line 965, the code attempts to read from an address 24 bytes past this region. This suggests a significant mismatch between the calculated allocation size and the index used for access.
This usually happens when:
1. The compiler calculates a map/array size as 0 or 1 based on an empty or singular input structure.
2. But the subsequent logic iterates based on a different assumption or corrupted state counter, accessing indices like 6 or 7 (28 bytes offset).
### Reproduce
1. Build janet and harness with Release optimization and ASAN enabled.
<details>
<summary>harness.c</summary>
```
#include "janet.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc < 2) {
return 1;
}
janet_init();
JanetTable *env = janet_core_env(NULL);
FILE *f = fopen(argv[1], "rb");
if (!f) {
janet_deinit();
return 1;
}
fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char *buf = (unsigned char *)malloc(len + 1);
if (!buf) {
fclose(f);
janet_deinit();
return 1;
}
if (fread(buf, 1, len, f) != len) {
free(buf);
fclose(f);
janet_deinit();
return 1;
}
fclose(f);
buf[len] = '\0';
if (len >= 1) {
Janet retval;
janet_dostring(env, (const char *)buf, NULL, &retval);
janet_gcroot(janet_wrap_nil());
}
free(buf);
janet_deinit();
return 0;
}
```
</details>
2. Run with the crashing [file](https://github.com/oneafter/0123/blob/main/ja4/repro):
```
./harness repro
```
<details>
<summary>ASAN report</summary>
```
==6433==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50200000794c at pc 0x55b67b6e4bba bp 0x7ffe7d00ec40 sp 0x7ffe7d00ec38
READ of size 4 at 0x50200000794c thread T0
#0 0x55b67b6e4bb9 in janetc_pop_funcdef /src/janet/src/core/compile.c:965:44
#1 0x55b67b6e53ac in janet_compile_lint /src/janet/src/core/compile.c:1084:29
#2 0x55b67b7e63dd in janet_compile /src/janet/src/core/compile.c:1099:12
#3 0x55b67b7e63dd in janet_dobytes /src/janet/src/core/run.c:51:39
#4 0x55b67b6870f3 in main /src/janet/harness.c:44:9
#5 0x7f640cb9f1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#6 0x7f640cb9f28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#7 0x55b67b5a5a94 in _start (/src/janet/harness_janet+0x54a94) (BuildId: 99073a3a75c69a7f87afa4e4c777fe183943214e)
0x50200000794c is located 24 bytes after 4-byte region [0x502000007930,0x502000007934)
allocated by thread T0 here:
#0 0x55b67b645aad in calloc (/src/janet/harness_janet+0xf4aad) (BuildId: 99073a3a75c69a7f87afa4e4c777fe183943214e)
#1 0x55b67b6e3192 in janetc_pop_funcdef /src/janet/src/core/compile.c:959:28
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/janet/src/core/compile.c:965:44 in janetc_pop_funcdef
Shadow bytes around the buggy address:
0x502000007680: fa fa 00 00 fa fa fd fa fa fa fd fa fa fa 00 fa
0x502000007700: fa fa fd fa fa fa 04 fa fa fa 00 00 fa fa 00 fa
0x502000007780: fa fa 04 fa fa fa fd fa fa fa fd fa fa fa fd fa
0x502000007800: fa fa 00 00 fa fa fd fa fa fa 04 fa fa fa fd fa
0x502000007880: fa fa 04 fa fa fa fd fa fa fa fd fa fa fa 00 fa
=>0x502000007900: fa fa 01 fa fa fa 04 fa fa[fa]fa fa fa fa fa fa
0x502000007980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000007a00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000007a80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000007b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x502000007b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==6433==ABORTING
```
</details> |
|---|
| Fonte | ⚠️ https://github.com/janet-lang/janet/issues/1702 |
|---|
| Utilizador | Oneafter (UID 92781) |
|---|
| Submissão | 06/02/2026 03h55 (há 3 meses) |
|---|
| Moderação | 09/02/2026 10h38 (3 days later) |
|---|
| Estado | Aceite |
|---|
| Entrada VulDB | 344979 [janet-lang janet até 1.40.1 src/core/compile.c janetc_pop_funcdef Divulgação de Informação] |
|---|
| Pontos | 20 |
|---|