C 从PLT跳变时的SEG故障

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, ...)

我试图找到segfault的原因,并使用gdb的btrace将其缩小到PLT。SEGFULT发生在从PLT跳转到GOT的过程中,我将其解释为表示PLT在执行过程中损坏。根据下面的分析,这种解释正确吗?PLT腐败的罪魁祸首可能是什么?堆栈溢出?我相信在GET地址上安装监视点在这种情况下可能会有所帮助。
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>