C 从PLT跳变时的SEG故障
我试图找到segfault的原因,并使用gdb的btrace将其缩小到PLT。SEGFULT发生在从PLT跳转到GOT的过程中,我将其解释为表示PLT在执行过程中损坏。根据下面的分析,这种解释正确吗?PLT腐败的罪魁祸首可能是什么?堆栈溢出?我相信在GET地址上安装监视点在这种情况下可能会有所帮助。C 从PLT跳变时的SEG故障,c,debugging,segmentation-fault,got,C,Debugging,Segmentation Fault,Got,我试图找到segfault的原因,并使用gdb的btrace将其缩小到PLT。SEGFULT发生在从PLT跳转到GOT的过程中,我将其解释为表示PLT在执行过程中损坏。根据下面的分析,这种解释正确吗?PLT腐败的罪魁祸首可能是什么?堆栈溢出?我相信在GET地址上安装监视点在这种情况下可能会有所帮助。watch-l0x5562f048是正确的方法吗?其他调试的想法是受欢迎的 对于上下文,segfault在调用函数foo中的strlen时发生: int foo(char * path, ...)
watch-l0x5562f048
是正确的方法吗?其他调试的想法是受欢迎的
对于上下文,segfault在调用函数
foo
中的strlen
时发生:
int foo(char * path, ...) {
...
if (strlen(path) >= PATH_MAX) {
相应的装配线为:
0x58114 <foo+212> cmpq $0x0,-0x4c8(%rbp)
0x5811c <foo+220> jne 0x5812a <foo+234>
0x5811e <foo+222> lea 0xb96fb(%rip),%rdi # 0x111820
0x58125 <foo+229> callq 0x376c0 <__ubsan_handle_nonnull_arg@plt>
0x5812a <foo+234> mov -0x4c8(%rbp),%rax
0x58131 <foo+241> mov %rax,%rdi
0x58134 <foo+244> callq 0x37090 <strlen@plt>
在这里,我们看到
path
不是空的,因此程序跳到
,并为strlen
调用设置(mov
,mov
,callq
)。最后执行的指令是jmpq*0xa3fb2(%rip)
到GOT(strlen@got.plt
),因此程序崩溃,gdb失去上下文(报告称它无法找到当前函数的边界)。“什么可能是PLT损坏的罪魁祸首”。代码中的错误。但是,如果没有看到您的代码,就不可能说得更多。无论如何,请展示您尝试的调试和分析,但您还需要显示代码。你的分析可能是对的,但也可能是完全错误的。但是我们不能在没有测试的情况下验证任何一种方法。@kaylum:这当然是一个bug,但我想知道是否特定类型的bug更可能被关联起来。不幸的是,它的代码库太大,无法生成最小的工作示例,尽管我同意这对查找源代码非常有益。jmpq*0xa3fb2(%rip)
读取地址rip+0xa3fb2
处的指针,然后跳到它读取的指针。在GDB中,在执行jmpq
之前,您应该x/gx$rip+0xa3fb2
,并检查它是否实际上是指向任何正常对象的指针;我不知道哪一个有毛病。如果总是相同的函数分段错误,则只需监视一个GET;为此,您需要中断函数,到达此strlen
调用,进入jmpq
,然后awatch ADDR
,其中ADDR
是jmpq
读取的指针的源(这可以从程序执行更改为程序执行!)。另一种尝试是使用链接器标志-z relro
重新编译所有代码,该标志将重新定位标记为只读。如果有任何东西正在损坏它们,它将立即崩溃。@user001正确,应该是这样的,因为重新定位在启动时设置一次,然后由动态加载程序通过使该内存区域只读而冻结。“什么可能是PLT损坏的罪魁祸首”。代码中的错误。但是,如果没有看到您的代码,就不可能说得更多。无论如何,请展示您尝试的调试和分析,但您还需要显示代码。你的分析可能是对的,但也可能是完全错误的。但是我们不能在没有测试的情况下验证任何一种方法。@kaylum:这当然是一个bug,但我想知道是否特定类型的bug更可能被关联起来。不幸的是,它的代码库太大,无法生成最小的工作示例,尽管我同意这对查找源代码非常有益。jmpq*0xa3fb2(%rip)
读取地址rip+0xa3fb2
处的指针,然后跳到它读取的指针。在GDB中,在执行jmpq
之前,您应该x/gx$rip+0xa3fb2
,并检查它是否实际上是指向任何正常对象的指针;我不知道哪一个有毛病。如果总是相同的函数分段错误,则只需监视一个GET;为此,您需要中断函数,到达此strlen
调用,进入jmpq
,然后awatch ADDR
,其中ADDR
是jmpq
读取的指针的源(这可以从程序执行更改为程序执行!)。另一种尝试是使用链接器标志-z relro
重新编译所有代码,该标志将重新定位标记为只读。如果有任何东西正在损坏它们,它将立即崩溃。@user001正确,应该是这样,因为重新定位在启动时设置一次,然后由动态加载程序通过使该内存区域为只读而冻结。
(gdb) record btrace
(gdb) c
136 0x00005555555ac114 <foo+212>: cmpq $0x0,-0x4c8(%rbp)
137 0x00005555555ac11c <foo+220>: jne 0x5555555ac12a <foo+234>
138 0x00005555555ac12a <foo+234>: mov -0x4c8(%rbp),%rax
139 0x00005555555ac131 <foo+241>: mov %rax,%rdi
140 0x00005555555ac134 <foo+244>: callq 0x55555558b090 <strlen@plt>
141 0x000055555558b090 <strlen@plt+0>: jmpq *0xa3fb2(%rip) # 0x55555562f048 <strlen@got.plt>