Skip to content

Commit 9fda057

Browse files
optimize: to webp and fix CI
1 parent 0647f74 commit 9fda057

1,477 files changed

Lines changed: 66 additions & 66 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

document/notes/linux_kernel_debugging/ch01_2.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
这个故事很棒,很有画面感,以至于它成了计算机科学界的传说。
4848

49-
![The famous moth](images/ch01_fig001.jpeg)
49+
![The famous moth](images/ch01_fig001.webp)
5050
*图 1.1——那只著名的飞蛾(由 Naval Surface Warfare Center, Dahlgren, VA 提供,1988 年。U.S. Naval Historical Center Online Library Photograph NH 96566-KN. Public Domain)*
5151

5252
但作为一名严谨的工程师,我得泼一盆冷水:

document/notes/linux_kernel_debugging/ch03_2.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ module_exit(printk_loglevels_exit);
233233

234234
当我们把它插进内核,你会看到类似这样的输出(截图 3.1):
235235

236-
![figure](images/ch03_fig019.png)
236+
![figure](images/ch03_fig019.webp)
237237
*(图 3.1 – printk_loglevels 模块的运行输出截图)*
238238

239239
这里有几个细节值得你停下来看一看:
@@ -254,7 +254,7 @@ module_exit(printk_loglevels_exit);
254254

255255
我们可以用一张表来概括它的流向(表 3.1):
256256

257-
![figure](images/ch03_fig020.png)
257+
![figure](images/ch03_fig020.webp)
258258
*(图 3.1 – printk 输出流向示意图)*
259259

260260
| 输出位置 | 描述 | 查看方式 |

document/notes/linux_kernel_debugging/ch04_3.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ BUG: sleeping function called from invalid context at lib/strncpy_from_user.c:11
125125
126126
为了控制日志量,我们依然只在进程上下文是 `vi` 的时候才打印。图 4.5 展示了 `dmesg` 的输出尾部:
127127
128-
![figure](images/ch04_fig037.png)
128+
![figure](images/ch04_fig037.webp)
129129
130130
**图 4.5** – x86_64 VM 上 3_kprobe 演示的 dmesg 输出尾部(过滤仅显示 vi 进程上下文)
131131
@@ -164,7 +164,7 @@ rpi4 # echo –n 0 > /sys/module/3_kprobe/parameters/skip_if_not_vi
164164

165165
好了,现在所有的文件打开系统调用都会被捕获。图 4.6 可以看到效果(你可以清楚地看到 `dmesg``systemd-journal` 进程正在打开各种文件):
166166

167-
![figure](images/ch04_fig038.png)
167+
![figure](images/ch04_fig038.webp)
168168

169169
**图 4.6** – 树莓派 4 (AArch64) 上运行 3_kprobe 的截图,显示所有正在被打开的文件
170170

@@ -255,7 +255,7 @@ static irqreturn_t e1000_intr(int irq, void *data);
255255

256256
仔细看我们传给脚本的参数。图 4.7 展示了脚本的执行过程:
257257

258-
![figure](images/ch04_fig039.png)
258+
![figure](images/ch04_fig039.webp)
259259

260260
**图 4.7** – kp_load.sh 辅助脚本执行并加载自定义 kprobe LKM 的截图
261261

@@ -265,7 +265,7 @@ static irqreturn_t e1000_intr(int irq, void *data);
265265

266266
我把内核日志保存到文件 (`journalctl –k > myklog`),然后卸载模块,用 `vi` 打开日志。输出量很大,图 4.8 是部分截图。你能看到我们自定义 kprobe 的 pre-handler printk、`PRINT_CTX()` 宏的输出,以及最劲爆的 `dump_stack()` 的输出!最后两行是 post handler 的输出:
267267

268-
![figure](images/ch04_fig040.png)
268+
![figure](images/ch04_fig040.webp)
269269

270270
**图 4.8** – 内核日志部分截图,显示 helper script 生成的 kprobe 在 pre-handler 里的输出;最后两行是 post handler 的
271271

document/notes/linux_kernel_debugging/ch05_3.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747

4848
这就是为什么现代 Linux 内核支持三种不同「档次」的 KASAN 模式。我们在表 5.2 里总结了一下它们的行为:
4949

50-
![table](images/ch05_fig047.png)
50+
![table](images/ch05_fig047.webp)
5151
*(表 5.2:KASAN 的三种模式及其开销对比)*
5252

5353
| 模式 | 昵称 | 内存/CPU 开销 | 适用场景 | 架构限制 |

document/notes/linux_kernel_debugging/ch05_4.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ make ARCH=arm64 menuconfig
1919

2020
进入这个子菜单后,你会看到模式选择的选项。这里我们保持默认,也就是 **Generic KASAN** 模式。
2121

22-
![Kernel Configuration Menu](images/ch05_fig048.png)
22+
![Kernel Configuration Menu](images/ch05_fig048.webp)
2323
*图 5.1 – 启用 KASAN 的内核配置截图*
2424

2525
当你把光标停在 `Config KASAN as generic mode` 这一项上时,按下 `< Help >` 键,屏幕上会弹出一段值得你花 10 秒钟读完的提示。这不仅是说明,这是它在向你索要「代价」:

document/notes/linux_kernel_debugging/ch05_5.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ $ sudo modprobe test_kasan
9191

9292
这会导致 KASAN 测试模块里的所有测试用例全部执行!查看内核日志(通过 `journalctl -k``dmesg`),你会看到每个测试用例详细的 KASAN 报告。因为输出内容非常庞大,我只截取一部分。第一个测试用例——`KUNIT_CASE(kmalloc_oob_right)`——导致 KASAN 生成了如下报告(输出被截断了——后面会有更多):
9393

94-
![Figure 5.2](images/ch05_fig049.png)
94+
![Figure 5.2](images/ch05_fig049.webp)
9595

9696
**Figure 5.2 – KUnit KASAN 抓虫示例的第一部分**
9797

@@ -118,13 +118,13 @@ $ sudo modprobe test_kasan
118118
119119
输出的剩余部分可以在下图中看到:
120120
121-
![Figure 5.3](images/ch05_fig050.png)
121+
![Figure 5.3](images/ch05_fig050.webp)
122122
123123
**Figure 5.3 – KUnit KASAN 抓虫示例的第二部分**
124124
125125
由于我们之前建议在配置 Generic KASAN 模式时开启了 `CONFIG_PAGE_OWNER=y`(参见 Configuring the kernel for Generic KASAN mode 一节),下面的输出也会出现。它让你深入了解到发生非法访问的页面位于何处以及它的所有权信息:
126126
127-
![Figure 5.4](images/ch05_fig051.png)
127+
![Figure 5.4](images/ch05_fig051.webp)
128128
129129
**Figure 5.4 – KUnit KASAN 抓虫示例的第三(也是最后)部分**
130130
@@ -173,7 +173,7 @@ ptr[123] = 'x';
173173

174174
Generic KASAN 的内存粒度大小是 8 字节。所以在分配的 123 字节中,第 15 个内存粒度(`8 * 15 = 120`)正是我们要写入的目标。下面的示意图清晰地展示了内存缓冲区以及它是如何被溢出的:
175175

176-
![Figure 5.5](images/ch05_fig052.png)
176+
![Figure 5.5](images/ch05_fig052.webp)
177177

178178
**Figure 5.5 – 被 kmalloc 分配的内存(slab)缓冲区发生了溢出**
179179

@@ -197,7 +197,7 @@ Generic KASAN 的内存粒度大小是 8 字节。所以在分配的 123 字节
197197
198198
快速检查一下内核日志,会发现如我们所料——内核的 KUnit KASAN 测试用例模块抓住了所有 38 个有内存缺陷的测试用例:
199199
200-
![Figure 5.6](images/ch05_fig053.png)
200+
![Figure 5.6](images/ch05_fig053.webp)
201201
202202
**Figure 5.6 – 截图显示内核的 KUnit KASAN 测试模块抓住了全部 38 个有内存缺陷的测试用例**
203203
@@ -291,7 +291,7 @@ res1 == NULL ? "<whoops, it's NULL; UAR!>" : (char *)res1);
291291

292292
现实是,内存通常是以页面级别为粒度分配的。这也包括栈页面的内存。因此,一旦为栈分配了一页内存,通常足够容纳好几个帧(当然,这取决于具体情况)。然后,当需要更多栈内存时,栈就会增长(通过分配更多页面,向下增长,因为栈是向下长的)。系统通过让栈指针(Stack Pointer, SP)寄存器跟踪这个内存位置来知晓栈顶在哪里。此外,你要意识到所谓的「栈顶」通常是最低的合法地址。因此,当帧被分配和/或函数被调用时,SP 寄存器的值会减少。当函数返回时,栈通过向 SP 寄存器加值来收缩(记住,这是一个向下增长的栈!)。下面的示意图展示了一个典型的 Linux 系统上(32 位)内核模式栈的样子:
293293

294-
![Figure 5.7](images/ch05_fig054.png)
294+
![Figure 5.7](images/ch05_fig054.webp)
295295

296296
**Figure 5.7 – 32 位 Linux 上典型的内核模式栈示意图;函数调用链:foo1() -> bar1() -> foo2() -> bar2()**
297297

@@ -330,13 +330,13 @@ res1 == NULL ? "<whoops, it's NULL; UAR!>" : (char *)res1);
330330

331331
下面的截图显示我们的 `test_kmembugs` 模块确实被加载进去了(这是通过我们的 `load_testmod` 脚本完成的),通过 `run_tests` 脚本显示了菜单,以及我们正在运行测试用例 #2——那个 UAR Bug:
332332

333-
![Figure 5.8](images/ch05_fig055.png)
333+
![Figure 5.8](images/ch05_fig055.webp)
334334

335335
**Figure 5.8 – 部分截图,显示了我们的 kmembugs_test LKM 的构建和输出**
336336

337337
下面是我们的测试用例框架通过 KASAN 抓住左 OOB 写 Bug 访问的示例截图:
338338

339-
![Figure 5.9](images/ch05_fig056.png)
339+
![Figure 5.9](images/ch05_fig056.webp)
340340

341341
**Figure 5.9 – 部分截图,显示了 KASAN 抓住了向全局内存写入时的左 OOB Bug**
342342

@@ -379,8 +379,8 @@ $
379379
380380
KASAN 到底能抓到哪些内存破坏 Bug(缺陷),又抓不到哪些?根据我们的测试运行,我们把结果汇总在下面的表格里。请仔细研究它,以及随后的注释:
381381
382-
![Figure 5.7](images/ch05_fig057.png)
383-
![Figure 5.8](images/ch05_fig058.png)
382+
![Figure 5.7](images/ch05_fig057.webp)
383+
![Figure 5.8](images/ch05_fig058.webp)
384384
385385
**Table 5.3 – KASAN 捕获(或未捕获)的内存缺陷和算术 UB 测试用例汇总**
386386

document/notes/linux_kernel_debugging/ch05_8.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
这也是为什么会有下面这张大表。
1010

11-
![Table 5.5](images/ch05_fig058.png)
11+
![Table 5.5](images/ch05_fig058.webp)
1212

1313
**表 5.5 —— 各种常见内存缺陷与不同技术捕获能力的总结**
1414

document/notes/linux_kernel_debugging/ch06_3.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
4040
看图:
4141
42-
![Figure 6.1 – Bootlin 源码截图](images/ch06_fig067.png)
42+
![Figure 6.1 – Bootlin 源码截图](images/ch06_fig067.webp)
4343
4444
真是不偏不倚。触发 bug 的正是第 305 行。这说明即使是普通的 vanilla 内核,也保留了最后一丝理智——它能检测出这种「原始」的 double-free,知道这是一种内存破坏。
4545
@@ -55,7 +55,7 @@
5555
5656
如果你是通过 VirtualBox 或者直接在真机上操作,编辑 GRUB 启动项大概是这样:
5757
58-
![Figure 6.2 – GRUB 编辑菜单](images/ch06_fig068.jpeg)
58+
![Figure 6.2 – GRUB 编辑菜单](images/ch06_fig068.webp)
5959
6060
改完重启进系统,第一步永远是确认内核真的收到了你的指令。别懒,这一定要看:
6161

document/notes/linux_kernel_debugging/ch07_3.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ sudo insmod ./oops_tryv2.ko bug_in_workq=yes
2626

2727
让我们把目光集中在图 7.7 标注为 **1** 的区域。
2828

29-
![图 7.7 – Oops 输出分解图:第 1 部分](images/ch07_fig093.jpeg)
29+
![图 7.7 – Oops 输出分解图:第 1 部分](images/ch07_fig093.webp)
3030

3131
这是 Oops 的第一部分,也是定性的部分。**背景里的红色**并不是为了吓唬你,那是 `dmesg``pr_alert()` 日志级别的默认配色——内核在用颜色大喊:「出大事了!」
3232

@@ -135,13 +135,13 @@ pr_alert("#PF: error_code(0x%04lx) – %s\n", error_code,
135135
Oops: 0002 [#1] PREEMPT SMP PTI
136136
```
137137

138-
![图 7.8 – Oops 输出第 2 部分](images/ch07_fig094.png)
138+
![图 7.8 – Oops 输出第 2 部分](images/ch07_fig094.webp)
139139

140140
这里的 `0002` 可不是刚才那个 `error_code`,它是 **Oops 位掩码**。虽然数值碰巧一样,但含义不同。这是内核架构特定的错误代码,由 `arch/x86/kernel/dumpstack.c` 里的 `__die()` 函数打印出来的。
141141

142142
我们可以从内核源码里看到它的生成逻辑:
143143

144-
![图 7.9 – 生成 Oops 位掩码的内核代码片段](images/ch07_fig095.png)
144+
![图 7.9 – 生成 Oops 位掩码的内核代码片段](images/ch07_fig095.webp)
145145

146146
这串数字就像是 CPU 的指纹。在 x86 架构上,MMU 在发生缺页时,会通过位掩码的形式告诉内核具体发生了什么。这不仅仅是给内核看的,也是给你的。
147147

@@ -180,7 +180,7 @@ Oops: 0002 [#1] PREEMPT SMP PTI
180180

181181
接下来的两行(对应图 7.10)帮我们锁定「是谁干的」。
182182

183-
![图 7.10 – Oops 输出第 3 部分](images/ch07_fig097.jpeg)
183+
![图 7.10 – Oops 输出第 3 部分](images/ch07_fig097.webp)
184184

185185
```text
186186
CPU: 0 PID: 16 Comm: kworker/0:1 Tainted: G OE 5.10.60-prod01 #6
@@ -203,7 +203,7 @@ Linux 内核开发社区非常在意「纯净」二字。一个「被污染」
203203

204204
这个状态由一个 18 位的位掩码记录。你可以对照下面的表来破译这些字母:
205205

206-
![图 7.10-2 – Tainted 标志位含义表](images/ch07_fig098.png)
206+
![图 7.10-2 – Tainted 标志位含义表](images/ch07_fig098.webp)
207207

208208
*表 7.2 – 内核污染标志位含义速查*
209209

@@ -227,7 +227,7 @@ Linux 内核开发社区非常在意「纯净」二字。一个「被污染」
227227

228228
接下来的这几行(对应图 7.11)是整个尸检报告中最核心的部分——**案发现场的确切坐标**
229229

230-
![图 7.11 – Oops 输出第 4 部分](images/ch07_fig099.png)
230+
![图 7.11 – Oops 输出第 4 部分](images/ch07_fig099.webp)
231231

232232
我们重点看这行:
233233

@@ -271,7 +271,7 @@ oopsie->data = 'x'; // 这里就是 RIP 停下的地方
271271

272272
最后,我们看一眼剩下的两块拼图:机器码(图 7.12)和寄存器状态(图 7.13)。
273273

274-
![图 7.12 – Oops 输出第 5 部分:机器码](images/ch07_fig101.png)
274+
![图 7.12 – Oops 输出第 5 部分:机器码](images/ch07_fig101.webp)
275275

276276
```text
277277
Code: 48 c7 43 30 78 00 00 00 e8 1f e5 ff ff 48 89 ef 5d 41 5c 5d c3 0f 1f 44 00 00 48 8b 7b 30 48 85 ff 74 04 48 89 df e8 0b 50 00 00 <48> 89 43 30 e8 15 e5 ff ff 48 89 ef 5d 41 5c 5d c3
@@ -283,7 +283,7 @@ Code: 48 c7 43 30 78 00 00 00 e8 1f e5 ff ff 48 89 ef 5d 41 5c 5d c3 0f 1f 44 00
283283
> **小工具预告**
284284
> 后面我们会专门讲如何使用 `decodecode``decode_stacktrace.sh` 脚本来自动化分析这些内容。别急,工具就在手边。
285285
286-
![图 7.13 – Oops 输出第 6 部分:寄存器值](images/ch07_fig092.png)
286+
![图 7.13 – Oops 输出第 6 部分:寄存器值](images/ch07_fig092.webp)
287287

288288
这堆寄存器 dump 出来的是 CPU 那个瞬间的**内心世界**
289289
- **RSP**:栈指针。`0xffffb6e1c008be48`。内核栈向下增长,这就是栈顶。
@@ -304,7 +304,7 @@ Code: 48 c7 43 30 78 00 00 00 e8 1f e5 ff ff 48 89 ef 5d 41 5c 5d c3 0f 1f 44 00
304304

305305
最后一部分,也是对调试最有帮助的部分(图 7.14):**Call Trace(调用栈)**
306306

307-
![图 7.14 – Oops 输出第 7-9 部分:调用栈与 CR2](images/ch07_fig103.jpeg)
307+
![图 7.14 – Oops 输出第 7-9 部分:调用栈与 CR2](images/ch07_fig103.webp)
308308

309309
```text
310310
Call Trace:

document/notes/linux_kernel_debugging/ch07_5.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
在看细节之前,先有一张地图总是好的。表 7.3 列出了本节会重点讨论的几个脚本,以及它们各自解决什么问题。这不是完整的列表(源码树里还有更多),但这些都是你调试路上的「救命稻草」。
1818

19-
![Table 7.3](images/ch07_fig106.png)
19+
![Table 7.3](images/ch07_fig106.webp)
2020

2121
**表 7.3 —— 常用内核辅助脚本速查表**
2222

@@ -182,7 +182,7 @@ decode_code() {
182182

183183
假设我们把 `do_the_work` 触发 Oops 时的机器码部分单独拎出来喂给 `decodecode`,它会吐出类似图 7.17 这样的输出:
184184

185-
![Figure 7.17](images/ch07_fig107.png)
185+
![Figure 7.17](images/ch07_fig107.webp)
186186

187187
**图 7.17 —— decodecode 脚本输出示例**
188188

@@ -299,7 +299,7 @@ $ ./scripts/get_maintainer.pl -f kernel/debug/gdbstub.c
299299

300300
脚本会像变魔术一样吐出一堆信息(见图 7.19):
301301

302-
![Figure 7.19](images/ch07_fig109.png)
302+
![Figure 7.19](images/ch07_fig109.webp)
303303

304304
**图 7.19 —— get_maintainer.pl 输出示例**
305305

0 commit comments

Comments
 (0)