【问题标题】:What is the real address of `%fs:0xfffffffffffffff8`?`%fs:0xfffffffffffffff8` 的真实地址是什么?
【发布时间】:2020-06-30 04:57:04
【问题描述】:

我想使用ebpf跟踪go程序的goid。

阅读了一些帖子和博客后,我知道%fs:0xfffffffffffffff8 指向go 的g 结构,mov %fs:0xfffffffffffffff8,%rcx 指令总是出现在go 函数的开头。

main.main为例:

func main() {
 177341   458330:   64 48 8b 0c 25 f8 ff    mov    %fs:0xfffffffffffffff8,%rcx
 177342   458337:   ff ff
 177343   458339:   48 3b 61 10             cmp    0x10(%rcx),%rsp
 177344   45833d:   76 1a                   jbe    458359 <main.main+0x29>
 177345   45833f:   48 83 ec 08             sub    $0x8,%rsp
 177346   458343:   48 89 2c 24             mov    %rbp,(%rsp)
 177347   458347:   48 8d 2c 24             lea    (%rsp),%rbp
 177348     myFunc()
 177349   45834b:   e8 10 00 00 00          callq  458360 <main.myFunc>
 177350 }

我也知道 goid 信息存储在 go 的 g 结构中。 fs寄存器的值可以通过ebpf函数的ctx参数获取。

但我不知道%fs:0xfffffffffffffff8 的真实地址是什么,因为我是汇编语言新手。谁能给我一些提示?

如果fs寄存器的值为0x88,%fs:0xfffffffffffffff8的值是多少?

【问题讨论】:

    标签: go assembly x86-64 bpf ebpf


    【解决方案1】:

    这是一个负数,所以它是 FS 基数之前的一个 qword。您需要 FS 基地址,它不是在调试器中可以看到的 FS 段寄存器中的选择器值。

    您的进程可能进行了系统调用以要求操作系统对其进行设置,或者可能在支持它的系统上的某个时刻使用了wrfsbase 指令。

    请注意,至少在 Go 之外,Linux 通常将 FS 用于线程本地存储。

    (我不确定实际找到 FS 基础的标准方法是什么;在 rdmsr 不可用的用户空间中执行此操作显然取决于操作系统;FS 和 GS 基础作为 MSR 公开,所以OSes use that 而不是实际修改 GDT 或 LDT 条目。rdfsbase 需要通过内核在支持 FSGSBASE ISA 扩展的 CPU 上的 CR4 中设置一个位来启用,所以你不能指望它工作。)

    @MargaretBloom 建议用户空间可能触发无效页面错误;大多数操作系统将错误的虚拟地址报告回用户空间。例如,在 Linux 中,SIGSEGV 具有地址。 (或者 SIGBUS,如果它是非规范的,IIRC。即不在虚拟地址空间的低 47 位或高 47 位中,而是在地址不是低 48 的符号扩展的“洞”中。)

    因此,您需要为这些信号安装信号处理程序,并尝试从位于内核空间中间的偏移量(基数为 0)或类似的地方加载。如果由于某种原因没有故障,请将虚拟地址增加 1TiB 或循环中的某些内容。通常没有 MMIO 映射到用户空间的虚拟地址空间,因此仅读取没有副作用。

    【讨论】:

    • 是否可以使用诱导页错误来查找fs 的基地址?即如果fs:x 出现故障,报告的虚拟地址为y
    • @MargaretBloom:您的意思是捕获 SIGSEGV 和 SIGBUS(在非规范 IIRC 的情况下),因为内核以这种方式将虚拟地址报告回用户空间?是的,这可以工作!我猜你想从通常内核空间中间的某个偏移量加载。
    猜你喜欢
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 2012-05-06
    • 2019-02-01
    • 1970-01-01
    相关资源
    最近更新 更多