您当前的位置:首页 > 电脑百科 > 软件技术 > 操作系统 > linux百科

Linux程序内存越界定位分析总结

时间:2022-11-03 14:55:42  来源:知乎  作者:linux服务器开发

问题描述:最近在工作中遇到这样一个奇葩问题,程序里需使用一个.so库,同份源码用我电脑编译的库放到程序使用出现各种异常问题,其他同事编译出来的没问题。刚开始以为是编译方式有问题,思来想去发现并不是。经分析发现是库源代码里一全局数组内存地址大面积越界到其他全局数组了。

问题现象:现象为触发某个业务条件,将导致程序逻辑运行不正常,异常log如下图,可看出“g_s32MaxFd”变量的值(文件句柄)被置0,正常情况应该是大于0,所以此时导致整个业务运行异常。

初步分析肯定是其他地方对变量“g_s32MaxFd”有赋值才会导致值为0。那么到底是代码正常逻辑语句操作还是代码内存越界引起“g_s32MaxFd”值为0呢?这个倒好定位,只需要搜索下“g_s32MaxFd”变量在代码哪些地方有使用就知道了,得出结论是代码内存越界这种情况导致。

一:开始定位内存越界处

【1】定位内存越界处,因程序并没有因为内存越界而引发segment fault退出,所以准备使用linux中mprotect()函数来设置指定内存区域的保护属性为只读,故意使程序引发segment fault退出从而产生core dumped文件来定位问题点。

分析下面问题前最好先熟悉下mprotect()函数

思路:使用mprotect()函数对被踩变量“g_s32MaxFd”内存地址设为只读属性,由于mprotect()函数的局限性(保护属性区域的起始地址必须为操作系统一个页大小的整数倍),结合实际情况多样性,分析情况如下表述:

1、当“g_s32MaxFd”数组起始地址刚好是页大小整数倍时,此时只需要将数组起始地址设置为mprotect()函数保护属性为只读的起始地址即可,但需要注意一点,当被保护地址区域被程序正常数据结构进行访问时,也会引发segment fault退出(简而言之就是当数组“g_s32MaxFd”内存地址被设置为只读后,如果是程序正常使用时也会引发段错误退出),这种情况就无法辨别是程序正常使用还是内存越界处使用,会影响分析真正的问题点。

解决方法:可利用GNU编译器对.bss地址分配特性(具体特性自行查阅其他资料),在“g_s32MaxFd”数组地址处定义一个为页大小整数倍大小的“g_debug_place”数组,这就相当于新增的“g_debug_place”数组占用之前“g_s32MaxFd”数组的地址。如下图所示在“Var5”和“g_s32MaxFd”之间定义一个动态数组“g_debug_place”,大小最好是页大小整数倍(如果小于一个页大小会导致锁定的区域越界到“g_s32MaxFd”地址,问题得不到解决),这样既可以保证新增的“g_debug_place”数组变量只在内存越界的地方才会被访问而且数组大小也满足mprotect()函数参数长度的取值要求(页大小整数倍)。

2、 当“g_s32MaxFd”数组起始地址不是页大小整数倍时,要结合上面第1种方法后还需要计算出大于且最靠近“g_debug_place”数组起始地址的页大小整数倍地址。可套用公式:

设置保护属性起始地址=被踩内存变量起始地址+(页大小-(被踩内存变量起始地址%页大小))
注意:(被踩内存变量起始地址%页大小)等于0时不适用以上公式,也就是被踩内存变量起始地址是页大小整数倍情况下

假设“g_debug_place”数组起始地址为0x7fd8985bf8c0代入公式可得设置保护属性起始地址为0x7fd8985c0000 ,理论上只需要将地址0x7fd8985c0000设置为mprotect()函数保护属性为只读的起始地址即可,但需要注意的是此时的0x7fd8985c0000地址并不是“g_debug_place”数组起始地址,由上面公式可知这个地址是为了满足mprotect()函数的局限性而计算出来的地址。

解决方法:可通过在.bss段(之所以强调.bss段是因为我实际出现问题的变量就是未初始化的全局数组变量)首个变量地址前增加动态数组来改变内存分配解决。举个例子,就好比是排队,本来小明是排第六个,突然在队伍最前面插一个小红进来,小明就排在第七了,而小明前面之前那五个人的顺序还是不变。而这个第七就是我们程序里要的那个0x7fd8985c0000地址。

下图蓝色区域为新增动态数组(插队小红),大小为0x740字节。增加后可使“g_debug_place”数组起始地址为0x7fd8985c0000(小明第七的位置),这时将0x7fd8985c0000地址作为mprotect()函数保护属性为只读的起始地址就可以了,接下来就可以复现问题等着程序内存越界产生段错误退出吧。

注意:如果增加动态数组后并没有直观发现内存越界时,这可能是由于内存越界的字节数太小(可能只踩到一个字节或几个字节),导致调整过后的内存地址刚好踩到一个未使用的地址,这时需要微调动态数组大小来保证地址间隔及分配顺序不变,具体问题具体分析。我是没有出现这种情况,只是觉得通过这种方法分析可能会存在此风险,如果有小伙伴遇到可以留言探讨。

bss段变量地址结构分布简要展示如下图(展示的是测试代码,非实际工程代码):

 

【2】gdb分析core文件,编译可执行程序时编译选项需加-g参数,不要strip优化,否则可能会导致调试信息不是很完整。

检查core dumped是否打开

/home # ulimit -c
0
/home # ulimit -c unlimited
/home # ulimit -c
unlimited

如果找不到ulimit命令,可以用busybox sh -c 'ulimit -a’指令测试ulimit是否存在,(ulimit是busybox的内置命令,往往我们想使用tab键快捷调用ulimit时可能不会弹出)有如下log输出证明命令存在,后续直接执行ulimit -c unlimited,不要再执行busybox sh -c ‘ulimit -c unlimited’,这样是打不开core的,我就这么傻的操作过,当时还以为内核没有打开这个功能。

/home # busybox sh -c 'ulimit -a'
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                8192
-c: core file size (blocks)        unlimited
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      1982
-n: file descriptors               1024
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0

分析core文件过程,如下图所示。当输出log信息不完整时,需要检查下源码和相关库文件路径是否设置好,可根据图片中标注处进行设置。(展示的是测试代码,非实际工程代码)

实际代码gdb分析log如下

/home/outApp/app # …/…/gdb xxx_capture core
GNU gdb (GDB) 7.6
Copyright © 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for detAIls.
This GDB was configured as “arm-hisiv300-linux”.
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/…
Reading symbols from /home/outapp/app/xxx_capture…(no debugging symbols found)…done.
[New LWP 803]
[New LWP 789]
[New LWP 798]
[New LWP 807]
[New LWP 799]
[New LWP 791]
[New LWP 832]
[New LWP 797]
[New LWP 795]
[New LWP 802]
[New LWP 809]
[New LWP 790]
[New LWP 805]
[New LWP 804]
[New LWP 808]
[New LWP 796]
[New LWP 806]
[New LWP 810]
[New LWP 831]
[New LWP 833]
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/libthread_db.so.1”.
Core was generated by `xxx_capture capture 660’.
Program terminated with signal 11, Segmentation fault.
#0 0xb5e63b54 in memset () from /lib/libc.so.0
(gdb) bt
#0 0xb5e63b54 in memset () from /lib/libc.so.0
#1 0xb6e63064 in xxx3520D_Sample_OsdRegShowUpdata (ps8Contenx=0xb1dc2a70 " 000KM/H ", pstRegAttr=0x32f9e9c)
at SdkLogic/xxx3520dSample/xxx3520dOsd.c:436
#2 0xb6e63930 in xxx3520D_Sample_OsdShowGpsSpeed (pstRegAttr=0x32f9e9c, u8Speed=0 ‘00’) at SdkLogic/xxx3520dSample/xxx3520dOsd.c:621
#3 0xb6e4dc14 in xxxSdkAl_OsdShowGpsSpeed (pstRegAttr=0x32f9e9c, u8Speed=0 ‘00’) at SdkAppInt/xxxAHDSdkAL.c:474
#4 0xb6cb7b50 in OsdServiec::Osd_Reg_Show() () from /hi3520/lib/libxxxxxx_hi3520_AHDOsd.so
#5 0xb6cb726c in xxx_Osd_Display(void*) () from /hi3520/lib/libxxxxxx_hi3520_AHDOsd.so
#6 0xb6fc0f6c in start_thread () from /lib/libpthread.so.0
#7 0xb5e82134 in clone () from /lib/libc.so.0
#8 0xb5e82134 in clone () from /lib/libc.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

小结:以上定位内存越界只是一个大体思路,实际情况多样性,具体问题还需要具体分析,个人认为如果只需要定位程序异常退出的话,用backtrace相关函数来代替gdb分析问题要轻量化很多。上述之所以使用gdb去分析问题是由于使用的交叉编译是uclibc环境(uclibc环境下backtrace函数是没实现的),就只能使用sdk提供的gdb工具了

二:为什么我电脑编译出来的库就暴露这个问题呢?

通过上面的方法已经定位到是哪行代码有bug,所以想再分析下我编译出来的库为啥就暴露这个问题了呢?分析得知是在生成.so库时由于链接.o的顺序不同导致库里面全局变量数组的地址分布也有所不同。下面分析下log文件里具体不同点,截图贴上:

qiuhui@ubuntu:/mnt/hgfs/qh/work/app/SVN/?????$ arm-hisiv300-linux-objdump -t ???/lib?????.so > log

【图一为我电脑编译的】

【图二为同事电脑编译的】

由上图可以观察到两个全局数组变量“gs_s8Contenx”与“g_s32MaxFd”它们的地址有前后顺序差异,图一:“gs_s8Contenx地址0xfd9e4”小于“g_s32MaxFd地址0xfed34”,图二:“gs_s8Contenx地址0xfdfd4”大于“g_s32MaxFd地址0xfdbd4”。正是由于这两个地址的前后顺序才导致我编的库暴露了问题,因为我编的gs_s8Contenx地址小于g_s32MaxFd,代码里刚好使用gs_s8Contenx数组时以超过数组元素最大值做赋值操作,从而引发大面积内存越界,导致越界地址直接就踩到g_s32MaxFd变量地址了(踩到很多全局变量了),所以g_s32MaxFd数组的值被莫名修改,从而产生各种异常。当然同事编译的同样也会使gs_s8Contenx越界,但由于gs_s8Contenx地址大于g_s32MaxFd,所以gs_s8Contenx刚好踩到的是一段不常用的地址,导致问题没有及时暴露出来。



Tags:   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
早高峰打“飞的”有多快?半小时车程仅需6分钟
横越珠江,掠过广东省博物馆、花城广场等地标性景观,向着广州塔飞去……近日,小鹏汇天的eVTOL(电动垂直起降飞行器)旅航者X2首次飞跃广州CBD。跨江示范飞行中,半小时车...【详细内容】
2024-04-12  Search:   点击:(1)  评论:(0)  加入收藏
JavaScript的异步编程常见模式
在JavaScript中,异步编程是一种处理长时间运行操作(如网络请求或I/O操作)的常见方式。它允许程序在等待这些操作完成时继续执行其他任务,从而提高应用程序的响应性和性能。JavaS...【详细内容】
2024-04-12  Search:   点击:(2)  评论:(0)  加入收藏
Rust编程语言的内存安全与性能:如何平衡?
Rust编程语言自诞生以来,就以其独特的内存安全特性和高性能而备受瞩目。然而,如何在保证内存安全的同时,实现高效的性能,一直是Rust开发者们面临的挑战。本文将深入探讨Rust的内...【详细内容】
2024-04-12  Search:   点击:(2)  评论:(0)  加入收藏
数字人破解跨境直播难题,打造经济高效运营新路径
在数字化浪潮席卷全球,跨境直播蔚然成风之际,众多企业与品牌纷纷借此渠道掘金国际市场,直面全球消费者。然而,构建一支专业且高能的直播团队并非一日之功,它需耗费大量资源进行人...【详细内容】
2024-04-12  Search:   点击:(2)  评论:(0)  加入收藏
Meta确认5月发布Llama 3,参数量达1400亿
周二,在伦敦的一场活动上,Meta 确认计划在下个月初推出其 LLM 的最新版 Llama 3,这个模型是驱动生成式 AI 助手的核心技术。这一消息证实了《The Information》杂志周一发布的...【详细内容】
2024-04-12  Search:   点击:(2)  评论:(0)  加入收藏
ChatGPT 应用商店?可能是一个万能应用程序!
OpenAI 在去年 11 月召开了一次开发者大会,首席执行官 Sam Altman 希望软件制造商在 ChatGPT 之上进行进一步的构建。OpenAI 表示,它将很快推出一个市场,开发人员和非技术人员...【详细内容】
2024-04-12  Search:   点击:(3)  评论:(0)  加入收藏
社交网络与Web3:数字社交的演进
在数字化时代的浪潮下,社交网络已成为人们日常生活的重要组成部分。从早期的在线论坛到如今的社交媒体平台,社交网络已经成为人们交流、分享和获取信息的主要渠道。然而,随着区...【详细内容】
2024-04-12  Search:   点击:(2)  评论:(0)  加入收藏
速查微信聊天最频繁对象,情侣必备!
在如今数字化交流的时代,微信无疑是我们日常生活中使用最频繁的工具之一。无论是工作、学习还是娱乐,微信都陪伴在我们身边,成为我们沟通的重要桥梁。而在微信的众多功能中,聊天...【详细内容】
2024-04-12  Search:   点击:(1)  评论:(0)  加入收藏
女人在微信上给你发这两个字,其实是想你了
情感的表达需借助书信,那一份份缓慢穿越时空的纸张,承载着承诺与深情,往往能够维系一段白头偕老的姻缘。而如今,随着科技的进步,爱情已不再依赖书信这种传统的沟通方式。我们有了...【详细内容】
2024-04-12  Search:   点击:(2)  评论:(0)  加入收藏
Qt与Flutter:在跨平台UI框架中哪个更受欢迎?
在跨平台UI框架领域,Qt和Flutter是两个备受瞩目的选择。它们各自具有独特的优势,也各自有着广泛的应用场景。本文将对Qt和Flutter进行详细的比较,以探讨在跨平台UI框架中哪个更...【详细内容】
2024-04-12  Search:   点击:(1)  评论:(0)  加入收藏
▌简易百科推荐
微软 Win11 Linux 子系统(WSL)发布 2.2.2 版本
IT之家 4 月 8 日消息,微软近日更新 Windows Subsystem for Linux(WSL),最新 2.2.2 版本中带来了诸多改进,重点更新了 nft 规则,可以让 IPv6 流量通过 Linux 容器。图源: dev.to,AI...【详细内容】
2024-04-08    IT之家  Tags:Linux   点击:(6)  评论:(0)  加入收藏
从原理到实践:深入探索Linux安全机制
Linux 是一种开源的类Unix操作系统内核,由Linus Torvalds在1991年首次发布,其后又衍生出许多不同的发行版(如Ubuntu、Debian、CentOS等)。前言本文将从用户和权限管理、文件系统...【详细内容】
2024-03-27  凡夫编程  微信公众号  Tags:Linux安全   点击:(16)  评论:(0)  加入收藏
在Linux系统中,如何处理内存管理和优化的问题?
本文对 Linux 内存管理和优化的一些高级技巧的详细介绍,通过高级的内存管理技巧,可以帮助系统管理员和开发人员更好地优化 Linux 系统的内存使用情况,提高系统性能和稳定性。在...【详细内容】
2024-03-26  编程技术汇  微信公众号  Tags:Linux   点击:(10)  评论:(0)  加入收藏
Linux 6.9-rc1 内核发布:AMD P-State 首选核心、BH 工作队列
IT之家 3 月 25 日消息,Linus Torvalds 宣布,Linux 6.9 内核的首个 RC(候选发布)版 Linux 6.9-rc1 发布。▲ Linux 6.9-rc1Linus 表示,Linux 内核 6.9 看起来是一个“相当正常”...【详细内容】
2024-03-25    IT之家  Tags:Linux   点击:(12)  评论:(0)  加入收藏
轻松实现Centos系统的软件包安装管理:yum指令实战详解
yum 是一种用于在 CentOS、Red Hat Enterprise Linux (RHEL) 等基于 RPM 的 Linux 发行版上安装、更新和管理软件包的命令行工具。它可以自动解决软件包依赖关系,自动下载并...【详细内容】
2024-02-27  凡夫贬夫  微信公众号  Tags:Centos   点击:(54)  评论:(0)  加入收藏
Win + Ubuntu 缝合怪:第三方开发者推出“Wubuntu”Linux 发行版
IT之家 2 月 26 日消息,一位第三方开发者推出了一款名为“Wubuntu”的缝合怪 Linux 发行版,系统本身基于 Ubuntu,但界面为微软 Windows 11 风格,甚至存在微软 Windows 徽标。据...【详细内容】
2024-02-27    IT之家  Tags:Ubuntu   点击:(50)  评论:(0)  加入收藏
Linux中磁盘和文件系统工作原理解析
在Linux系统中,一切皆文件的概念意味着所有的资源,包括普通文件、目录以及设备文件等,都以文件的形式存在。这种统一的文件系统管理方式使得Linux系统具有高度的灵活性和可扩展...【详细内容】
2024-02-20  王建立    Tags:Linux   点击:(53)  评论:(0)  加入收藏
Linux子系统概览
inux操作系统是一个模块化的系统,由多个子系统组成。这些子系统协同工作,使Linux能够执行各种任务。了解Linux的子系统有助于更好地理解整个操作系统的运作机制。以下是Linux...【详细内容】
2024-02-01    简易百科  Tags:Linux   点击:(77)  评论:(0)  加入收藏
Linux内核:系统之魂与交互之源
内核,作为任何基于Linux的操作系统的心脏,扮演着至关重要的角色。它不仅是计算机系统软件与硬件之间的桥梁,更是确保系统稳定、高效运行的关键。内核提供了一系列核心功能,为上...【详细内容】
2024-02-01  松鼠宝贝    Tags:Linux内核   点击:(69)  评论:(0)  加入收藏
如何确保Linux进程稳定与持久
在Linux系统中,进程的稳定性与持久性对于维持系统的持续运行至关重要。然而,由于各种原因,进程可能会面临崩溃或系统重启的情况。为了确保关键进程能够持续运行,我们必须采取一...【详细内容】
2024-01-19  松鼠宝贝    Tags:Linux进程   点击:(85)  评论:(0)  加入收藏
相关文章
    无相关信息
站内最新
站内热门
站内头条