Linux 内核编译生成的 System.map 文件的内容到底是什么意思?

2022-01-25 11:44:09 +08:00
 kgdb00
这个文件记录的函数地址不可能是物理地址,因为数值非常大,比如这一行:

[root@develop linux]# grep kvm_guest_init System.map
ffffffff81afa999 t kvm_guest_init

我在这个函数的入口打印它的地址和 System.map 记录的是一样的。

这个地址是分页前的线性地址吗?如果是的话,那我怎么知道这个函数实际运行过程中的物理地址?
2251 次点击
所在节点    Linux
12 条回复
2i2Re2PLMaDnghL
2022-01-25 12:58:06 +08:00
首先物理地址应该是只有内核态下才能知道,每次冷启动都会导致内存随机化分布,内核的代码实际存在的位置是随机的,缓解缓冲区溢出覆盖代码区导致的影响(攻击者无法知道溢出之后覆盖到哪个函数那儿去)
kgdb00
2022-01-25 13:12:25 +08:00
@2i2Re2PLMaDnghL 感谢回复
https://www.kernel.org/doc/html/latest/x86/boot.html 这个文档讲物理地址 0x100000 以上是 Protected-mode kernel ,意思应是内核代码的物理地址在从 2MB 开始的区域,我猜测内核函数的物理地址随机化之后应该也是在靠近 2MB 的位置,不太可能是整个物理内存完全随机,因为那样的话就不好分配一个很大的物理地址连续的页框,不知道我猜的对不对。
kgdb00
2022-01-25 13:14:45 +08:00
@kgdb00 #2 更正:一个页框 -> 一组页框
yanqiyu
2022-01-26 07:49:43 +08:00
system.map 里面是没开 kaslr 的情况下内核被装载到的虚拟地址,开了之后会变,要用 root 去 /proc/kallsyms 下面读

至于物理地址,应该可以去 /proc/iomem 拿到 kernel 的基地址,再根据 system.map 算偏移就行

至于内核物理地址的随机化确实不是到处随机,而是在前 512M?记不清了?因为随机化内核还要避开一堆不能用的内存于是整个过程干的事情很杂乱
yanqiyu
2022-01-26 08:06:08 +08:00
@yanqiyu 重新看了下,是我记错了,基本上是完全随机的,避开一些不能用的内存,拿到一些 slots ,然后在这些 slots 里面随机选择,并加上一个偏移

那个 512M 是这些随机范围的下区间的最大值,实际上用不到,除非 hack 了 config

https://github.com/torvalds/linux/blob/master/arch/x86/boot/compressed/kaslr.c
kgdb00
2022-01-26 16:12:25 +08:00
@yanqiyu 感谢回复
我试了一下,关闭 kaslr 后通过查看 /proc/iomem 发现内核代码的起始地址固定是在物理内存 16MB ( qemu )或 32MB (物理机),不明白为什么不是在 2MB 。
kgdb00
2022-01-26 17:05:30 +08:00
@yanqiyu 顺便问一下,怎么知道内核的 stack 是在物理内存和虚拟内存的哪个位置?
yanqiyu
2022-01-26 20:11:16 +08:00
@kgdb00 因为现在内核是压缩过的,bootloader 加载到 2mb 位置的东西也是一个 loader 负责初始化和解压真正的内核
kgdb00
2022-01-26 20:44:28 +08:00
@yanqiyu 为什么这么认为?

https://www.kernel.org/doc/html/latest/x86/boot.html 这篇文档讲的就是 bzImage 的 kernel 的 Protected-mode kernel 地址是从 0x100000 开始的。

而且《 Understanding the LINUX KERNEL 》这本书的附录 1 的“Booting Linux from a Disk”节也这样讲:
Invokes a BIOS procedure to load the rest of the kernel image from disk and puts the image in RAM starting from either low address 0x00010000 (for small kernel images compiled with make zImage) or high address 0x00100000 (for big kernel images compiled with make bzImage).
kgdb00
2022-01-26 21:23:27 +08:00
@yanqiyu 更正一下我的描述,我说的 2MB 都是指从第二个 MB 开始的地址,也就是从 0x100000 开始的地址。
yanqiyu
2022-01-26 21:56:39 +08:00
@kgdb00 看样子我记错了,解压出来的 image 确实是在 0x1000000 的位置的,我把这个地址和实模式部分记混了,要不看看你的内核的 CONFIG_PHYSICAL_START 参数是?
kgdb00
2022-01-26 23:15:04 +08:00
@yanqiyu 我用的是 fedora35 默认的内核,CONFIG_PHYSICAL_ALIGN 和 CONFIG_PHYSICAL_START 都是 0x1000000 ,0x1000000 是第 17 个 MB 开始的地方,和《 Understanding the LINUX KERNEL 》这本书描述的不一样,我发现 2.6.23 版本的 linux 的 arch/i386/defconfig 这个文件确实定义了 CONFIG_PHYSICAL_START=0x100000 ,应该是后面的版本将这个值改大了。

另外我发现我的物理机的 kernel 的起始地址是 0x2000000 是因为使用 uefi 启动导致的,不知道为什么 uefi 启动会让内核的启起始地址从 0x1000000 变成 0x2000000 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/830453

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX