
OpenHarmony设备开发小型系统内核(LiteOS-A) 调测与工具
版本:V3.2Beta
LMS调测
基本概念
LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能:
- 支持多内存池检测;
- 支持LOS_MemAlloc、LOS_MemAllocAlign、LOS_MemRealloc申请出的内存检测;
- 支持安全函数的访问检测(默认开启);
- 支持libc 高频函数的访问检测,包括:memset、memcpy、memmove、strcat、strcpy、strncat、strncpy。
运行机制
LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。
- 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头节点区的影子内存设置为“不可读写”状态。
- 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。
- 编译代码时,会在代码中的读写指令前插入检测函数,对地址的合法性进行检验。主要是检测访问内存的影子内存的状态值,若检测到影子内存为不可读写,则会报溢出错误;若检测到影子内存为已释放,则会报释放后使用错误。
- 在内存释放时,会检测被释放地址的影子内存状态值,若检测到影子内存非可读写,则会报重复释放错误。
接口说明
内核态
OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信息可以查看API参考。
表1 LMS模块接口说明
功能分类 | 接口名 | 描述 |
添加指定内存池被检测 | LOS_LmsCheckPoolAdd | 将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。 |
删除指定内存池不被检测 | LOS_LmsCheckPoolDel | 不检测指定内存池地址范围内的合法性校验。 |
使能指定内存段锁保护 | LOS_LmsAddrProtect | 为某段内存地址上锁,设置为不可读写,一旦访问则报错。 |
去能指定内存段锁保护 | LOS_LmsAddrDisableProtect | 为某段内存地址解锁,设置为可读写。 |
用户态
用户态仅提供LMS检测库,不提供对外接口。
开发指导
内核态开发流程
开启LMS调测的典型流程如下:
- 配置LMS模块相关宏。 配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel->Enable Lite Memory Sanitizer"中打开YES:
宏 | menuconfig选项 | 含义 | 取值 |
LOSCFG_KERNEL_LMS | Enable Lms Feature | Lms模块的裁剪开关 | YES/NO |
LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | LMS支持的检测内存池最大个数 | INT |
LOSCFG_LMS_LOAD_CHECK | Enable lms read check | LMS内存读检测的裁剪开关 | YES/NO |
LOSCFG_LMS_STORE_CHECK | Enable lms write check | LMS内存写检测的裁剪开关 | YES/NO |
LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | LMS内存逐字节严格检测的裁剪开关 | YES/NO |
- 在被检测模块的编译脚本中,修改编译选项。 增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。
gcc与clang编译选项存在差异,参照如下示例:
- 重新编译,查看串口输出。如果检测到内存问题,会输出检测结果。
内核态编程实例
本实例实现如下功能:
- 创建一个用于Lms测试的任务。
- 构造内存溢出错误和释放后使用错误。
- 添加-fsanitize=kernel-address后编译执行,观察输出结果。
内核态示例代码
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。 实例代码如下:
内核态结果验证
输出结果如下:
输出的关键信息包括:
- 错误类型:
- Heap buffer overflow堆内存越界
- Use after free 释放后使用
- 错误操作:
- Illegal Read非法读
- Illegal Write非法写
- Illegal Double free重复释放
- 上下文:
- 当前任务信息(taskName, taskId)
- 回溯栈(backtrace)
- 出错地址的内存信息:
- 内存的值、及对应影子内存的值
- 内存地址:内存值| [影子内存地址 | 影子内存字节内偏移]:影子内存值
- 影子内存值:0(可读可写)、3(已释放)、2(红区)、1(填充值)。
用户态开发流程
在待检测的app编译脚本中,添加如下参数即可, 完整示例可参见 /kernel/liteos_a/apps/lms/BUILD.gn。
用户态编程实例
本实例实现如下功能:
- 构造内存溢出错误和释放后使用错误。
- 添加对应编译选项后,重新编译执行。
用户态示例代码
实例代码如下:
用户态结果验证
输出结果如下:
输出的Backtrace中包含地址所在的文件名,用户需查找对应文件中地址对应的代码行号。
LMS调测
基本概念
LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能:
- 支持多内存池检测;
- 支持LOS_MemAlloc、LOS_MemAllocAlign、LOS_MemRealloc申请出的内存检测;
- 支持安全函数的访问检测(默认开启);
- 支持libc 高频函数的访问检测,包括:memset、memcpy、memmove、strcat、strcpy、strncat、strncpy。
运行机制
LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。
- 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头节点区的影子内存设置为“不可读写”状态。
- 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。
- 编译代码时,会在代码中的读写指令前插入检测函数,对地址的合法性进行检验。主要是检测访问内存的影子内存的状态值,若检测到影子内存为不可读写,则会报溢出错误;若检测到影子内存为已释放,则会报释放后使用错误。
- 在内存释放时,会检测被释放地址的影子内存状态值,若检测到影子内存非可读写,则会报重复释放错误。
接口说明
内核态
OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信息可以查看API参考。
表1 LMS模块接口说明
功能分类 | 接口名 | 描述 |
添加指定内存池被检测 | LOS_LmsCheckPoolAdd | 将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。 |
删除指定内存池不被检测 | LOS_LmsCheckPoolDel | 不检测指定内存池地址范围内的合法性校验。 |
使能指定内存段锁保护 | LOS_LmsAddrProtect | 为某段内存地址上锁,设置为不可读写,一旦访问则报错。 |
去能指定内存段锁保护 | LOS_LmsAddrDisableProtect | 为某段内存地址解锁,设置为可读写。 |
用户态
用户态仅提供LMS检测库,不提供对外接口。
开发指导
内核态开发流程
开启LMS调测的典型流程如下:
- 配置LMS模块相关宏。 配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel->Enable Lite Memory Sanitizer"中打开YES:
宏 | menuconfig选项 | 含义 | 取值 |
LOSCFG_KERNEL_LMS | Enable Lms Feature | Lms模块的裁剪开关 | YES/NO |
LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | LMS支持的检测内存池最大个数 | INT |
LOSCFG_LMS_LOAD_CHECK | Enable lms read check | LMS内存读检测的裁剪开关 | YES/NO |
LOSCFG_LMS_STORE_CHECK | Enable lms write check | LMS内存写检测的裁剪开关 | YES/NO |
LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | LMS内存逐字节严格检测的裁剪开关 | YES/NO |
- 在被检测模块的编译脚本中,修改编译选项。 增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。
gcc与clang编译选项存在差异,参照如下示例:
- 重新编译,查看串口输出。如果检测到内存问题,会输出检测结果。
内核态编程实例
本实例实现如下功能:
- 创建一个用于Lms测试的任务。
- 构造内存溢出错误和释放后使用错误。
- 添加-fsanitize=kernel-address后编译执行,观察输出结果。
内核态示例代码
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。 实例代码如下:
内核态结果验证
输出结果如下:
输出的关键信息包括:
- 错误类型:
- Heap buffer overflow堆内存越界
- Use after free 释放后使用
- 错误操作:
- Illegal Read非法读
- Illegal Write非法写
- Illegal Double free重复释放
- 上下文:
- 当前任务信息(taskName, taskId)
- 回溯栈(backtrace)
- 出错地址的内存信息:
- 内存的值、及对应影子内存的值
- 内存地址:内存值| [影子内存地址 | 影子内存字节内偏移]:影子内存值
- 影子内存值:0(可读可写)、3(已释放)、2(红区)、1(填充值)。
用户态开发流程
在待检测的app编译脚本中,添加如下参数即可, 完整示例可参见 /kernel/liteos_a/apps/lms/BUILD.gn。
用户态编程实例
本实例实现如下功能:
- 构造内存溢出错误和释放后使用错误。
- 添加对应编译选项后,重新编译执行。
用户态示例代码
实例代码如下:
用户态结果验证
输出结果如下:
输出的Backtrace中包含地址所在的文件名,用户需查找对应文件中地址对应的代码行号。
文章转载自:https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/device-dev/kernel/kernel-small-memory-lms.md/
