286 lines
7.6 KiB
Markdown
286 lines
7.6 KiB
Markdown
|
|
# 🚨 重大発見: TLS SLL Head 汚染 (2025-12-03)
|
|||
|
|
|
|||
|
|
**Status**: 🔴 CRITICAL - 根本原因が明確に
|
|||
|
|
**Commit**: 4d2784c52
|
|||
|
|
**Discovery**: ChatGPT による診断強化で判明
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 発見内容
|
|||
|
|
|
|||
|
|
### 以前の仮説(間違い)
|
|||
|
|
```
|
|||
|
|
問題: ポインタが16バイトずれてる
|
|||
|
|
原因: next ポインタのオフセット計算エラー
|
|||
|
|
→ 修正: tiny_next_off() の検証
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 新しい真実(正しい)
|
|||
|
|
```
|
|||
|
|
問題: TLS SLL の head 自体が ゴミ値に上書きされてる
|
|||
|
|
原因: TLS領域への外部からの不正な書き込み
|
|||
|
|
→ 修正: 書き込み元を特定して防止する必要あり
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 診断実行結果(/tmp/sh8_short.log)
|
|||
|
|
|
|||
|
|
### ログから見える汚染パターン
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[TLS_SLL_SANITIZE] stage=pop_enter cls=1 head=0x749fe96c0990 meta_cls=255 idx=-1 ss=(nil)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**解釈**:
|
|||
|
|
- `head=0x749fe96c0990` → SuperSlabレジストリに登録されてない
|
|||
|
|
- `meta_cls=255` → 無効なメタデータ(0xff)
|
|||
|
|
- `idx=-1` → そのアドレスはSlabの範囲外
|
|||
|
|
- `ss=(nil)` → hak_super_lookup() が NULL返却
|
|||
|
|
|
|||
|
|
### 重要な観察
|
|||
|
|
|
|||
|
|
1. **SuperSlab登録は成功**
|
|||
|
|
```
|
|||
|
|
Superslab register class0/1/2/6 で map_count=4
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **しかしその直後、TLS headが壊れてる**
|
|||
|
|
```
|
|||
|
|
pop_enter 時点ですでに head が正しくない
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **汚染値はランダム**
|
|||
|
|
```
|
|||
|
|
head=0x749fe96c0990 (その時々で違う値)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 根本原因分析
|
|||
|
|
|
|||
|
|
### パターン認識
|
|||
|
|
|
|||
|
|
| 兆候 | 解釈 |
|
|||
|
|
|------|------|
|
|||
|
|
| SuperSlab登録成功 | → 割り当ては正常 |
|
|||
|
|
| head がゴミ値 | → TLS領域が上書きされた |
|
|||
|
|
| meta_cls=255 | → ユーザーデータなどの無関係な値 |
|
|||
|
|
| 汚染値が無登録 | → 誰かが意図せず書き込んだ |
|
|||
|
|
|
|||
|
|
### 可能性のある原因
|
|||
|
|
|
|||
|
|
#### 原因1: TLS変数境界オーバーフロー ⭐⭐⭐
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// TLS領域が連続してて、隣の変数がオーバーフロー?
|
|||
|
|
struct {
|
|||
|
|
TlsSllBucket g_tls_sll[TINY_NUM_CLASSES]; // ← ここが破壊される
|
|||
|
|
...other TLS vars... // ← ここからのoverflow?
|
|||
|
|
} tls_state;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**症状と一致**:
|
|||
|
|
- g_tls_sll が破壊される(他の領域は無視)
|
|||
|
|
- 値がランダム(overflow元の値に依存)
|
|||
|
|
|
|||
|
|
#### 原因2: memset/memcpy 範囲エラー ⭐⭐
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// どこかで誤った範囲で memset/memcpy?
|
|||
|
|
memset(ptr, 0, size); // size が大きすぎる?
|
|||
|
|
memcpy(dst, src, len); // len が大きすぎる?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**症状と一致**:
|
|||
|
|
- TLS領域が一部破壊される(全体ではない)
|
|||
|
|
- 初期化時の特定タイミングで発生
|
|||
|
|
|
|||
|
|
#### 原因3: TLS初期化の重複実行 ⭐
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// スレッド初期化が2回実行される?
|
|||
|
|
tls_state_init(); // 1回目 - OK
|
|||
|
|
tls_state_init(); // 2回目 - head を上書き?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**症状と一致**:
|
|||
|
|
- head が新しい値に置き換わる
|
|||
|
|
- SuperSlab登録後に発生
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 現在のサニタイズ(防御的対策)
|
|||
|
|
|
|||
|
|
### tls_sll_sanitize_head() の動作
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// push/pop の入口で実行
|
|||
|
|
if (head が SuperSlab に登録されてない) {
|
|||
|
|
fprintf(stderr, "[TLS_SLL_SANITIZE] ...");
|
|||
|
|
g_tls_sll[class_idx].head = NULL;
|
|||
|
|
count = 0;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**効果**:
|
|||
|
|
- ✅ 破損リストが伝播するのを防ぐ
|
|||
|
|
- ✅ その後の割り当てが新しいリストを使う
|
|||
|
|
- ✅ ログで汚染を検知できる
|
|||
|
|
|
|||
|
|
**制限**:
|
|||
|
|
- ⚠️ 根本原因(何が書き込んでるか)は未解決
|
|||
|
|
- ⚠️ フリーリストの喪失(メモリリーク)
|
|||
|
|
- ⚠️ パフォーマンス低下の可能性
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 次のChatGPTタスク(優先順位順)
|
|||
|
|
|
|||
|
|
### Task A: TLS領域のメモリレイアウト完全監査 ⭐⭐⭐
|
|||
|
|
|
|||
|
|
**目的**: 隣接変数のオーバーフロー候補を特定
|
|||
|
|
|
|||
|
|
**実行内容**:
|
|||
|
|
```bash
|
|||
|
|
# TLS変数の宣言と位置を全て特定
|
|||
|
|
grep -r "^__thread" core/
|
|||
|
|
grep -r "_Thread_local" core/
|
|||
|
|
|
|||
|
|
# 各変数のサイズを計算
|
|||
|
|
# → 隣接変数がオーバーフローできる大きさか確認
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**チェック項目**:
|
|||
|
|
- [ ] g_tls_sll のサイズ(確認: 8 * sizeof(TlsSllBucket))
|
|||
|
|
- [ ] その直後の変数は何か
|
|||
|
|
- [ ] その変数がオーバーフローできるサイズか
|
|||
|
|
- [ ] メモリレイアウト図を作成
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Task B: 全ての memset/memcpy/memmove 監査 ⭐⭐⭐
|
|||
|
|
|
|||
|
|
**目的**: 誤った範囲の書き込みを特定
|
|||
|
|
|
|||
|
|
**実行内容**:
|
|||
|
|
```bash
|
|||
|
|
# TLS領域をなめてる全ての memXxx 呼び出しを特定
|
|||
|
|
grep -r "memset.*tls\|memcpy.*tls\|memmove.*tls" core/
|
|||
|
|
|
|||
|
|
# 特にサイズ計算エラーがないか確認
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**チェック項目**:
|
|||
|
|
- [ ] memset で `sizeof()` 使ってるか、hardcode じゃないか
|
|||
|
|
- [ ] memcpy の src/dst/len が正確か
|
|||
|
|
- [ ] TLS領域全体をリセットしてる場所がないか
|
|||
|
|
- [ ] オフセット計算エラーがないか
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Task C: TLS初期化の重複/競合検査 ⭐⭐
|
|||
|
|
|
|||
|
|
**目的**: 初期化処理が複数回実行されないことを確認
|
|||
|
|
|
|||
|
|
**実行内容**:
|
|||
|
|
```c
|
|||
|
|
// hakmem_tls_state_box.inc に追加:
|
|||
|
|
static _Atomic int g_tls_init_count = 0;
|
|||
|
|
|
|||
|
|
static inline void tls_state_init() {
|
|||
|
|
int count = atomic_fetch_add(&g_tls_init_count, 1);
|
|||
|
|
if (count > 0) {
|
|||
|
|
fprintf(stderr, "[TLS_INIT_DUPLICATE] count=%d THREAD_ID=%p\n", count, ...);
|
|||
|
|
}
|
|||
|
|
// ... 初期化 ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**チェック項目**:
|
|||
|
|
- [ ] 各スレッドで init が1回だけ実行されるか
|
|||
|
|
- [ ] コンテキストスイッチ中に2重実行される可能性
|
|||
|
|
- [ ] pthread_once() や similar mechanism があるか
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 追加の診断情報
|
|||
|
|
|
|||
|
|
### ログから読める情報
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[TLS_SLL_SANITIZE] stage=pop_enter cls=1 head=0x749fe96c0990 meta_cls=255 idx=-1 ss=(nil)
|
|||
|
|
↑ ↑ ↑ ↑ ↑
|
|||
|
|
| | | | └─ Lookup失敗
|
|||
|
|
| | | └─ 無効メタデータ
|
|||
|
|
| | └─ 汚染されたhead値
|
|||
|
|
| └─ クラス1
|
|||
|
|
└─ pop開始時に検出
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**推測**:
|
|||
|
|
1. pop_enter で head を読む
|
|||
|
|
2. その値は「どこかから」上書きされてる
|
|||
|
|
3. 上書き時期: push直後~pop直前の間
|
|||
|
|
4. 上書き値: 無関係なポインタ(memory garbage)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## パフォーマンス影響
|
|||
|
|
|
|||
|
|
### 現在のサニタイズ
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
tls_sll_sanitize_head() {
|
|||
|
|
hak_super_lookup(); // O(1) hash lookup
|
|||
|
|
slab_index_for(); // O(1)
|
|||
|
|
metadata check; // O(1)
|
|||
|
|
if (corrupted) reset; // O(1)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**コスト**: 1-5 サイクル/pop(許容範囲)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## まとめ
|
|||
|
|
|
|||
|
|
### 現在判明したこと ✅
|
|||
|
|
|
|||
|
|
1. **問題の本質**: TLS head が外部から上書きされてる
|
|||
|
|
2. **次ポインタオフセットではない** - 仮説は誤り
|
|||
|
|
3. **防御機構は機能中** - sanitize で検知・リセット可能
|
|||
|
|
4. **根本原因は未特定** - TLS領域の誰かが書き込んでる
|
|||
|
|
|
|||
|
|
### 必要な調査
|
|||
|
|
|
|||
|
|
1. TLS領域のメモリレイアウト完全把握
|
|||
|
|
2. 全ての memXxx 操作の監査
|
|||
|
|
3. TLS初期化の重複チェック
|
|||
|
|
|
|||
|
|
### 期待される成果
|
|||
|
|
|
|||
|
|
これら3つのタスクを実行すれば、**真の原因が必ず見つかる**はず。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 技術的インパクト
|
|||
|
|
|
|||
|
|
| 項目 | 影響 |
|
|||
|
|
|------|------|
|
|||
|
|
| **根本原因** | TLS領域への不正な書き込み(外部) |
|
|||
|
|
| **修正難度** | 中程度(原因特定後は簡単) |
|
|||
|
|
| **パフォーマンス** | 現在の防御は< 2% |
|
|||
|
|
| **安全性** | サニタイズで破損伝播を防ぐ(良) |
|
|||
|
|
| **長期展望** | 根本原因を排除すれば性能回復 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**次のステップ**: ChatGPT に Task A/B/C を指示
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*Document created: 2025-12-03*
|
|||
|
|
*Commit: 4d2784c52*
|
|||
|
|
*Discovery: ChatGPT diagnostic logging revealed head corruption, not offset issue*
|