首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Memcpy使用有效指针进行分段故障

Memcpy使用有效指针进行分段故障
EN

Stack Overflow用户
提问于 2011-07-28 23:40:10
回答 2查看 4.5K关注 0票数 1

我在我的程序中使用了libcurl,并且遇到了一个段错误。在我向curl项目提交bug之前,我想我应该做一点调试。我发现的东西对我来说非常奇怪,我还不能理解它。

首先,段故障回溯:

代码语言:javascript
复制
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffe77f6700 (LWP 592)]
0x00007ffff6a2ea5c in memcpy () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0  0x00007ffff6a2ea5c in memcpy () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff5bc29e5 in x509_name_oneline (a=0x7fffe3d9c3c0,
    buf=0x7fffe77f4ec0 "C=US; O=The Go Daddy Group, Inc.; OU=Go Daddy Class 2 Certification Authority\375\034<M_r\206\233\261\310\340\371\023.Jg\205\244\304\325\347\372\016#9Ph%", size=255) at ssluse.c:629
#2  0x00007ffff5bc2a6f in cert_verify_callback (ok=1, ctx=0x7fffe77f50b0)
    at ssluse.c:645
#3  0x00007ffff72c9a80 in ?? () from /lib/libcrypto.so.0.9.8
#4  0x00007ffff72ca430 in X509_verify_cert () from /lib/libcrypto.so.0.9.8
#5  0x00007ffff759af58 in ssl_verify_cert_chain () from /lib/libssl.so.0.9.8
#6  0x00007ffff75809f3 in ssl3_get_server_certificate ()
   from /lib/libssl.so.0.9.8
#7  0x00007ffff7583e50 in ssl3_connect () from /lib/libssl.so.0.9.8
#8  0x00007ffff5bc48f0 in ossl_connect_step2 (conn=0x7fffe315e9a8, sockindex=0)
    at ssluse.c:1724
#9  0x00007ffff5bc700f in ossl_connect_common (conn=0x7fffe315e9a8,
    sockindex=0, nonblocking=false, done=0x7fffe77f543f) at ssluse.c:2498
#10 0x00007ffff5bc7172 in Curl_ossl_connect (conn=0x7fffe315e9a8, sockindex=0)
    at ssluse.c:2544
#11 0x00007ffff5ba76b9 in Curl_ssl_connect (conn=0x7fffe315e9a8, sockindex=0)
...

对memcpy的调用如下所示:

代码语言:javascript
复制
  memcpy(buf, biomem->data, size);
(gdb) p buf
$46 = 0x7fffe77f4ec0 "C=US; O=The Go Daddy Group, Inc.; OU=Go Daddy Class 2 Certification Authority\375\034<M_r\206\233\261\310\340\371\023.Jg\205\244\304\325\347\372\016#9Ph%"
(gdb) p biomem->data
$47 = 0x7fffe3e1ef60 "C=US; O=The Go Daddy Group, Inc.; OU=Go Daddy Class 2 Certification Authority\375\034<M_r\206\233\261\310\340\371\023.Jg\205\244\304\325\347\372\016#9Ph%"
(gdb) p size
$48 = 255

如果我向上一帧,我看到为buf传入的指针来自调用函数中定义的一个局部变量:

代码语言:javascript
复制
char buf[256];

这就是它开始变得奇怪的地方。我可以手动检查所有256字节的buf和biomem->数据,而不会出现gdb报告内存不可访问的情况。我还可以使用gdb set命令手动写入全部256字节的buf,没有任何错误。那么,如果涉及到的所有内存都是可读和可写的,为什么memcpy会失败?

同样有趣的是,我可以使用gdb手动调用包含指针的memcpy。只要我传递一个大小为<= 160的参数,它就可以正常运行。只要我超过161或更高的值,gdb就会得到sigsegv。我知道buf大于160,因为它是在堆栈上作为256数组创建的。biomem->data比较难理解,但是我可以用gdb读取超过160字节的内容。

我还应该提到,这个函数(或者更确切地说,是我调用的curl方法)在崩溃之前多次成功完成。我的程序在运行时使用curl重复调用web服务API。它大约每五秒钟调用一次API,并在崩溃之前运行大约14个小时。可能是我的应用程序中的其他东西写出了越界,并践踏了一些造成错误条件的东西。但它似乎很可疑,它每次都在完全相同的点崩溃,尽管时间不同。在gdb中所有的指针看起来都没问题,但是memcpy仍然失败。Valgrind没有发现任何边界错误,但我已经14个小时没有让我的程序使用valgrind运行了。

在memcpy本身中,反汇编过程如下所示:

代码语言:javascript
复制
(gdb) x/20i $rip-10
   0x7ffff6a2ea52 <memcpy+242>: jbe    0x7ffff6a2ea74 <memcpy+276>
   0x7ffff6a2ea54 <memcpy+244>: lea    0x20(%rdi),%rdi
   0x7ffff6a2ea58 <memcpy+248>: je     0x7ffff6a2ea90 <memcpy+304>
   0x7ffff6a2ea5a <memcpy+250>: dec    %ecx
=> 0x7ffff6a2ea5c <memcpy+252>: mov    (%rsi),%rax
   0x7ffff6a2ea5f <memcpy+255>: mov    0x8(%rsi),%r8
   0x7ffff6a2ea63 <memcpy+259>: mov    0x10(%rsi),%r9
   0x7ffff6a2ea67 <memcpy+263>: mov    0x18(%rsi),%r10
   0x7ffff6a2ea6b <memcpy+267>: mov    %rax,(%rdi)
   0x7ffff6a2ea6e <memcpy+270>: mov    %r8,0x8(%rdi)
   0x7ffff6a2ea72 <memcpy+274>: mov    %r9,0x10(%rdi)
   0x7ffff6a2ea76 <memcpy+278>: mov    %r10,0x18(%rdi)
   0x7ffff6a2ea7a <memcpy+282>: lea    0x20(%rsi),%rsi
   0x7ffff6a2ea7e <memcpy+286>: lea    0x20(%rdi),%rdi
   0x7ffff6a2ea82 <memcpy+290>: jne    0x7ffff6a2ea30 <memcpy+208>
   0x7ffff6a2ea84 <memcpy+292>: data32 data32 nopw %cs:0x0(%rax,%rax,1)
   0x7ffff6a2ea90 <memcpy+304>: and    $0x1f,%edx
   0x7ffff6a2ea93 <memcpy+307>: mov    -0x8(%rsp),%rax
   0x7ffff6a2ea98 <memcpy+312>: jne    0x7ffff6a2e969 <memcpy+9>
   0x7ffff6a2ea9e <memcpy+318>: repz retq
(gdb) info registers
rax            0x0      0
rbx            0x7fffe77f50b0   140737077268656
rcx            0x1      1
rdx            0xff     255
rsi            0x7fffe3e1f000   140737016623104
rdi            0x7fffe77f4f60   140737077268320
rbp            0x7fffe77f4e90   0x7fffe77f4e90
rsp            0x7fffe77f4e48   0x7fffe77f4e48
r8             0x11     17
r9             0x10     16
r10            0x1      1
r11            0x7ffff6a28f7a   140737331236730
r12            0x7fffe3dde490   140737016358032
r13            0x7ffff5bc2a0c   140737316137484
r14            0x7fffe3d69b50   140737015880528
r15            0x0      0
rip            0x7ffff6a2ea5c   0x7ffff6a2ea5c <memcpy+252>
eflags         0x10203  [ CF IF RF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) p/x $rsi
$50 = 0x7fffe3e1f000
(gdb) x/20x $rsi
0x7fffe3e1f000: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffe3e1f010: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffe3e1f020: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffe3e1f030: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffe3e1f040: 0x00000000      0x00000000      0x00000000      0x00000000

我使用的是libcurl版本7.21.6、c-are版本1.7.4和openssl版本1.0.0d。我的程序是多线程的,但我已经向openssl注册了互斥回调。该程序在64位的Ubuntu 11.04桌面上运行。libc为2.13。

EN

回答 2

Stack Overflow用户

发布于 2011-07-31 12:23:33

显然,libcurl正在过度读取源缓冲区,并进入不可读的内存(参见0x7fffe3e1f000 --您可以通过查看正在调试的程序的/proc/<pid>/maps来确认内存是不可读的)。

这就是它开始变得奇怪的地方。我可以手动检查所有256个字节的

buf和biomem->data,没有gdb抱怨内存不可访问。

有一个众所周知的Linux内核缺陷:即使对于具有PROT_NONE的内存(并导致SIGSEGV尝试从进程本身读取它),GDBptrace(PEEK_DATA,...)的尝试也会成功。这就解释了为什么您可以在GDB中检查256个字节的源缓冲区,即使其中只有96个字节是实际可访问的。

试着在Valgrind下运行你的程序,它很可能会告诉你memcpy到堆分配的缓冲区太小了。

票数 4
EN

Stack Overflow用户

发布于 2011-07-28 23:56:26

你有没有可能创建一个“褶皱区域”?

也就是说,故意增加两个缓冲区的大小,或者在结构的情况下将额外的未使用的元素放在目的地之后?

然后,你用诸如"0xDEADBEEF“之类的东西来播种源crumple,用一些好的东西来播种目的地。如果目的地每次都发生变化,你就有了可以使用的东西。

256有点暗示,有没有可能会被视为有符号的数量,变成-1,因此非常大?我不明白为什么gdb不会显示它,但是...

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6861724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档