60 关于 SegmentFault 的一些场景 (1)

前言

呵呵 此问题主要是来自于 帖子 月经结贴 -- 《Segmentation Fault in Linux》

这里主要也是 结合了作者的相关 case, 来做的一些 调试分享 

当然 很多的情况还是 蛮有意思 

 

本文主要问题如下 

1. 访问可执行文件中的 只读数据
2. 访问不存在的虚拟地址
3. 访问内核地址
4. 访问空指针
5. 访问异常堆地址1
6. 访问异常堆地址2
7. 访问异常堆地址3

 

 

1. 访问可执行文件中的 只读数据

比如如下数据, “Hello World” 会被放到 .text 段, 该段只读, 这里程序中试图更新该内存的数据 

#include <stdio.h>
#include <stdlib.h>int main() {char* s = "Hello World";s[1] = 'x';}

 

调试上下文如下 

page fault 的时候 ip 为 4195562 = 0x4004EA

error_code 为 7, PF_PROT | PF_WRITE | PF_USER

40dbcff97a0f44afa8f0bd3f6d18dba0.png

 

0x4004EA 对应的信息如下, 是一段执行代码 

07a7943c31f747159db10eed73f75a78.png

 

对应于 main 中的 如下代码, 映射到业务源代码就是 “s[1] = 'x';”

c7e70030529041989f609294980eee75.png

 

校验的时候 期望写操作, 但是实际 不支持写操作 

d032a0c5c1ed42e69c18b0f2840890a9.png

 

接下来就是 输出内核日志信息, 以及向目标进程发送 SIGSEGV 信号  1e23f599874c40c9afbc89f4881336c8.png

 

输出内核日志信息如下

日志中输出了 进程名称, 进程编号, 访问的地址, 指令寄存器, 栈顶寄存器, 错误编码 等等信息

3f493281ead14310b536c4f7ca1f382c.png

 

出现问题的异常代码为 0x4004ea, 栈顶寄存器的值为 0x7ffdc7c9b1f0

错误编码为 7 表示 PF_PROT | PF_WRITE | PF_USER

(initramfs) ./Test16SigSegvAccessConstants

[  207.776273] Test16SigSegvAc[258]: segfault at 400585 ip 00000000004004ea sp 00007ffdc7c9b1f0 error 7 in Test16SigSegvAccessConstants[400000+1000]

 

0x400585 为 .rodata 中 

d8b772dc60aa4ba494510dbc0a431816.png

 

0x4004ea 为 main 中执行出现异常的代码段 

f0d040600ba04069b94d20ed14c9c827.png

 

 

2. 访问不存在的虚拟地址  

#include <stdio.h>
#include <stdlib.h>int main() {int *p = (int *) 0x7ffff7a8e58f;*p = 10;}

 

这个是根据 address 查询虚拟地址, 查询不到

直接走的 bad_area, 输出日志信息, 发送 SIGSEGV 给目标进程 

f36e05480c2f460aac5dbda97010e9de.png

 

报错日志信息为 

(initramfs) ./Test16SigSegvAccessUnknownAddr

[ 7575.969176] Test16SigSegvAc[262]: segfault at 7ffff7a8e58f ip 00000000004004ec sp 00007fffd34e74d0 error 6 in Test16SigSegvAccessUnknownAddr [400000+1000]

 

出现问题的进程为 262号进程, 异常访问的地址为 0x 7ffff7a8e58f

出现问题的异常代码为 0x4004ec, 栈顶寄存器的值为 0x 7fffd34e74d0

错误编码为 6 表示 PF_WRITE | PF_USER

 

0x7ffff7a8e58f 为 main 中定义的需要访问的异常地址 

 

0x4004ec 为 main 中执行出现异常的代码段 

f053ec239aba4f6d904db8e3c0e72d17.png

 

 

3. 访问内核地址

#include <stdio.h>
#include <stdlib.h>int main() {int *p = (int *) 0xffff88007fb89a80;*p = 10;}

 

如果是访问内核空间的地址

如果是普通用户程序访问, 直接发送 SIGSEGV 信号量 

91b8ed9a19e5415b970a81ff5a744042.png

 

报错日志信息为 

(initramfs) ./Test16SigSegvAccessKernelAddr

[ 1014.007466] Test16SigSegvAc[259]: segfault at ffff88007fb89a80 ip 00000000004004ec sp 00007fffc027d130 error 7 in Test16SigSegvAccessKernelAddr[400000+1000]

 

出现问题的进程为 259号进程, 异常访问的地址为 0x ffff88007fb89a80

出现问题的异常代码为 0x4004ec, 栈顶寄存器的值为 0x 7fffc027d130

错误编码为 7 表示 PF_PROT | PF_WRITE | PF_USER

 

0x ffff88007fb89a80 为 main 中定义的需要访问的异常地址 

 

0x4004ec 为 main 中执行出现异常的代码段 

6d525d21e10944b8a1acf3bab804cdb8.png

 

 

4. 访问空指针

#include <stdio.h>
#include <stdlib.h>int main() {int *p = NULL;*p = 10;}

 

这个是根据 address 查询虚拟地址, 查询不到

直接走的 bad_area, 输出日志信息, 发送 SIGSEGV 给目标进程 

d3cee4862dc448fa908a580c86f9cb7f.png

 

 

报错日志信息为 

(initramfs) ./Test16SigSegvAccessNpe

[ 9696.656307] Test16SigSegvAc[264]: segfault at 0 ip 00000000004004e6 sp 00007fffd2d459c0 error 6 in Test16SigSegvAccessNpe[400000+1000]

 

出现问题的进程为 264号进程, 异常访问的地址为 0x 0

出现问题的异常代码为 0x4004e6, 栈顶寄存器的值为 0x 7fffd2d459c0

错误编码为 6 表示 PF_WRITE | PF_USER

 

0x0 为 main 中定义的需要访问的异常地址 

 

0x4004e6 为 main 中执行出现异常的代码段 

39ceb0c272dd4146ae020ba38d09b442.png

 

 

5. 访问异常堆地址1

这里调整了一下 原文档中的测试用例, 源文档中作者的理解应该是存在问题 

所以 当我看到 overflow 15k 的时候很奇怪, 源文档中每次增量是 0k, 1k, 2k, 3k, …, 15k

但是 按照原作者的期望应该每次 增量是 1k, 这里我们稍微 调整了一下 测试用例

然后 原作者文档中提到当初次分配16M的时候, SISSEGV 延迟到了 180k, 这个 按道理来说作者的理解应该也是存在问题, 初次分配 16M的时候 malloc 分配的虚拟地址是在 mmap 映射区 这两种情况 得分开讨论

#include <stdio.h>
#include <stdlib.h>#define K 1024
int main () {char* c;int i = 0;c = malloc (1);while (1) {char* off = c + i*K;*off = 'a';printf ("overflow %dK\n", i);i ++;}
}

 

按照我们对于 malloc 的理解, 程序开始的时候 malloc 分配的 chunk 会在 132kb 左右 

这里 malloc(1) 会暂用 32byte, printf 会占用 1kb 左右 

然后 第一个循环中 操作的是 c 所在的内存空间, 第二个循环 操作的是 printf 的缓冲区 

到后面 132kb 末尾, 每 4kb 会有一个缺页中断, 操作的是对应的偏移的空间 

超过 132kb 之后, 会因为找不到 vma, 而发生 SIGSEGV

 

 

6. 访问异常堆地址2

#include <stdio.h>
#include <stdlib.h>#define K 1024
int main () {int* a;a = malloc (sizeof(int));*a = 100;printf ("0x%x\n", a);printf ("%d\n", *a);free (a);printf ("%d\n", *a);
}

 

这个测试用例不会报错很正常 

因为 malloc, free 维护的空间, 不管 free 之前还是在之后, 其申请的虚拟地址空间 都属于当前进程

malloc(sizeof(int)) 会申请 132kb 的空间 

然后 a 对应的地址会为 0x602010, 然后 这块地址 可读可写

不会 出现 SIGSEGV 

这里 page_fault 产生的 address 为 0x602008 是因为是在 malloc 的过程中设置这块空间的头部信息, 这里会走正常的缺页中断 

fa7a0970a58a4400b984e0fd09caf33f.png

 

这里 走正常的缺页中断处理

第二次访问的时候, 地址合法, 并且 虚拟内存对应的物理内存已经加载 

ce234a8efadf488db1f7ba49f696c239.png

 

我们大致看一下这个过程中 glibc 的 free 的相关处理 

这里两次输出之所以 第二次值为 0, 是因为 free 的时候需要在 chunkptr 中维护空闲链表信息

这里是当前区域的 第一块空闲区域, 更新 p->forward 为 NULL, 值为 0

d2db6bc61d7246d8993521cf183200bd.png

 

调整一下代码, 我们从程序上面简单的验证一下 这里的 forward 的处理 

#include <stdio.h>
#include <stdlib.h>#define K 1024
int main () {int* a = malloc (sizeof(int));int* b = malloc (sizeof(int));*a = 100;printf ("0x%x\n", a);printf ("%d\n", *a);free (a);printf ("%d\n", *a);*b = 100;printf ("0x%x\n", b);printf ("%d\n", *b);free (b);printf ("%d\n", *b);}

 

b 对应的 chunkptr->fd[等价于b的数据空间] 为 6299648 为 0x602000, 记录的是前一块 空闲的chunkptr 的地址

a 对应的 chunkptr->fd[等价于a的数据空间] 为 0 为 NULL, 记录的是前一块空闲的 chunkptr 的地址

root@ubuntu:~/Desktop/linux/HelloWorld# ./Test16SigSegvAccessInvalidHeapAddr02
0x602010
100
0
0x602030
100
6299648

 

 

7. 访问异常堆地址3

这个主要是在 glibc 层面的限制, 处理 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>void foo () {char c;memset (&c, 0x55, 128);
}int main () {foo();
}

 

日志输出如下

8038f369d6894bb7bcc7ba647245a20a.png

 

在 glibc 层面处理如下, 输出了如上 日志信息, 然后向给定的进程 发送了 SIGABRT 信号  839bfcee47974c0cbfa7fbd120aa091c.png

 

内核这边 调试收到 SIG_ABRT 的信号的地方如下 

f6b42efa2b174b65b00c853921bd73ad.png

 

foo 编译结果如下 

b8ffa0c5636f4b92913f2d3ff9d45c00.png

 

 gdb 调试这个过程如下 

Reading symbols from Test16SigSegvAccessInvalidHeapAddr03...
(gdb) list
1
2       #include <stdio.h>
3       #include <stdlib.h>
4       #include <string.h>
5
6       void foo () {
7               char c;
8
9               memset (&c, 0x55, 128);
10      }
(gdb) b Test16SigSegvAccessInvalidHeapAddr03.c:9
Breakpoint 1 at 0x4005ad: file Test16SigSegvAccessInvalidHeapAddr03.c, line 9.
(gdb) run
Starting program: /root/linux/tmp/Test16SigSegvAccessInvalidHeapAddr03Breakpoint 1, foo () at Test16SigSegvAccessInvalidHeapAddr03.c:9
9               memset (&c, 0x55, 128);
(gdb) disassemble
Dump of assembler code for function foo:0x0000000000400596 <+0>:     push   %rbp0x0000000000400597 <+1>:     mov    %rsp,%rbp0x000000000040059a <+4>:     sub    $0x10,%rsp0x000000000040059e <+8>:     mov    %fs:0x28,%rax0x00000000004005a7 <+17>:    mov    %rax,-0x8(%rbp)0x00000000004005ab <+21>:    xor    %eax,%eax
=> 0x00000000004005ad <+23>:    lea    -0x9(%rbp),%rax0x00000000004005b1 <+27>:    mov    $0x80,%edx0x00000000004005b6 <+32>:    mov    $0x55,%esi0x00000000004005bb <+37>:    mov    %rax,%rdi0x00000000004005be <+40>:    call   0x400470 <memset@plt>0x00000000004005c3 <+45>:    nop0x00000000004005c4 <+46>:    mov    -0x8(%rbp),%rax0x00000000004005c8 <+50>:    xor    %fs:0x28,%rax0x00000000004005d1 <+59>:    je     0x4005d8 <foo+66>0x00000000004005d3 <+61>:    call   0x400460 <__stack_chk_fail@plt>0x00000000004005d8 <+66>:    leave0x00000000004005d9 <+67>:    ret
End of assembler dump.
(gdb) stepi
0x00000000004005b1      9               memset (&c, 0x55, 128);
(gdb) stepi
0x00000000004005b6      9               memset (&c, 0x55, 128);
(gdb) stepi
0x00000000004005bb      9               memset (&c, 0x55, 128);
(gdb) stepi
0x00000000004005be      9               memset (&c, 0x55, 128);
(gdb) stepi
0x0000000000400470 in memset@plt ()
(gdb) step
Single stepping until exit from function memset@plt,
which has no line number information.
foo () at Test16SigSegvAccessInvalidHeapAddr03.c:10
10      }
(gdb) stepi
0x00000000004005c4      10      }
(gdb) stepi
0x00000000004005c8      10      }
(gdb) stepi
0x00000000004005d1      10      }
(gdb) stepi
0x00000000004005d3      10      }
(gdb) disassemble
Dump of assembler code for function foo:0x0000000000400596 <+0>:     push   %rbp0x0000000000400597 <+1>:     mov    %rsp,%rbp0x000000000040059a <+4>:     sub    $0x10,%rsp0x000000000040059e <+8>:     mov    %fs:0x28,%rax0x00000000004005a7 <+17>:    mov    %rax,-0x8(%rbp)0x00000000004005ab <+21>:    xor    %eax,%eax0x00000000004005ad <+23>:    lea    -0x9(%rbp),%rax0x00000000004005b1 <+27>:    mov    $0x80,%edx0x00000000004005b6 <+32>:    mov    $0x55,%esi0x00000000004005bb <+37>:    mov    %rax,%rdi0x00000000004005be <+40>:    call   0x400470 <memset@plt>0x00000000004005c3 <+45>:    nop0x00000000004005c4 <+46>:    mov    -0x8(%rbp),%rax0x00000000004005c8 <+50>:    xor    %fs:0x28,%rax0x00000000004005d1 <+59>:    je     0x4005d8 <foo+66>
=> 0x00000000004005d3 <+61>:    call   0x400460 <__stack_chk_fail@plt>0x00000000004005d8 <+66>:    leave0x00000000004005d9 <+67>:    ret
End of assembler dump.

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/21093.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式工程师人生提质的十大成长型思维分享

大家好,作为一名嵌入式开发者,很多时候,需要考虑个人未来的发展,人生旅途复杂多变,时常面临各种各样的挑战。如何在这个复杂多变的社会中稳步向前,不断成长,成为每个人都应该思考的问题。实际上,思维方式的差异决定我们应对挑战的能力与成长的速度。 第一:寻找自我坐…

HNCTF2022 REVERSE

[HNCTF 2022 WEEK2]esy_flower 简单花指令 Nop掉 然后整段u c p然后就反汇编 可能反编译的不太对&#xff0c;&#xff0c;看了别人的wp就是ida反编译的有问题 #include<stdio.h> #include<string.h> int main() {int i,j;char ch[]"c~scvdzKCEoDEZ[^roDICU…

微软远程连接工具:Microsoft Remote Desktop for Mac 中文版

Microsoft Remote Desktop 是一款由微软开发的远程桌面连接软件&#xff0c;它允许用户从远程地点连接到远程计算机或虚拟机&#xff0c;并在远程计算机上使用桌面应用程序和文件。 下载地址&#xff1a;https://www.macz.com/mac/5458.html?idOTI2NjQ5Jl8mMjcuMTg2LjEyNi4yMz…

C++进阶之AVL树+模拟实现

目录 目录 一、AVL树的基本概念 1.1 基本概念 二、AVL树的模拟实现 2.1 AVL树节点的定义 2.2 插入操作 2.3 旋转操作 2.4 具体实现 一、AVL树的基本概念 1.1 基本概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十四)- 微服务(4)

目录 8. http客户端Feign 8.1 feign远程调用 8.2 feign自定义配置 8.3 feign性能优化 8.4 feign最佳实践 8. http客户端Feign 8.1 feign远程调用 RestTemplate存在的问题 &#xff1a; 代码可读性差 参数复杂URL难以维护 Feign是声明式的http客户端 使用步骤 &#xf…

飞书API(11):阿里云MaxCompute分区表入库

一、引入 前面入库阿里云 MaxCompute 的数据都是读取之后直接写入&#xff0c;保留数据最新的状态&#xff0c;如果我要保留历史的状态&#xff0c;怎么办呢&#xff1f;MaxCompute 表有一个分区功能&#xff0c;可以自行定义分区。我们可以使用 MaxCompute 表的分区功能&…

远程自动锁定平面

目录 Ubuntu 系统上 方法一&#xff1a;使用 SSH 重新连接 方法二&#xff1a;解锁当前会话 方法三&#xff1a;通过 SSH 解锁会话 方法四&#xff1a;禁用自动锁屏&#xff08;如果合适&#xff09; windows系统 方法三&#xff1a;修改组策略设置 Ubuntu 系统上 远程…

重生之我要精通JAVA--第七周笔记

文章目录 IO流字符流字符流原理解析flush和close方法 文件拷贝代码文件加密解密修改文件中的数据 缓冲流字节缓冲流字符缓冲流例题 转换流序列化流序列化流/对象操作输出流 反序列化流序列化流/反序列化流的细节汇总打印流字节打印流字符打印流 解压缩流压缩流Commons-io常见方…

网络空间安全数学基础·环

4.1 环与子环 &#xff08;理解&#xff09; 4.2 整环、除环、域 &#xff08;熟练&#xff09; 4.3 环的同态、理想 &#xff08;掌握&#xff09; 4.1 环与子环 定义&#xff1a;设R是一非空集合&#xff0c;在R上定义了加法和乘法两种代数运算&#xff0c; 分别记为ab和a…

java收徒、java面试辅导、java辅导、java就业辅导

&#x1f497;博主介绍&#xff1a;✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还…

MMPose-RTMO推理详解及部署实现(下)

目录 前言一、RTMO推理(Python)1. RTMO预测2. RTMO预处理3. RTMO后处理4. RTMO推理 二、RTMO推理(C)1. ONNX导出2. RTMO预处理3. RTMO后处理4. RTMO推理 三、RTMO部署1. 源码下载2. 环境配置2.1 配置CMakeLists.txt2.2 配置Makefile 3. ONNX导出4. engine生成5. 源码修改6. 运行…

HCP;IDA;ABIDE(孤独症)磁共振数据库下载

ABIDE https://fcon_1000.projects.nitrc.org/indi/abide/abide_II.html 根据研究目的和研究目的选择不同站点的数据—不同站点的数据 HCP-IDE https://ida.loni.usc.edu/project_info.jsp 点击下载-图像集合 选择研究对象 全选-下载

边缘密度分布图 | ggExtra包/aplot拼图/ggpubr包 等的实现方法

概述&#xff1a;aplot 拼图效果好 根据网友探索[1]&#xff0c;总结如下&#xff1a; ggExtra 包的拼图间隙有点大&#xff0c;图例在主图和边缘图之间&#xff0c;除非去掉图例&#xff0c;否则没法看。aplot包的默认拼图间隙很小&#xff0c;比较美观&#xff0c;图例在外…

Cyber Weekly #9

赛博新闻 1、OpenAI&#xff1a;GPTs向全部用户开放&#xff0c;使用GPT-4o OpenAI宣布所有ChatGPT免费用户现在可以在GPT商店中使用GPTs&#xff0c;并且这些GPTs现在使用最新的GPT-4o模型。 2、马斯克 vs. Yann LeCun 这一周&#xff0c;AI圈最热闹的莫过于马斯克和LeCun的…

深入解析智慧互联网医院系统源码:医院小程序开发的架构到实现

本篇文章&#xff0c;小编将深入解析智慧互联网医院系统的源码&#xff0c;重点探讨医院小程序开发的架构和实现&#xff0c;旨在为相关开发人员提供指导和参考。 一、架构设计 智慧互联网医院系统的架构设计是整个开发过程的核心&#xff0c;直接影响到系统的性能、扩展性和维…

ZCU102启动镜像(详细版)

ZCU102启动镜像--详细版本 详细步骤1、安装好Vitis&#xff08;GUI界面&#xff09;、 Vivado、 Petalinux软件然后vivado这边的操作就先结束了 创建Petalinux工程编译镜像打包 详细步骤 B站参考视频链接: link 1、安装好Vitis&#xff08;GUI界面&#xff09;、 Vivado、 Pe…

Nocobase快速上手 - 开发第一个插件

在前面的几篇博文中&#xff0c;记录了在Nocobase中配置collection和界面&#xff0c;这篇文章开始插件的开发。插件可以扩展Nocobase的业务能力&#xff0c;解锁更强大的功能。 环境搭建 创建插件需要配置nocobase的开发环境&#xff0c;笔者采用的是clone 官方代码repo的方…

使用python下载股票数据至sqlite数据库

代码下载地址&#xff1a; https://download.csdn.net/download/weixin_44600457/89389489

2024四川三支一扶“考生信息表”照着填❗

2024四川三支一扶“考生信息表”照着填❗ ☑️四川三支一扶开始报名&#xff0c;大家要按照提示如实、准确、完整填写《高校毕业生“三支一扶”计划招募考生信息表》哦~ ☑️不知道怎么填写的宝子们&#xff0c;可以参考图1。 ☑️毕业证书编号如实填写&#xff0c;若是应届生&…

【JavaEE进阶】——MyBatis操作数据库 (#{}与${} 以及 动态SQL)

目录 &#x1f6a9;#{}和${} &#x1f388;#{} 和 ${}区别 &#x1f388;${}使用场景 &#x1f4dd;排序功能 &#x1f4dd;like 查询 &#x1f6a9;数据库连接池 &#x1f388;数据库连接池使⽤ &#x1f6a9;MySQL开发企业规范 &#x1f6a9;动态sql &#x1f388…