往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录)

✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

✏️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~

✏️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?

✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?

✏️ 记录一场鸿蒙开发岗位面试经历~

✏️ 持续更新中……


原理概述

HWASan是Hardware-Assisted Address Sanitizer的简称,它是Clang LLVM提供的一套内存错误检测系统,用来检测C/C++中常见的内存访问错误,相比之前的Asan(Address Sanitizer),它在性能、内存上有不小提升,依赖于编译器的Address Tagging特性,该特性允许应用程序自定义数据存储到虚拟地址的最高8位,当CPU操作该虚拟地址时会自动忽略它。HWASan工具检测地址越界问题的原理如下,

  1. 将整个虚拟内存区间按照16:1的比例,划分为user memory和shadow memory;同时,无论是堆上、栈上还是全局对象,其内存起始地址都按照16字节对齐,即保证每16字节的user memory都能映射到1字节的shadow memory;
  2. 分配对象的时候,随机分配一个8位的随机tag标记到该对象的虚拟地址最高8位,同时该tag也会保存到其映射的shadow memory中;
  3. 编译器在每个内存地址的load/store之前都会插入检查指令,用于确认操作地址的最高8位保存的tag与其映射的shadow memory中的tag值是否一致;
  4. 对象回收后也会重新分配一个随机值,保存到其映射的shadow memory中,当出现内存越界行为时,就会检测到tag值不一致的异常;

注意,当分配的对象小于16字节时,多余的内存不会再分配给其它对象,此时shadow memory中保存的是对象所占内存的实际字节数,而tag值则保存在16字节的最后一个字节里面。

常见的HWASan异常检测类型有stack-buffer-overflow/underflow,stack-use-after-return,heap-buffer-overflow等。

功能介绍

HWASan能检测到ASan所能检测到的同一系列错误:

  • 堆栈和堆缓冲区上溢/下溢。
  • 释放之后的堆使用情况。
  • 重复释放/错误释放。

和ASan相比,HWASan具有以下优点:

  • HWASan不需要安全区来检测buffer overflow,既极大地降低了工具对于内存的消耗,也不会出现ASan中某些overflow检测不到的情况。
  • HWASan不需要隔离区来检测UseAfterFree,因此不会出现ASan中某些UseAfterFree检测不到的情况。
  • 此外,HWASan还可以检测返回之后的堆栈使用情况。

使用约束

  • ROM版本5.0.0.107及以上支持。
  • ASan、TSan、HWASan、UBsan不能同时开启,四个只能开启其中一个。

配置HWASan

可通过方式一和方式二使能HWAsan,每种方式分为DevEco Studio场景和流水线场景。

方式一

DevEco Studio****场景

点击Run > Edit Configurations >**Diagnostics,勾选Hardware-Assisted Address Sanitizer**开启检测。

流水线场景

  1. 修改工程目录下的AppScope/app.json5文件,添加HWASan配置开关。
"hwasanEnabled": true

  1. 在hvigorw命令后加上**-p ****ohos-enable-hwasan=true**的选项,执行hvigorw命令,
hvigorw [taskNames...] -p ohos-enable-hwasan=true  <options> 

方式二

DevEco Studio场景

  1. 修改工程目录下的AppScope/app.json5文件,添加HWASan配置开关。
"hwasanEnabled": true

2. 在需要使能HWASan的模块中,通过添加构建参数开启HWASan检测插桩,在对应模块的模块级build-profile.json5中添加命令参数:

"arguments": "-DOHOS_ENABLE_HWASAN=ON"

流水线场景

在AppScope/app.json5和模块build-profile.json5配置对应HWASan项后,可直接执行hvigorw命令

hvigorw [taskNames...]  <options> 

说明
如果按方式一勾选以后,配置app.json5中的为false,HWASan仍生效

运行HWASan

  1. 运行或调试当前应用。

2. 当程序出现内存错误时,弹出HWASan log信息,点击信息中的链接即可跳转至引起内存错误的代码处。

HWasan异常检测类型

stack tag-mismatch

背景

"stack tag-mismatch"在HWASan中指的是栈内存标签不匹配错误。这种错误通常发生在访问栈内存时,指针携带的标签与栈内存中存储的标签不一致,触发其异常检测码字的异常类型有:stack-buffer-overflow/underflow、stack-use-after-return。

错误代码实例

// stack-buffer-overflow
int stackBufferOverflow() {
    int subscript = 43;
    char buffer[42];
    buffer[subscript] = 42;
    return 0;
}

// stack-buffer-underflow
int stackBufferUnderflow() {
    int subscript = -1;
    char buffer[42];
    buffer[subscript] = 42;
    return 0;
}

// stack-use-after-return
int *ptr;
__attribute__((noinline))
void FunctionThatEscapesLocalObject() {
  int local[100];
  ptr = &local[0];
}
int main(int argc, char **argv) {
  FunctionThatEscapesLocalObject();
  return ptr[argc];
}

影响

导致程序存在安全漏洞,并有崩溃风险。

开启ASan检测后,触发demo中的函数,应用闪退报HWASAN,包含字段:

HWAddressSanitizer: tag-mismatch on address

Cause: stack tag-mismatch

定位思路

如果有工程代码,直接开启HWAsan检测,debug模式运行后复现该错误,可以触发WAsan,直接点击堆栈中的超链接定位到代码行,能看到错误代码的位置。

Reason:HWASAN
==appspawn==61390==ERROR: HWAddressSanitizer: tag-mismatch on address 0x007eb11cc05f at pc 0x005acf446438
WRITE of size 1 at 0x007eb11cc05f tags: f1/00 (ptr/mem) in thread T0
    #0 0x5acf446438  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6438) (BuildId: 4b0b8d2189a7eb99fff81c6bc8889dfefd4af4a1)
    #1 0x5acf446c08  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6c08) (BuildId: 4b0b8d2189a7eb99fff81c6bc8889dfefd4af4a1)
    #2 0x5ab397cdc8  (/system/lib64/platformsdk/libace_napi.z.so+0x3cdc8) (BuildId: dc293a22b36a4db17dc689ff9413b64e)

Cause: stack tag-mismatch
Address 0x007eb11cc05f is located in stack of thread T0
Thread: T0 0x005b00002000 stack: [0x007eb09d2000,0x007eb11d1000) sz: 8384512 tls: [0x005aacd0fa98,0x005aacd10279)
Previously allocated frames:
  record_addr:0x5ab053c788 record:0xcc0a005acf4463c0  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x63c0) (BuildId: 4b0b8d2189a7eb99fff81c6bc8889dfefd4af4a1)
  record_addr:0x5ab053c780 record:0xcc1a005acf446a68  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6a68) (BuildId: 4b0b8d2189a7eb99fff81c6bc8889dfefd4af4a1)
  record_addr:0x5ab053c778 record:0xcb81005acf4866ac  (/data/storage/el1/bundle/libs/arm64/libmainpage.so+0x66ac) (BuildId: 10ffa0d04cbc27e12a59f658b5932674185d63ee)
  record_addr:0x5ab053c770 record:0xcc87005acf4465b4  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x65b4) (BuildId: 4b0b8d2189a7eb99fff81c6bc8889dfefd4af4a1)

修改方法

stack-buffer-overflow/underflow**:**访问索引要落在给定的范围内

stack-use-after-return:在作用域内使用局部变量

推荐建议

stack-buffer-overflow/underflow:访问索引不要超过给定的上界/下界

stack-use-return: 如果需要在函数返回后继续使用某些数据,考虑将它们存储在静态或全局变量中

heap-buffer-overflow

背景

访问堆内存越界(上下界),触发其异常检测码字的异常类型有:heap-buffer-overflow、heap-buffer-underflow

错误代码实例

// heap-buffer-overflow
void heapBufferOverflow() {
    char *buffer;
    buffer = (char *)malloc(10);
    *(buffer + 11) = 'n';
    *(buffer + 12) = 'n';
    free(buffer);
}

// heap-buffer-underflow
void heapBufferUnderflow() {
    char *buffer;
    buffer = (char *)malloc(10);
    *(buffer - 11) = 'n';
    *(buffer - 12) = 'n';
    free(buffer);
}

影响

导致程序存在安全漏洞,并有崩溃风险。

开启HWASan检测后,触发demo中的函数,应用闪退报HWASan,包含字段:

HWAddressSanitizer: tag-mismatch

Cause: heap-buffer-overflow

定位思路

如果有工程代码,直接开启HWASan检测,debug模式运行后复现该错误,可以触发HWASan,直接点击堆栈中的超链接定位到代码行,能看到错误代码的位置。

Reason:HWASAN
==appspawn==8344==ERROR: HWAddressSanitizer: tag-mismatch on address 0x000100760332 at pc 0x005adb286570
WRITE of size 1 at 0x000100760332 tags: cb/08(44) (ptr/mem) in thread T0
    #0 0x5adb286570  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6570) (BuildId: 4724eac5a66f4994a03c023a9958da3897de5f16)
    #1 0x5adb286c8c  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6c8c) (BuildId: 4724eac5a66f4994a03c023a9958da3897de5f16)
    #2 0x5abd63cdc8  (/system/lib64/platformsdk/libace_napi.z.so+0x3cdc8) (BuildId: dc293a22b36a4db17dc689ff9413b64e)

[0x000100760320,0x000100760340) is a small allocated heap chunk; size: 32 offset: 18

Cause: heap-buffer-overflow
0x000100760332 is located 110 bytes to the left of 10-byte region [0x0001007603a0,0x0001007603aa)
allocated here:
    #0 0x5a394625ec  (/system/lib64/libclang_rt.hwasan.so+0x225ec) (BuildId: 2b2455ae77181bfdfbfa9561b4e6e3ea376ec93b)
    #1 0x5adb286548  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6548) (BuildId: 4724eac5a66f4994a03c023a9958da3897de5f16)
    #2 0x5adb286c8c  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6c8c) (BuildId: 4724eac5a66f4994a03c023a9958da3897de5f16)
    #3 0x5abd63cdc8  (/system/lib64/platformsdk/libace_napi.z.so+0x3cdc8) (BuildId: dc293a22b36a4db17dc689ff9413b64e)
    #4 0x5ad4373b6c  (/system/lib64/module/arkcompiler/stub.an+0x3f3b6c)
    #5 0x5ad3f8be8c  (/system/lib64/module/arkcompiler/stub.an+0xbe8c)

修改方法

注意数组长度,不能越界

heap-buffer-overflow: 数组访问位置不要越上界

heap-buffer-underflow: 访问数组位置不要越下界

推荐建议

已知大小的数组注意访问不要越界,访问已知大小数组前先判断访问位置是否落在边界外

Use-after-free

背景

触发其异常检测码字的异常类型有:heap-use-after-free、double-free

heap-use-after-free: 当指针指向的内存被释放后,仍然通过该指针访问已经被释放的内存,就会触发heap-use-after-free

double-free: 重复释放内存

错误代码实例

// heap-use-after-free
int useAfterFree(int argc) {
    int *array = new int[100];
    delete[] array;
    return array[argc];
}

// double free
void doubleFree() {
    char *p = (char *)malloc(32 * sizeof(char));
    free(p);
    free(p);
}

影响

导致程序存在安全漏洞,并有崩溃风险。

开启HWAsan检测后,触发demo中的函数,应用闪退报HWAsan,包含字段:

HWAddressSanitizer: tag-mismatch

Cause: use-after-free

定位思路

如果有工程代码,直接开启ASan检测,debug模式运行后复现该错误,可以触发ASan,直接点击堆栈中的超链接定位到代码行,能看到错误代码的位置。

Reason:HWASAN
==appspawn==10741==ERROR: HWAddressSanitizer: tag-mismatch on address 0x000d00036a68 at pc 0x005ab24864c4
READ of size 4 at 0x000d00036a68 tags: ae/6e (ptr/mem) in thread T0
    #0 0x5ab24864c4  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x64c4) (BuildId: e073772c81ab52894a21e4190a263680198f3e9c)
    #1 0x5ab2486c84  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6c84) (BuildId: e073772c81ab52894a21e4190a263680198f3e9c)
    #2 0x5a96b7cdc8  (/system/lib64/platformsdk/libace_napi.z.so+0x3cdc8) (BuildId: dc293a22b36a4db17dc689ff9413b64e)

[0x000d00036a60,0x000d00036c00) is a small unallocated heap chunk; size: 416 offset: 8

Cause: use-after-free
0x000d00036a68 is located 8 bytes inside of 400-byte region [0x000d00036a60,0x000d00036bf0)
freed by thread T0 here:
    #0 0x5a90a6844c  (/system/lib64/libclang_rt.hwasan.so+0x2844c) (BuildId: 2b2455ae77181bfdfbfa9561b4e6e3ea376ec93b)
    #1 0x5ab2486494  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6494) (BuildId: e073772c81ab52894a21e4190a263680198f3e9c)
    #2 0x5ab2486c84  (/data/storage/el1/bundle/libs/arm64/libentry.so+0x6c84) (BuildId: e073772c81ab52894a21e4190a263680198f3e9c)
    #3 0x5a96b7cdc8  (/system/lib64/platformsdk/libace_napi.z.so+0x3cdc8) (BuildId: dc293a22b36a4db17dc689ff9413b64e)
    #4 0x5aab6b3b6c  (/system/lib64/module/arkcompiler/stub.an+0x3f3b6c)
    #5 0x5aab2cbe8c  (/system/lib64/module/arkcompiler/stub.an+0xbe8c)

修改方法

heap-use-after-free: 已经释放的指针不要再使用,将指针设置为NULL/nullptr。

double-free:已经释放一次的指针,不要再重复释放。

推荐建议

heap-use-after-free: 使用智能指针,或实现一个free()函数的替代版本或者 delete析构器来保证指针的重置。

double-free: 变量定义声明时初始化为NULL,释放内存后也应立即将变量重置为NULL,这样每次释放之前都可以通过判断变量是否为NULL来判断是否可以释放。

Logo

更多推荐