490 lines
14 KiB
Markdown
490 lines
14 KiB
Markdown
|
|
# slab_index_for/SS範囲チェック実装調査 - 詳細分析報告書
|
||
|
|
|
||
|
|
## Executive Summary
|
||
|
|
|
||
|
|
**CRITICAL BUG FOUND**: Buffer overflow vulnerability in multiple code paths when `slab_index_for()` returns -1 (invalid range).
|
||
|
|
|
||
|
|
The `slab_index_for()` function correctly returns -1 when ptr is outside SuperSlab bounds, but **calling code does NOT check for -1 before using it as an array index**. This causes out-of-bounds memory access to SuperSlab's internal structure.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. slab_index_for() 実装確認
|
||
|
|
|
||
|
|
### Location: `core/hakmem_tiny_superslab.h` (Line 141-148)
|
||
|
|
|
||
|
|
```c
|
||
|
|
static inline int slab_index_for(const SuperSlab* ss, const void* p) {
|
||
|
|
uintptr_t base = (uintptr_t)ss;
|
||
|
|
uintptr_t addr = (uintptr_t)p;
|
||
|
|
uintptr_t off = addr - base;
|
||
|
|
int idx = (int)(off >> 16); // 64KB per slab (2^16)
|
||
|
|
int cap = ss_slabs_capacity(ss);
|
||
|
|
return (idx >= 0 && idx < cap) ? idx : -1;
|
||
|
|
// ^^^^^^^^^^ Returns -1 when:
|
||
|
|
// 1. ptr < ss (negative offset)
|
||
|
|
// 2. ptr >= ss + (cap * 64KB) (outside capacity)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Implementation Analysis
|
||
|
|
|
||
|
|
**正の部分:**
|
||
|
|
- Offset calculation: `(addr - base)` は正確
|
||
|
|
- Capacity check: `ss_slabs_capacity(ss)` で 1MB/2MB どちらにも対応
|
||
|
|
- Return value: -1 で明示的に「無効」を示す
|
||
|
|
|
||
|
|
**問題のある部分:**
|
||
|
|
- Call site で -1 をチェック**していない**箇所が複数存在
|
||
|
|
|
||
|
|
|
||
|
|
### ss_slabs_capacity() Implementation (Line 135-138)
|
||
|
|
|
||
|
|
```c
|
||
|
|
static inline int ss_slabs_capacity(const SuperSlab* ss) {
|
||
|
|
size_t ss_size = (size_t)1 << ss->lg_size; // 1MB (20) or 2MB (21)
|
||
|
|
return (int)(ss_size / SLAB_SIZE); // 16 or 32
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
This correctly computes 16 slabs for 1MB or 32 slabs for 2MB.
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. 問題1: tiny_free_fast_ss() での範囲チェック欠落
|
||
|
|
|
||
|
|
### Location: `core/tiny_free_fast.inc.h` (Line 91-92)
|
||
|
|
|
||
|
|
```c
|
||
|
|
static inline int tiny_free_fast_ss(SuperSlab* ss, int slab_idx, void* ptr, uint32_t my_tid) {
|
||
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx]; // <-- CRITICAL BUG
|
||
|
|
// If slab_idx == -1, this accesses ss->slabs[-1]!
|
||
|
|
```
|
||
|
|
|
||
|
|
### Vulnerability Details
|
||
|
|
|
||
|
|
**When slab_index_for() returns -1:**
|
||
|
|
- slab_idx = -1 (from tiny_free_fast.inc.h:205)
|
||
|
|
- `&ss->slabs[-1]` points to memory BEFORE the slabs array
|
||
|
|
|
||
|
|
**Memory layout of SuperSlab:**
|
||
|
|
```
|
||
|
|
ss+0000: SuperSlab header (64B)
|
||
|
|
- magic (8B)
|
||
|
|
- size_class (1B)
|
||
|
|
- active_slabs (1B)
|
||
|
|
- lg_size (1B)
|
||
|
|
- _pad0 (1B)
|
||
|
|
- slab_bitmap (4B)
|
||
|
|
- freelist_mask (4B)
|
||
|
|
- nonempty_mask (4B)
|
||
|
|
- total_active_blocks (4B)
|
||
|
|
- refcount (4B)
|
||
|
|
- listed (4B)
|
||
|
|
- partial_epoch (4B)
|
||
|
|
- publish_hint (1B)
|
||
|
|
- _pad1 (3B)
|
||
|
|
|
||
|
|
ss+0040: remote_heads[SLABS_PER_SUPERSLAB_MAX] (128B = 32*8B)
|
||
|
|
ss+00C0: remote_counts[SLABS_PER_SUPERSLAB_MAX] (128B = 32*4B)
|
||
|
|
ss+0140: slab_listed[SLABS_PER_SUPERSLAB_MAX] (128B = 32*4B)
|
||
|
|
ss+01C0: partial_next (8B)
|
||
|
|
|
||
|
|
ss+01C8: *** VULNERABILITY ZONE ***
|
||
|
|
&ss->slabs[-1] points here (16B before valid slabs[0])
|
||
|
|
This overlaps with partial_next and padding!
|
||
|
|
|
||
|
|
ss+01D0: ss->slabs[0] (first valid TinySlabMeta, 16B)
|
||
|
|
- freelist (8B)
|
||
|
|
- used (2B)
|
||
|
|
- capacity (2B)
|
||
|
|
- owner_tid (4B)
|
||
|
|
|
||
|
|
ss+01E0: ss->slabs[1] ...
|
||
|
|
```
|
||
|
|
|
||
|
|
### Impact
|
||
|
|
|
||
|
|
When `slab_idx = -1`:
|
||
|
|
1. `meta = &ss->slabs[-1]` reads/writes 16 bytes at offset 0x1C8
|
||
|
|
2. This corrupts `partial_next` pointer (bytes 8-15 of the buffer)
|
||
|
|
3. Subsequent access to `meta->owner_tid` reads garbage or partially-valid data
|
||
|
|
4. `tiny_free_is_same_thread_ss()` performs ownership check on corrupted data
|
||
|
|
|
||
|
|
### Root Cause Path
|
||
|
|
|
||
|
|
```
|
||
|
|
tiny_free_fast() [tiny_free_fast.inc.h:209]
|
||
|
|
↓
|
||
|
|
slab_index_for(ss, ptr) [returns -1 if ptr out of range]
|
||
|
|
↓
|
||
|
|
tiny_free_fast_ss(ss, slab_idx=-1, ...) [NO bounds check]
|
||
|
|
↓
|
||
|
|
&ss->slabs[-1] [OUT-OF-BOUNDS ACCESS]
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. 問題2: hak_tiny_free_with_slab() での範囲チェック
|
||
|
|
|
||
|
|
### Location: `core/hakmem_tiny_free.inc` (Line 96-101)
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss, ptr);
|
||
|
|
int ss_cap = ss_slabs_capacity(ss);
|
||
|
|
if (__builtin_expect(slab_idx < 0 || slab_idx >= ss_cap, 0)) {
|
||
|
|
tiny_debug_ring_record(TINY_RING_EVENT_SUPERSLAB_ADOPT_FAIL, ...);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Status: CORRECT**
|
||
|
|
- ✅ Bounds check present: `slab_idx < 0 || slab_idx >= ss_cap`
|
||
|
|
- ✅ Early return prevents OOB access
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. 問題3: hak_tiny_free_superslab() での範囲チェック
|
||
|
|
|
||
|
|
### Location: `core/hakmem_tiny_free.inc` (Line 1164-1172)
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss, ptr);
|
||
|
|
size_t ss_size = (size_t)1ULL << ss->lg_size;
|
||
|
|
uintptr_t ss_base = (uintptr_t)ss;
|
||
|
|
if (__builtin_expect(slab_idx < 0, 0)) {
|
||
|
|
uintptr_t aux = tiny_remote_pack_diag(0xBAD1u, ss_base, ss_size, (uintptr_t)ptr);
|
||
|
|
tiny_debug_ring_record(...);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Status: PARTIAL**
|
||
|
|
- ✅ Checks `slab_idx < 0`
|
||
|
|
- ⚠️ Missing check: `slab_idx >= ss_cap`
|
||
|
|
- If slab_idx >= capacity, next line accesses out-of-bounds:
|
||
|
|
```c
|
||
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx]; // Can OOB if idx >= 32
|
||
|
|
```
|
||
|
|
|
||
|
|
### Vulnerability Scenario
|
||
|
|
|
||
|
|
For 1MB SuperSlab (cap=16):
|
||
|
|
- If ptr is at offset 1088KB (0x110000), off >> 16 = 0x11 = 17
|
||
|
|
- slab_index_for() returns -1 (not >= cap=16)
|
||
|
|
- Line 1167 check passes: -1 < 0? YES → returns
|
||
|
|
- OK (caught by < 0 check)
|
||
|
|
|
||
|
|
For 2MB SuperSlab (cap=32):
|
||
|
|
- If ptr is at offset 2112KB (0x210000), off >> 16 = 0x21 = 33
|
||
|
|
- slab_index_for() returns -1 (not >= cap=32)
|
||
|
|
- Line 1167 check passes: -1 < 0? YES → returns
|
||
|
|
- OK (caught by < 0 check)
|
||
|
|
|
||
|
|
Actually, since slab_index_for() returns -1 when idx >= cap, the < 0 check is sufficient!
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. 問題4: Magazine spill 経路での範囲チェック
|
||
|
|
|
||
|
|
### Location: `core/hakmem_tiny_free.inc` (Line 305-316)
|
||
|
|
|
||
|
|
```c
|
||
|
|
SuperSlab* owner_ss = hak_super_lookup(it.ptr);
|
||
|
|
if (owner_ss && owner_ss->magic == SUPERSLAB_MAGIC) {
|
||
|
|
int slab_idx = slab_index_for(owner_ss, it.ptr);
|
||
|
|
TinySlabMeta* meta = &owner_ss->slabs[slab_idx]; // <-- NO CHECK!
|
||
|
|
*(void**)it.ptr = meta->freelist;
|
||
|
|
meta->freelist = it.ptr;
|
||
|
|
meta->used--;
|
||
|
|
```
|
||
|
|
|
||
|
|
**Status: CRITICAL BUG**
|
||
|
|
- ❌ No bounds check for slab_idx
|
||
|
|
- ❌ slab_idx = -1 → &owner_ss->slabs[-1] out-of-bounds access
|
||
|
|
|
||
|
|
|
||
|
|
### Similar Issue at Line 464
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss_owner, it.ptr);
|
||
|
|
TinySlabMeta* meta = &ss_owner->slabs[slab_idx]; // <-- NO CHECK!
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. 問題5: tiny_free_fast.inc.h:205 での範囲チェック
|
||
|
|
|
||
|
|
### Location: `core/tiny_free_fast.inc.h` (Line 205-209)
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss, ptr);
|
||
|
|
uint32_t self_tid = tiny_self_u32();
|
||
|
|
|
||
|
|
// Box 6 Boundary: Try same-thread fast path
|
||
|
|
if (tiny_free_fast_ss(ss, slab_idx, ptr, self_tid)) { // <-- PASSES slab_idx=-1
|
||
|
|
```
|
||
|
|
|
||
|
|
**Status: CRITICAL BUG**
|
||
|
|
- ❌ No bounds check before calling tiny_free_fast_ss()
|
||
|
|
- ❌ tiny_free_fast_ss() immediately accesses ss->slabs[slab_idx]
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. SS範囲チェック全体サマリー
|
||
|
|
|
||
|
|
| Code Path | File:Line | Check Status | Severity |
|
||
|
|
|-----------|-----------|--------------|----------|
|
||
|
|
| hak_tiny_free_with_slab() | hakmem_tiny_free.inc:96-101 | ✅ OK (both < and >=) | None |
|
||
|
|
| hak_tiny_free_superslab() | hakmem_tiny_free.inc:1164-1172 | ✅ OK (checks < 0, -1 means invalid) | None |
|
||
|
|
| magazine spill path 1 | hakmem_tiny_free.inc:305-316 | ❌ NO CHECK | CRITICAL |
|
||
|
|
| magazine spill path 2 | hakmem_tiny_free.inc:464-468 | ❌ NO CHECK | CRITICAL |
|
||
|
|
| tiny_free_fast_ss() | tiny_free_fast.inc.h:91-92 | ❌ NO CHECK on entry | CRITICAL |
|
||
|
|
| tiny_free_fast() call site | tiny_free_fast.inc.h:205-209 | ❌ NO CHECK before call | CRITICAL |
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. 所有権/範囲ガード詳細
|
||
|
|
|
||
|
|
### Box 3: Ownership Encapsulation (slab_handle.h)
|
||
|
|
|
||
|
|
**slab_try_acquire()** (Line 32-78):
|
||
|
|
```c
|
||
|
|
static inline SlabHandle slab_try_acquire(SuperSlab* ss, int idx, uint32_t tid) {
|
||
|
|
if (!ss || ss->magic != SUPERSLAB_MAGIC) return {0};
|
||
|
|
|
||
|
|
int cap = ss_slabs_capacity(ss);
|
||
|
|
if (idx < 0 || idx >= cap) { // <-- CORRECT: Range check
|
||
|
|
return {0};
|
||
|
|
}
|
||
|
|
|
||
|
|
TinySlabMeta* m = &ss->slabs[idx];
|
||
|
|
if (!ss_owner_try_acquire(m, tid)) {
|
||
|
|
return {0};
|
||
|
|
}
|
||
|
|
|
||
|
|
h.valid = 1;
|
||
|
|
return h;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Status: CORRECT**
|
||
|
|
- ✅ Range validation present before array access
|
||
|
|
- ✅ owner_tid check done safely
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. TOCTOU 問題の可能性
|
||
|
|
|
||
|
|
### Check-Then-Use Pattern Analysis
|
||
|
|
|
||
|
|
**In tiny_free_fast_ss():**
|
||
|
|
1. Time T0: `slab_idx = slab_index_for(ss, ptr)` (no check)
|
||
|
|
2. Time T1: `meta = &ss->slabs[slab_idx]` (use)
|
||
|
|
3. Time T2: `tiny_free_is_same_thread_ss()` reads meta->owner_tid
|
||
|
|
|
||
|
|
**TOCTOU Race Scenario:**
|
||
|
|
- Thread A: slab_idx = slab_index_for(ss, ptr) → slab_idx = 0 (valid)
|
||
|
|
- Thread B: [simultaneously] SuperSlab ss is unmapped and remapped elsewhere
|
||
|
|
- Thread A: &ss->slabs[0] now points to wrong memory
|
||
|
|
- Thread A: Reads/writes garbage data
|
||
|
|
|
||
|
|
**Status: UNLIKELY but POSSIBLE**
|
||
|
|
- Most likely attack: freeing to already-freed SuperSlab
|
||
|
|
- Mitigated by: hak_super_lookup() validation (SUPERSLAB_MAGIC check)
|
||
|
|
- But: If magic still valid, race exists
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 10. 発見したバグ一覧
|
||
|
|
|
||
|
|
### Bug #1: tiny_free_fast_ss() - No bounds check on slab_idx
|
||
|
|
|
||
|
|
**File:** core/tiny_free_fast.inc.h
|
||
|
|
**Line:** 91-92
|
||
|
|
**Severity:** CRITICAL
|
||
|
|
**Impact:** Buffer overflow when slab_index_for() returns -1
|
||
|
|
|
||
|
|
```c
|
||
|
|
static inline int tiny_free_fast_ss(SuperSlab* ss, int slab_idx, void* ptr, uint32_t my_tid) {
|
||
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx]; // BUG: No check if slab_idx < 0 or >= capacity
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix:**
|
||
|
|
```c
|
||
|
|
if (slab_idx < 0 || slab_idx >= ss_slabs_capacity(ss)) return 0;
|
||
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx];
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
### Bug #2: Magazine spill path (first occurrence) - No bounds check
|
||
|
|
|
||
|
|
**File:** core/hakmem_tiny_free.inc
|
||
|
|
**Line:** 305-308
|
||
|
|
**Severity:** CRITICAL
|
||
|
|
**Impact:** Buffer overflow in magazine recycling
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(owner_ss, it.ptr);
|
||
|
|
TinySlabMeta* meta = &owner_ss->slabs[slab_idx]; // BUG: No bounds check
|
||
|
|
*(void**)it.ptr = meta->freelist;
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix:**
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(owner_ss, it.ptr);
|
||
|
|
if (slab_idx < 0 || slab_idx >= ss_slabs_capacity(owner_ss)) continue;
|
||
|
|
TinySlabMeta* meta = &owner_ss->slabs[slab_idx];
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
### Bug #3: Magazine spill path (second occurrence) - No bounds check
|
||
|
|
|
||
|
|
**File:** core/hakmem_tiny_free.inc
|
||
|
|
**Line:** 464-467
|
||
|
|
**Severity:** CRITICAL
|
||
|
|
**Impact:** Same as Bug #2
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss_owner, it.ptr);
|
||
|
|
TinySlabMeta* meta = &ss_owner->slabs[slab_idx]; // BUG: No bounds check
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix:** Same as Bug #2
|
||
|
|
|
||
|
|
|
||
|
|
### Bug #4: tiny_free_fast() call site - No bounds check before tiny_free_fast_ss()
|
||
|
|
|
||
|
|
**File:** core/tiny_free_fast.inc.h
|
||
|
|
**Line:** 205-209
|
||
|
|
**Severity:** HIGH (depends on function implementation)
|
||
|
|
**Impact:** Passes invalid slab_idx to tiny_free_fast_ss()
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss, ptr);
|
||
|
|
uint32_t self_tid = tiny_self_u32();
|
||
|
|
|
||
|
|
// Box 6 Boundary: Try same-thread fast path
|
||
|
|
if (tiny_free_fast_ss(ss, slab_idx, ptr, self_tid)) { // Passes slab_idx without checking
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix:**
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss, ptr);
|
||
|
|
if (slab_idx < 0 || slab_idx >= ss_slabs_capacity(ss)) {
|
||
|
|
hak_tiny_free(ptr); // Fallback to slow path
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
uint32_t self_tid = tiny_self_u32();
|
||
|
|
if (tiny_free_fast_ss(ss, slab_idx, ptr, self_tid)) {
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 11. 修正提案
|
||
|
|
|
||
|
|
### Priority 1: Fix tiny_free_fast_ss() entry point
|
||
|
|
|
||
|
|
**File:** core/tiny_free_fast.inc.h (Line 91)
|
||
|
|
|
||
|
|
```c
|
||
|
|
static inline int tiny_free_fast_ss(SuperSlab* ss, int slab_idx, void* ptr, uint32_t my_tid) {
|
||
|
|
// ADD: Range validation
|
||
|
|
if (__builtin_expect(slab_idx < 0 || slab_idx >= ss_slabs_capacity(ss), 0)) {
|
||
|
|
return 0; // Invalid index → delegate to slow path
|
||
|
|
}
|
||
|
|
|
||
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx];
|
||
|
|
// ... rest of function
|
||
|
|
```
|
||
|
|
|
||
|
|
**Rationale:** This is the fastest fix (5 bytes code addition) that prevents the OOB access.
|
||
|
|
|
||
|
|
|
||
|
|
### Priority 2: Fix magazine spill paths
|
||
|
|
|
||
|
|
**File:** core/hakmem_tiny_free.inc (Line 305 and 464)
|
||
|
|
|
||
|
|
At both locations, add bounds check:
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(owner_ss, it.ptr);
|
||
|
|
if (slab_idx < 0 || slab_idx >= ss_slabs_capacity(owner_ss)) {
|
||
|
|
continue; // Skip if invalid
|
||
|
|
}
|
||
|
|
TinySlabMeta* meta = &owner_ss->slabs[slab_idx];
|
||
|
|
```
|
||
|
|
|
||
|
|
**Rationale:** Magazine spill is not a fast path, so small overhead acceptable.
|
||
|
|
|
||
|
|
|
||
|
|
### Priority 3: Add bounds check at tiny_free_fast() call site
|
||
|
|
|
||
|
|
**File:** core/tiny_free_fast.inc.h (Line 205)
|
||
|
|
|
||
|
|
Add validation before calling tiny_free_fast_ss():
|
||
|
|
|
||
|
|
```c
|
||
|
|
int slab_idx = slab_index_for(ss, ptr);
|
||
|
|
if (__builtin_expect(slab_idx < 0 || slab_idx >= ss_slabs_capacity(ss), 0)) {
|
||
|
|
hak_tiny_free(ptr); // Fallback
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
uint32_t self_tid = tiny_self_u32();
|
||
|
|
|
||
|
|
if (tiny_free_fast_ss(ss, slab_idx, ptr, self_tid)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Rationale:** Defense in depth - validate at call site AND in callee.
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 12. Test Case to Trigger Bugs
|
||
|
|
|
||
|
|
```c
|
||
|
|
void test_slab_index_for_oob() {
|
||
|
|
SuperSlab* ss = allocate_1mb_superslab();
|
||
|
|
|
||
|
|
// Case 1: Pointer before SuperSlab
|
||
|
|
void* ptr_before = (void*)((uintptr_t)ss - 1024);
|
||
|
|
int idx = slab_index_for(ss, ptr_before);
|
||
|
|
assert(idx == -1); // Should return -1
|
||
|
|
|
||
|
|
// Case 2: Pointer at SS end (just beyond capacity)
|
||
|
|
void* ptr_after = (void*)((uintptr_t)ss + (1024*1024));
|
||
|
|
idx = slab_index_for(ss, ptr_after);
|
||
|
|
assert(idx == -1); // Should return -1
|
||
|
|
|
||
|
|
// Case 3: tiny_free_fast() with OOB pointer
|
||
|
|
tiny_free_fast(ptr_after); // BUG: Calls tiny_free_fast_ss(ss, -1, ptr, tid)
|
||
|
|
// Without fix: Accesses ss->slabs[-1] → buffer overflow
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Summary
|
||
|
|
|
||
|
|
| Issue | Location | Severity | Status |
|
||
|
|
|-------|----------|----------|--------|
|
||
|
|
| slab_index_for() implementation | hakmem_tiny_superslab.h:141 | Info | Correct |
|
||
|
|
| tiny_free_fast_ss() bounds check | tiny_free_fast.inc.h:91 | CRITICAL | Bug |
|
||
|
|
| Magazine spill #1 bounds check | hakmem_tiny_free.inc:305 | CRITICAL | Bug |
|
||
|
|
| Magazine spill #2 bounds check | hakmem_tiny_free.inc:464 | CRITICAL | Bug |
|
||
|
|
| tiny_free_fast() call site | tiny_free_fast.inc.h:205 | HIGH | Bug |
|
||
|
|
| slab_try_acquire() bounds check | slab_handle.h:32 | Info | Correct |
|
||
|
|
| hak_tiny_free_superslab() bounds check | hakmem_tiny_free.inc:1164 | Info | Correct |
|
||
|
|
|