V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
kgdb00
V2EX  ›  Linux

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

  •  
  •   kgdb00 · 2022-01-25 11:44:09 +08:00 · 2377 次点击
    这是一个创建于 1037 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这个文件记录的函数地址不可能是物理地址,因为数值非常大,比如这一行:

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

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

    这个地址是分页前的线性地址吗?如果是的话,那我怎么知道这个函数实际运行过程中的物理地址?
    12 条回复    2022-01-26 23:15:04 +08:00
    2i2Re2PLMaDnghL
        1
    2i2Re2PLMaDnghL  
       2022-01-25 12:58:06 +08:00   ❤️ 1
    首先物理地址应该是只有内核态下才能知道,每次冷启动都会导致内存随机化分布,内核的代码实际存在的位置是随机的,缓解缓冲区溢出覆盖代码区导致的影响(攻击者无法知道溢出之后覆盖到哪个函数那儿去)
    kgdb00
        2
    kgdb00  
    OP
       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
        3
    kgdb00  
    OP
       2022-01-25 13:14:45 +08:00
    @kgdb00 #2 更正:一个页框 -> 一组页框
    yanqiyu
        4
    yanqiyu  
       2022-01-26 07:49:43 +08:00 via Android   ❤️ 1
    system.map 里面是没开 kaslr 的情况下内核被装载到的虚拟地址,开了之后会变,要用 root 去 /proc/kallsyms 下面读

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

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

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

    https://github.com/torvalds/linux/blob/master/arch/x86/boot/compressed/kaslr.c
    kgdb00
        6
    kgdb00  
    OP
       2022-01-26 16:12:25 +08:00
    @yanqiyu 感谢回复
    我试了一下,关闭 kaslr 后通过查看 /proc/iomem 发现内核代码的起始地址固定是在物理内存 16MB ( qemu )或 32MB (物理机),不明白为什么不是在 2MB 。
    kgdb00
        7
    kgdb00  
    OP
       2022-01-26 17:05:30 +08:00
    @yanqiyu 顺便问一下,怎么知道内核的 stack 是在物理内存和虚拟内存的哪个位置?
    yanqiyu
        8
    yanqiyu  
       2022-01-26 20:11:16 +08:00 via Android
    @kgdb00 因为现在内核是压缩过的,bootloader 加载到 2mb 位置的东西也是一个 loader 负责初始化和解压真正的内核
    kgdb00
        9
    kgdb00  
    OP
       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
        10
    kgdb00  
    OP
       2022-01-26 21:23:27 +08:00
    @yanqiyu 更正一下我的描述,我说的 2MB 都是指从第二个 MB 开始的地址,也就是从 0x100000 开始的地址。
    yanqiyu
        11
    yanqiyu  
       2022-01-26 21:56:39 +08:00
    @kgdb00 看样子我记错了,解压出来的 image 确实是在 0x1000000 的位置的,我把这个地址和实模式部分记混了,要不看看你的内核的 CONFIG_PHYSICAL_START 参数是?
    kgdb00
        12
    kgdb00  
    OP
       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 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2900 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 15:10 · PVG 23:10 · LAX 07:10 · JFK 10:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.