| Titel | janet-lang janet c43e066 Heap-based Buffer Overflow |
|---|
| Beschreibung | ### Description
We discovered a Heap-buffer-overflow vulnerability in Janet. The crash occurs in the os_strftime function during runtime execution.
The ASAN report indicates a READ violation of size 1, occurring exactly at the boundary (0 bytes after) of a 41-byte allocated region (likely a string buffer).
Vendor confirmed and fixed this vulnerability in commit (0f28585
)[https://github.com/janet-lang/janet/commit/0f285855f0e34f9183956be5f16e045f54626bff].
### 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: os_strftime
- Location: src/core/os.c:1938
- Root Cause Analysis: The function os_strftime processes a format string to generate a date/time string. The ASAN report shows:
```
0x5040000210f9 is located 0 bytes after 41-byte region
READ of size 1
```
This suggests that os_strftime is iterating over the format string (or an internal buffer) and fails to stop at the null terminator, or calculates an index that is off-by-one, attempting to read the byte immediately following the allocated string. This often happens if the format string contains specific sequences that confuse the length calculation or pointer increment logic.
### 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/ja3/repro):
```
./harness repro
```
<details>
<summary>ASAN report</summary>
```
==92243==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5040000210f9 at pc 0x55cce0daf457 bp 0x7ffcf73785b0 sp 0x7ffcf73785a8
READ of size 1 at 0x5040000210f9 thread T0
#0 0x55cce0daf456 in os_strftime /src/janet/src/core/os.c:1938:12
#1 0x55cce0e1a24b in run_vm /src/janet/src/core/vm.c:1038:25
#2 0x55cce0e26ec7 in janet_continue_no_check /src/janet/src/core/vm.c:1529:15
#3 0x55cce0ddba9a in janet_continue /src/janet/src/core/vm.c:1547:12
#4 0x55cce0ddba9a in janet_dobytes /src/janet/src/core/run.c:56:38
#5 0x55cce0c7c0f3 in main /src/janet/harness.c:44:9
#6 0x7f986fef01c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#7 0x7f986fef028a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#8 0x55cce0b9aa94 in _start (/src/janet/harness_janet+0x54a94) (BuildId: 99073a3a75c69a7f87afa4e4c777fe183943214e)
0x5040000210f9 is located 0 bytes after 41-byte region [0x5040000210d0,0x5040000210f9)
allocated by thread T0 here:
#0 0x55cce0c3a8c3 in malloc (/src/janet/harness_janet+0xf48c3) (BuildId: 99073a3a75c69a7f87afa4e4c777fe183943214e)
#1 0x55cce0c7ccd2 in janet_gcalloc /src/janet/src/core/gc.c:536:11
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/janet/src/core/os.c:1938:12 in os_strftime
Shadow bytes around the buggy address:
0x504000020e00: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x504000020e80: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x504000020f00: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x504000020f80: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x504000021000: fa fa 00 00 00 00 03 fa fa fa 00 00 00 00 00 00
=>0x504000021080: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00[01]
0x504000021100: fa fa 00 00 00 00 04 fa fa fa 00 00 00 00 00 00
0x504000021180: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 fa
0x504000021200: fa fa 00 00 00 00 00 00 fa fa 00 00 00 00 00 00
0x504000021280: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
0x504000021300: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
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
==92243==ABORTING
```
</details> |
|---|
| Quelle | ⚠️ https://github.com/janet-lang/janet/issues/1701 |
|---|
| Benutzer | Oneafter (UID 92781) |
|---|
| Einreichung | 06.02.2026 04:07 (vor 3 Monaten) |
|---|
| Moderieren | 09.02.2026 10:38 (3 days later) |
|---|
| Status | Akzeptiert |
|---|
| VulDB Eintrag | 344980 [janet-lang janet bis 1.40.1 src/core/os.c os_strftime Information Disclosure] |
|---|
| Punkte | 20 |
|---|