更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_lms.c
浏览该文件的文档.
1/*!
2 * @file los_lms.c
3 * @brief 检测内存主文件
4 * @link
5 @verbatim
6 基本概念
7 LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),
8 释放后使用(use after free) 和重复释放(double Free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,
9 能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
10 OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能:
11 支持多内存池检测。
12 支持LOS_MemAlloc、LOS_MemAllocAlign、LOS_MemRealloc申请出的内存检测。
13 支持安全函数的访问检测(默认开启)。
14 支持libc 高频函数的访问检测,包括:memset、memcpy、memmove、strcat、strcpy、strncat、strncpy。
15 运行机制
16 LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。
17 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头结点区的影子内存设置为“不可读写”状态。
18 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。
19 编译代码时,会在代码中的读写指令前插入检测函数,对地址的合法性进行检验。主要是检测访问内存的影子内存的状态值,
20 若检测到影子内存为不可读写,则会报溢出错误;若检测到影子内存为已释放,则会报释放后使用错误。
21 在内存释放时,会检测被释放地址的影子内存状态值,若检测到影子内存非可读写,则会报重复释放错误。
22 @endverbatim
23 * @version
24 * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
25 * @date 2022-03-22
26 */
27/*
28 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
29 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without modification,
32 * are permitted provided that the following conditions are met:
33 *
34 * 1. Redistributions of source code must retain the above copyright notice, this list of
35 * conditions and the following disclaimer.
36 *
37 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
38 * of conditions and the following disclaimer in the documentation and/or other materials
39 * provided with the distribution.
40 *
41 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
42 * to endorse or promote products derived from this software without specific prior written
43 * permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
47 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
49 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58#include "los_lms_pri.h"
59#include "los_spinlock.h"
60#include "los_exc.h"
61#include "los_sched_pri.h"
62#include "los_atomic.h"
63#include "los_init.h"
64
65LITE_OS_SEC_BSS STATIC LmsMemListNode g_lmsCheckPoolArray[LOSCFG_LMS_MAX_RECORD_POOL_NUM];
66LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_lmsCheckPoolList;
68LmsHook *g_lms = NULL;
69
70LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_lmsSpin);
71#define LMS_LOCK(state) LOS_SpinLockSave(&g_lmsSpin, &(state))
72#define LMS_UNLOCK(state) LOS_SpinUnlockRestore(&g_lmsSpin, (state))
73
74#define OS_MEM_ALIGN_BACK(value, align) (((UINT32)(value)) & ~((UINT32)((align) - 1)))
75#define OS_MEM_ALIGN_SIZE sizeof(UINTPTR)
76#define POOL_ADDR_ALIGNSIZE 64
77#define LMS_POOL_UNUSED 0
78#define LMS_POOL_USED 1
79#define INVALID_SHADOW_VALUE 0xFFFFFFFF
80
82{
83 return OS_MEM_ALIGN_BACK(LMS_POOL_RESIZE(size), POOL_ADDR_ALIGNSIZE);
84}
85
86STATIC LmsMemListNode *OsLmsGetPoolNode(const VOID *pool)
87{
88 UINTPTR poolAddr = (UINTPTR)pool;
89 LmsMemListNode *current = NULL;
91
93 goto EXIT;
94 }
95
96 LOS_DL_LIST_FOR_EACH_ENTRY(current, listHead, LmsMemListNode, node) {
97 if (current->poolAddr == poolAddr) {
98 return current;
99 }
100 }
101
102EXIT:
103 return NULL;
104}
105
107{
108 LmsMemListNode *current = NULL;
109 LOS_DL_LIST *listHead = &g_lmsCheckPoolList;
110
112 goto EXIT;
113 }
114
115 LOS_DL_LIST_FOR_EACH_ENTRY(current, listHead, LmsMemListNode, node) {
116 if ((addr >= current->poolAddr) && (addr < current->poolAddr + current->poolSize)) {
117 return current;
118 }
119 }
120
121EXIT:
122 return NULL;
123}
124
126{
127 UINT32 i;
128 LmsMemListNode *current = NULL;
129 for (i = 0; i < LOSCFG_LMS_MAX_RECORD_POOL_NUM; i++) {
130 current = &g_lmsCheckPoolArray[i];
131 if (current->used == LMS_POOL_UNUSED) {
132 current->used = LMS_POOL_USED;
133 return current;
134 }
135 }
136 return NULL;
137}
138/// 添加指定内存池被检测
139/// 将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;
140/// 且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。
141UINT32 LOS_LmsCheckPoolAdd(const VOID *pool, UINT32 size)
142{
143 UINT32 intSave;
144 UINTPTR poolAddr = (UINTPTR)pool;
145 UINT32 realSize;
146 LmsMemListNode *lmsPoolNode = NULL;
147
148 if (pool == NULL) {
149 return 0;
150 }
151
152 LMS_LOCK(intSave);
153
154 lmsPoolNode = OsLmsGetPoolNodeFromAddr((UINTPTR)pool);
155 if (lmsPoolNode != NULL) { /* if pool range already on checklist */
156 if (lmsPoolNode->poolAddr != (UINTPTR)pool) { /* pool is a subset of lmsPoolNode->poolAddr */
157 /* do not add it again, just return */
158 PRINT_DEBUG("[LMS]pool %p already on lms checklist !\n", pool);
159 LMS_UNLOCK(intSave);
160 return size; /* return size indicate the shadow memory init successful */
161 } else { /* Re-initialize the same pool, maybe with different size */
162 /* delete the old node, then add a new one */
163 lmsPoolNode->used = LMS_POOL_UNUSED;
164 LOS_ListDelete(&(lmsPoolNode->node));
165 }
166 }
167
168 lmsPoolNode = OsLmsCheckPoolCreate();
169 if (lmsPoolNode == NULL) {
170 PRINT_DEBUG("[LMS]the num of lms check pool is max already !\n");
171 LMS_UNLOCK(intSave);
172 return 0;
173 }
174 realSize = OsLmsPoolResize(size);
175
176 lmsPoolNode->poolAddr = poolAddr;
177 lmsPoolNode->poolSize = realSize;
178 lmsPoolNode->shadowStart = (UINTPTR)poolAddr + realSize;
179 lmsPoolNode->shadowSize = poolAddr + size - lmsPoolNode->shadowStart;
180 /* init shadow value */
181 (VOID)memset((VOID *)lmsPoolNode->shadowStart, LMS_SHADOW_AFTERFREE_U8, lmsPoolNode->shadowSize);
182
183 LOS_ListAdd(&g_lmsCheckPoolList, &(lmsPoolNode->node));
184
185 LMS_UNLOCK(intSave);
186 return realSize;
187}
188
189VOID LOS_LmsCheckPoolDel(const VOID *pool)
190{
191 UINT32 intSave;
192 if (pool == NULL) {
193 return;
194 }
195
196 LMS_LOCK(intSave);
197 LmsMemListNode *delNode = OsLmsGetPoolNode(pool);
198 if (delNode == NULL) {
199 PRINT_ERR("[LMS]pool %p is not on lms checklist !\n", pool);
200 goto Release;
201 }
202 delNode->used = LMS_POOL_UNUSED;
203 LOS_ListDelete(&(delNode->node));
204Release:
205 LMS_UNLOCK(intSave);
206}
207/// 初始化 LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具
208STATIC UINT32 OsLmsInit(VOID)
209{
212 static LmsHook hook = {
214 .mallocMark = OsLmsLosMallocMark,
215 .freeMark = OsLmsLosFreeMark,
216 .simpleMark = OsLmsSimpleMark,
217 .check = OsLmsCheckValid,
218 };
219 g_lms = &hook;
220 return LOS_OK;
221}
222
223STATIC INLINE UINT32 OsLmsMem2Shadow(LmsMemListNode *node, UINTPTR memAddr, UINTPTR *shadowAddr, UINT32 *shadowOffset)
224{
225 if ((memAddr < node->poolAddr) || (memAddr >= node->poolAddr + node->poolSize)) { /* check ptr valid */
226 PRINT_ERR("[LMS]memAddr %p is not in pool region [%p, %p)\n", memAddr, node->poolAddr,
227 node->poolAddr + node->poolSize);
228 return LOS_NOK;
229 }
230
231 UINT32 memOffset = memAddr - node->poolAddr;
232 *shadowAddr = node->shadowStart + memOffset / LMS_SHADOW_U8_REFER_BYTES;
233 *shadowOffset = ((memOffset % LMS_SHADOW_U8_REFER_BYTES) / LMS_SHADOW_U8_CELL_NUM) *
234 LMS_SHADOW_BITS_PER_CELL; /* (memOffset % 16) / 4 */
235 return LOS_OK;
236}
237
238STATIC INLINE VOID OsLmsGetShadowInfo(LmsMemListNode *node, UINTPTR memAddr, LmsAddrInfo *info)
239{
240 UINTPTR shadowAddr;
241 UINT32 shadowOffset;
242 UINT32 shadowValue;
243
244 if (OsLmsMem2Shadow(node, memAddr, &shadowAddr, &shadowOffset) != LOS_OK) {
245 return;
246 }
247
248 shadowValue = ((*(UINT8 *)shadowAddr) >> shadowOffset) & LMS_SHADOW_MASK;
249 info->memAddr = memAddr;
250 info->shadowAddr = shadowAddr;
251 info->shadowOffset = shadowOffset;
252 info->shadowValue = shadowValue;
253}
254
255VOID OsLmsSetShadowValue(LmsMemListNode *node, UINTPTR startAddr, UINTPTR endAddr, UINT8 value)
256{
257 UINTPTR shadowStart;
258 UINTPTR shadowEnd;
259 UINT32 startOffset;
260 UINT32 endOffset;
261
262 UINT8 shadowValueMask;
263 UINT8 shadowValue;
264
265 /* endAddr -1, then we mark [startAddr, endAddr) to value */
266 if (OsLmsMem2Shadow(node, startAddr, &shadowStart, &startOffset) ||
267 OsLmsMem2Shadow(node, endAddr - 1, &shadowEnd, &endOffset)) {
268 return;
269 }
270
271 if (shadowStart == shadowEnd) { /* in the same u8 */
272 /* because endAddr - 1, the endOffset falls into the previous cell,
273 so endOffset + 2 is required for calculation */
274 shadowValueMask = LMS_SHADOW_MASK_U8;
275 shadowValueMask =
276 (shadowValueMask << startOffset) & (~(shadowValueMask << (endOffset + LMS_SHADOW_BITS_PER_CELL)));
277 shadowValue = value & shadowValueMask;
278 *(UINT8 *)shadowStart &= ~shadowValueMask;
279 *(UINT8 *)shadowStart |= shadowValue;
280 } else {
281 /* Adjust startAddr to left util it reach the beginning of a u8 */
282 if (startOffset > 0) {
283 shadowValueMask = LMS_SHADOW_MASK_U8;
284 shadowValueMask = shadowValueMask << startOffset;
285 shadowValue = value & shadowValueMask;
286 *(UINT8 *)shadowStart &= ~shadowValueMask;
287 *(UINT8 *)shadowStart |= shadowValue;
288 shadowStart += 1;
289 }
290
291 /* Adjust endAddr to right util it reach the end of a u8 */
292 if (endOffset < (LMS_SHADOW_U8_CELL_NUM - 1) * LMS_SHADOW_BITS_PER_CELL) {
293 shadowValueMask = LMS_SHADOW_MASK_U8;
294 shadowValueMask &= ~(shadowValueMask << (endOffset + LMS_SHADOW_BITS_PER_CELL));
295 shadowValue = value & shadowValueMask;
296 *(UINT8 *)shadowEnd &= ~shadowValueMask;
297 *(UINT8 *)shadowEnd |= shadowValue;
298 shadowEnd -= 1;
299 }
300
301 if (shadowEnd + 1 > shadowStart) {
302 (VOID)memset((VOID *)shadowStart, value & LMS_SHADOW_MASK_U8, shadowEnd + 1 - shadowStart);
303 }
304 }
305}
306
307VOID OsLmsGetShadowValue(LmsMemListNode *node, UINTPTR addr, UINT32 *shadowValue)
308{
309 UINTPTR shadowAddr;
310 UINT32 shadowOffset;
311 if (OsLmsMem2Shadow(node, addr, &shadowAddr, &shadowOffset) != LOS_OK) {
312 return;
313 }
314
315 *shadowValue = ((*(UINT8 *)shadowAddr) >> shadowOffset) & LMS_SHADOW_MASK;
316}
317
318VOID OsLmsSimpleMark(UINTPTR startAddr, UINTPTR endAddr, UINT32 value)
319{
320 UINT32 intSave;
321 if (endAddr <= startAddr) {
322 PRINT_DEBUG("[LMS]mark 0x%x, 0x%x, 0x%x\n", startAddr, endAddr, (UINTPTR)__builtin_return_address(0));
323 return;
324 }
325
326 if (!IS_ALIGNED(startAddr, OS_MEM_ALIGN_SIZE) || !IS_ALIGNED(endAddr, OS_MEM_ALIGN_SIZE)) {
327 PRINT_ERR("[LMS]mark addr is not aligned! 0x%x, 0x%x\n", startAddr, endAddr);
328 return;
329 }
330
331 LMS_LOCK(intSave);
332
333 LmsMemListNode *node = OsLmsGetPoolNodeFromAddr(startAddr);
334 if (node == NULL) {
335 LMS_UNLOCK(intSave);
336 return;
337 }
338
339 OsLmsSetShadowValue(node, startAddr, endAddr, value);
340 LMS_UNLOCK(intSave);
341}
342
343VOID OsLmsLosMallocMark(const VOID *curNodeStart, const VOID *nextNodeStart, UINT32 nodeHeadSize)
344{
345 UINT32 intSave;
346 UINTPTR curNodeStartAddr = (UINTPTR)curNodeStart;
347 UINTPTR nextNodeStartAddr = (UINTPTR)nextNodeStart;
348
349 LMS_LOCK(intSave);
350 LmsMemListNode *node = OsLmsGetPoolNodeFromAddr((UINTPTR)curNodeStart);
351 if (node == NULL) {
352 LMS_UNLOCK(intSave);
353 return;
354 }
355
356 OsLmsSetShadowValue(node, curNodeStartAddr, curNodeStartAddr + nodeHeadSize, LMS_SHADOW_REDZONE_U8);
357 OsLmsSetShadowValue(node, curNodeStartAddr + nodeHeadSize, nextNodeStartAddr, LMS_SHADOW_ACCESSABLE_U8);
358 OsLmsSetShadowValue(node, nextNodeStartAddr, nextNodeStartAddr + nodeHeadSize, LMS_SHADOW_REDZONE_U8);
359 LMS_UNLOCK(intSave);
360}
361
362VOID OsLmsCheckValid(UINTPTR checkAddr, BOOL isFreeCheck)
363{
364 UINT32 intSave;
365 UINT32 shadowValue = INVALID_SHADOW_VALUE;
366 LMS_LOCK(intSave);
367 LmsMemListNode *node = OsLmsGetPoolNodeFromAddr(checkAddr);
368 if (node == NULL) {
369 LMS_UNLOCK(intSave);
370 return;
371 }
372
373 OsLmsGetShadowValue(node, checkAddr, &shadowValue);
374 LMS_UNLOCK(intSave);
375 if ((shadowValue == LMS_SHADOW_ACCESSABLE) || ((isFreeCheck) && (shadowValue == LMS_SHADOW_PAINT))) {
376 return;
377 }
378
379 OsLmsReportError(checkAddr, MEM_REGION_SIZE_1, isFreeCheck ? FREE_ERRORMODE : COMMON_ERRMODE);
380}
381
382VOID OsLmsLosFreeMark(const VOID *curNodeStart, const VOID *nextNodeStart, UINT32 nodeHeadSize)
383{
384 UINT32 intSave;
385 UINT32 shadowValue = INVALID_SHADOW_VALUE;
386
387 LMS_LOCK(intSave);
388 LmsMemListNode *node = OsLmsGetPoolNodeFromAddr((UINTPTR)curNodeStart);
389 if (node == NULL) {
390 LMS_UNLOCK(intSave);
391 return;
392 }
393
394 UINTPTR curNodeStartAddr = (UINTPTR)curNodeStart;
395 UINTPTR nextNodeStartAddr = (UINTPTR)nextNodeStart;
396
397 OsLmsGetShadowValue(node, curNodeStartAddr + nodeHeadSize, &shadowValue);
398 if ((shadowValue != LMS_SHADOW_ACCESSABLE) && (shadowValue != LMS_SHADOW_PAINT)) {
399 LMS_UNLOCK(intSave);
400 OsLmsReportError(curNodeStartAddr + nodeHeadSize, MEM_REGION_SIZE_1, FREE_ERRORMODE);
401 return;
402 }
403
404 if (*((UINT8 *)curNodeStart) == 0) { /* if merge the node has memset with 0 */
405 OsLmsSetShadowValue(node, curNodeStartAddr, curNodeStartAddr + nodeHeadSize, LMS_SHADOW_AFTERFREE_U8);
406 }
407 OsLmsSetShadowValue(node, curNodeStartAddr + nodeHeadSize, nextNodeStartAddr, LMS_SHADOW_AFTERFREE_U8);
408
409 if (*((UINT8 *)nextNodeStart) == 0) { /* if merge the node has memset with 0 */
410 OsLmsSetShadowValue(node, nextNodeStartAddr, nextNodeStartAddr + nodeHeadSize, LMS_SHADOW_AFTERFREE_U8);
411 }
412
413 LMS_UNLOCK(intSave);
414}
415
416VOID LOS_LmsAddrProtect(UINTPTR addrStart, UINTPTR addrEnd)
417{
418 UINT32 intSave;
419 if (addrEnd <= addrStart) {
420 return;
421 }
422 LMS_LOCK(intSave);
423 LmsMemListNode *node = OsLmsGetPoolNodeFromAddr(addrStart);
424 if (node != NULL) {
425 OsLmsSetShadowValue(node, addrStart, addrEnd, LMS_SHADOW_REDZONE_U8);
426 }
427 LMS_UNLOCK(intSave);
428}
429
431{
432 UINT32 intSave;
433 if (addrEnd <= addrStart) {
434 return;
435 }
436 LMS_LOCK(intSave);
437 LmsMemListNode *node = OsLmsGetPoolNodeFromAddr(addrStart);
438 if (node != NULL) {
439 OsLmsSetShadowValue(node, addrStart, addrEnd, LMS_SHADOW_ACCESSABLE_U8);
440 }
441 LMS_UNLOCK(intSave);
442}
443
445{
446 UINT32 intSave;
447 UINT32 shadowValue = INVALID_SHADOW_VALUE;
448 /* do not check nested or before all cpu start */
449 if ((LOS_AtomicRead(&g_checkDepth)) || (!OS_SCHEDULER_ALL_ACTIVE)) {
450 return 0;
451 }
452
453 LMS_LOCK(intSave);
455 if (node == NULL) {
456 LMS_UNLOCK(intSave);
457 return LMS_SHADOW_ACCESSABLE_U8;
458 }
459
460 OsLmsGetShadowValue(node, addr, &shadowValue);
461 LMS_UNLOCK(intSave);
462 return shadowValue;
463}
464
465#ifdef LOSCFG_LMS_CHECK_STRICT
466STATIC INLINE UINT32 OsLmsCheckAddrRegion(UINTPTR addr, UINT32 size)
467{
468 UINT32 i;
469 for (i = 0; i < size; i++) {
470 if (OsLmsCheckAddr(addr + i)) {
471 return LOS_NOK;
472 }
473 }
474 return LOS_OK;
475}
476
477#else
478STATIC INLINE UINT32 OsLmsCheckAddrRegion(UINTPTR addr, UINT32 size)
479{
480 if (OsLmsCheckAddr(addr) || OsLmsCheckAddr(addr + size - 1)) {
481 return LOS_NOK;
482 } else {
483 return LOS_OK;
484 }
485}
486#endif
487
489{
490 UINT32 count = 0;
491 UINT32 intSave;
492 LmsMemListNode *current = NULL;
493 LOS_DL_LIST *listHead = &g_lmsCheckPoolList;
494
495 LMS_LOCK(intSave);
496 LOS_DL_LIST_FOR_EACH_ENTRY(current, listHead, LmsMemListNode, node)
497 {
498 count++;
499 PRINT_DEBUG(
500 "[LMS]memory pool[%1u]: totalsize 0x%-8x memstart 0x%-8x memstop 0x%-8x memsize 0x%-8x shadowstart 0x%-8x "
501 "shadowSize 0x%-8x\n",
502 count, current->poolSize + current->shadowSize, current->poolAddr, current->poolAddr + current->poolSize,
503 current->poolSize, current->shadowStart, current->shadowSize);
504 }
505
506 LMS_UNLOCK(intSave);
507}
508
510{
511#define LMS_DUMP_OFFSET 16
512#define LMS_DUMP_RANGE_DOUBLE 2
513
514 PRINTK("\n[LMS] Dump info around address [0x%8x]:\n", addr);
515 const UINT32 printY = LMS_DUMP_OFFSET * LMS_DUMP_RANGE_DOUBLE + 1;
516 const UINT32 printX = LMS_MEM_BYTES_PER_SHADOW_CELL * LMS_DUMP_RANGE_DOUBLE;
517 UINTPTR dumpAddr = addr - addr % printX - LMS_DUMP_OFFSET * printX;
518 UINT32 shadowValue = 0;
519 UINTPTR shadowAddr = 0;
520 UINT32 shadowOffset = 0;
521 LmsMemListNode *nodeInfo = NULL;
522 INT32 isCheckAddr, x, y;
523
524 nodeInfo = OsLmsGetPoolNodeFromAddr(addr);
525 if (nodeInfo == NULL) {
526 PRINT_ERR("[LMS]addr is not in checkpool\n");
527 return;
528 }
529
530 for (y = 0; y < printY; y++, dumpAddr += printX) {
531 if (dumpAddr < nodeInfo->poolAddr) { /* find util dumpAddr in pool region */
532 continue;
533 }
534
535 if ((dumpAddr + printX) >=
536 nodeInfo->poolAddr + nodeInfo->poolSize) { /* finish if dumpAddr exceeds pool's upper region */
537 goto END;
538 }
539
540 PRINTK("\n\t[0x%x]: ", dumpAddr);
541 for (x = 0; x < printX; x++) {
542 if ((dumpAddr + x) == addr) {
543 PRINTK("[%02x]", *(UINT8 *)(dumpAddr + x));
544 } else {
545 PRINTK(" %02x ", *(UINT8 *)(dumpAddr + x));
546 }
547 }
548
549 if (OsLmsMem2Shadow(nodeInfo, dumpAddr, &shadowAddr, &shadowOffset) != LOS_OK) {
550 goto END;
551 }
552
553 PRINTK("|\t[0x%x | %2u]: ", shadowAddr, shadowOffset);
554
555 for (x = 0; x < printX; x += LMS_MEM_BYTES_PER_SHADOW_CELL) {
556 OsLmsGetShadowValue(nodeInfo, dumpAddr + x, &shadowValue);
557 isCheckAddr = dumpAddr + x - (UINTPTR)addr + LMS_MEM_BYTES_PER_SHADOW_CELL;
558 if ((isCheckAddr > 0) && (isCheckAddr <= LMS_MEM_BYTES_PER_SHADOW_CELL)) {
559 PRINTK("[%1x]", shadowValue);
560 } else {
561 PRINTK(" %1x ", shadowValue);
562 }
563 }
564 }
565END:
566 PRINTK("\n");
567}
568
569STATIC VOID OsLmsGetErrorInfo(UINTPTR addr, UINT32 size, LmsAddrInfo *info)
570{
572 OsLmsGetShadowInfo(node, addr, info);
573 if (info->shadowValue != LMS_SHADOW_ACCESSABLE_U8) {
574 return;
575 } else {
576 OsLmsGetShadowInfo(node, addr + size - 1, info);
577 }
578}
579
580STATIC VOID OsLmsPrintErrInfo(LmsAddrInfo *info, UINT32 errMod)
581{
582 switch (info->shadowValue) {
583 case LMS_SHADOW_AFTERFREE:
584 PRINT_ERR("Use after free error detected\n");
585 break;
586 case LMS_SHADOW_REDZONE:
587 PRINT_ERR("Heap buffer overflow error detected\n");
588 break;
589 case LMS_SHADOW_ACCESSABLE:
590 PRINT_ERR("No error\n");
591 break;
592 default:
593 PRINT_ERR("UnKnown Error detected\n");
594 break;
595 }
596
597 switch (errMod) {
598 case FREE_ERRORMODE:
599 PRINT_ERR("Illegal Double free address at: [0x%lx]\n", info->memAddr);
600 break;
601 case LOAD_ERRMODE:
602 PRINT_ERR("Illegal READ address at: [0x%lx]\n", info->memAddr);
603 break;
604 case STORE_ERRMODE:
605 PRINT_ERR("Illegal WRITE address at: [0x%lx]\n", info->memAddr);
606 break;
607 case COMMON_ERRMODE:
608 PRINT_ERR("Common Error at: [0x%lx]\n", info->memAddr);
609 break;
610 default:
611 PRINT_ERR("UnKnown Error mode at: [0x%lx]\n", info->memAddr);
612 break;
613 }
614
615 PRINT_ERR("Shadow memory address: [0x%lx : %1u] Shadow memory value: [%u] \n", info->shadowAddr,
616 info->shadowOffset, info->shadowValue);
617}
618
620{
621 UINT32 intSave;
622 LmsAddrInfo info;
623
624 (VOID)LOS_AtomicAdd(&g_checkDepth, 1);
625 LMS_LOCK(intSave);
626 (VOID)memset(&info, 0, sizeof(LmsAddrInfo));
627
628 PRINT_ERR("***** Kernel Address Sanitizer Error Detected Start *****\n");
629
630 OsLmsGetErrorInfo(p, size, &info);
631
632 OsLmsPrintErrInfo(&info, errMod);
633
634 OsBackTrace();
635
637 LMS_UNLOCK(intSave);
638 PRINT_ERR("***** Kernel Address Sanitizer Error Detected End *****\n");
639 (VOID)LOS_AtomicSub(&g_checkDepth, 1);
640}
641
642#ifdef LOSCFG_LMS_STORE_CHECK
644{
645 if (OsLmsCheckAddr(p) != LMS_SHADOW_ACCESSABLE_U8) {
646 OsLmsReportError(p, MEM_REGION_SIZE_1, STORE_ERRMODE);
647 }
648}
649
651{
652 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_2) != LOS_OK) {
653 OsLmsReportError(p, MEM_REGION_SIZE_2, STORE_ERRMODE);
654 }
655}
656
658{
659 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_4) != LOS_OK) {
660 OsLmsReportError(p, MEM_REGION_SIZE_4, STORE_ERRMODE);
661 }
662}
663
665{
666 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_8) != LOS_OK) {
667 OsLmsReportError(p, MEM_REGION_SIZE_8, STORE_ERRMODE);
668 }
669}
670
672{
673 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_16) != LOS_OK) {
674 OsLmsReportError(p, MEM_REGION_SIZE_16, STORE_ERRMODE);
675 }
676}
677
679{
680 if (OsLmsCheckAddrRegion(p, size) != LOS_OK) {
681 OsLmsReportError(p, size, STORE_ERRMODE);
682 }
683}
684#else
686{
687 (VOID)p;
688}
689
691{
692 (VOID)p;
693}
694
696{
697 (VOID)p;
698}
699
701{
702 (VOID)p;
703}
704
706{
707 (VOID)p;
708}
709
711{
712 (VOID)p;
713 (VOID)size;
714}
715
716#endif
717
718#ifdef LOSCFG_LMS_LOAD_CHECK
720{
721 if (OsLmsCheckAddr(p) != LMS_SHADOW_ACCESSABLE_U8) {
722 OsLmsReportError(p, MEM_REGION_SIZE_1, LOAD_ERRMODE);
723 }
724}
725
727{
728 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_2) != LOS_OK) {
729 OsLmsReportError(p, MEM_REGION_SIZE_2, LOAD_ERRMODE);
730 }
731}
732
734{
735 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_4) != LOS_OK) {
736 OsLmsReportError(p, MEM_REGION_SIZE_4, LOAD_ERRMODE);
737 }
738}
739
741{
742 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_8) != LOS_OK) {
743 OsLmsReportError(p, MEM_REGION_SIZE_8, LOAD_ERRMODE);
744 }
745}
746
748{
749 if (OsLmsCheckAddrRegion(p, MEM_REGION_SIZE_16) != LOS_OK) {
750 OsLmsReportError(p, MEM_REGION_SIZE_16, LOAD_ERRMODE);
751 }
752}
753
755{
756 if (OsLmsCheckAddrRegion(p, size) != LOS_OK) {
757 OsLmsReportError(p, size, LOAD_ERRMODE);
758 }
759}
760#else
762{
763 (VOID)p;
764}
765
767{
768 (VOID)p;
769}
770
772{
773 (VOID)p;
774}
775
777{
778 (VOID)p;
779}
780
782{
783 (VOID)p;
784}
785
787{
788 (VOID)p;
789 (VOID)size;
790}
791#endif
793{
794 return;
795}
796
797LOS_MODULE_INIT(OsLmsInit, LOS_INIT_LEVEL_KMOD_PREVM);
STATIC INLINE INT32 LOS_AtomicRead(const Atomic *v)
Atomic read. | 读取32bit原子数据
Definition: los_atomic.h:123
STATIC INLINE INT32 LOS_AtomicAdd(Atomic *v, INT32 addVal)
Atomic addition.
Definition: los_atomic.h:173
STATIC INLINE INT32 LOS_AtomicSub(Atomic *v, INT32 subVal)
Atomic subtraction.
Definition: los_atomic.h:217
VOID OsBackTrace(VOID)
Kernel backtrace function.
Definition: los_exc.c:1025
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a new node to a doubly linked list.
Definition: los_list.h:217
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
Identify whether a specified doubly linked list is empty. | 判断链表是否为空
Definition: los_list.h:321
void * memset(void *addr, int c, size_t len)
Definition: lms_libc.c:36
原子操作 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-atomic....
volatile INT32 Atomic
Definition: los_atomic.h:102
STATIC VOID OsLmsPrintErrInfo(LmsAddrInfo *info, UINT32 errMod)
Definition: los_lms.c:580
STATIC INLINE UINT32 OsLmsMem2Shadow(LmsMemListNode *node, UINTPTR memAddr, UINTPTR *shadowAddr, UINT32 *shadowOffset)
Definition: los_lms.c:223
STATIC INLINE UINT32 OsLmsCheckAddrRegion(UINTPTR addr, UINT32 size)
Definition: los_lms.c:466
VOID __asan_load2_noabort(UINTPTR p)
Definition: los_lms.c:726
VOID __asan_store16_noabort(UINTPTR p)
Definition: los_lms.c:671
STATIC UINT32 OsLmsInit(VOID)
初始化 LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具
Definition: los_lms.c:208
VOID __asan_store4_noabort(UINTPTR p)
Definition: los_lms.c:657
LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_lmsCheckPoolList
Definition: los_lms.c:66
VOID OsLmsPrintMemInfo(UINTPTR addr)
Definition: los_lms.c:509
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_lmsSpin)
VOID __asan_loadN_noabort(UINTPTR p, UINT32 size)
Definition: los_lms.c:754
VOID __asan_load8_noabort(UINTPTR p)
Definition: los_lms.c:740
STATIC Atomic g_checkDepth
Definition: los_lms.c:67
VOID __asan_store1_noabort(UINTPTR p)
Definition: los_lms.c:643
VOID __asan_storeN_noabort(UINTPTR p, UINT32 size)
Definition: los_lms.c:678
VOID __asan_store2_noabort(UINTPTR p)
Definition: los_lms.c:650
STATIC UINT32 OsLmsPoolResize(UINT32 size)
Definition: los_lms.c:81
STATIC UINT32 OsLmsCheckAddr(UINTPTR addr)
Definition: los_lms.c:444
STATIC LmsMemListNode * OsLmsGetPoolNode(const VOID *pool)
Definition: los_lms.c:86
LmsHook * g_lms
Definition: los_lms.c:68
VOID __asan_load16_noabort(UINTPTR p)
Definition: los_lms.c:747
VOID __asan_handle_no_return(VOID)
Definition: los_lms.c:792
UINT32 LOS_LmsCheckPoolAdd(const VOID *pool, UINT32 size)
Definition: los_lms.c:141
STATIC LmsMemListNode * OsLmsGetPoolNodeFromAddr(UINTPTR addr)
Definition: los_lms.c:106
VOID OsLmsCheckValid(UINTPTR checkAddr, BOOL isFreeCheck)
Definition: los_lms.c:362
VOID LOS_LmsCheckPoolDel(const VOID *pool)
Definition: los_lms.c:189
VOID OsLmsLosFreeMark(const VOID *curNodeStart, const VOID *nextNodeStart, UINT32 nodeHeadSize)
Definition: los_lms.c:382
VOID LOS_LmsAddrProtect(UINTPTR addrStart, UINTPTR addrEnd)
Definition: los_lms.c:416
STATIC LmsMemListNode * OsLmsCheckPoolCreate(VOID)
Definition: los_lms.c:125
VOID OsLmsReportError(UINTPTR p, UINT32 size, UINT32 errMod)
Definition: los_lms.c:619
VOID OsLmsSimpleMark(UINTPTR startAddr, UINTPTR endAddr, UINT32 value)
Definition: los_lms.c:318
LOS_MODULE_INIT(OsLmsInit, LOS_INIT_LEVEL_KMOD_PREVM)
STATIC VOID OsLmsGetErrorInfo(UINTPTR addr, UINT32 size, LmsAddrInfo *info)
Definition: los_lms.c:569
VOID OsLmsGetShadowValue(LmsMemListNode *node, UINTPTR addr, UINT32 *shadowValue)
Definition: los_lms.c:307
VOID __asan_store8_noabort(UINTPTR p)
Definition: los_lms.c:664
LITE_OS_SEC_BSS STATIC LmsMemListNode g_lmsCheckPoolArray[LOSCFG_LMS_MAX_RECORD_POOL_NUM]
Definition: los_lms.c:65
VOID LOS_LmsAddrDisableProtect(UINTPTR addrStart, UINTPTR addrEnd)
Definition: los_lms.c:430
VOID __asan_load4_noabort(UINTPTR p)
Definition: los_lms.c:733
STATIC INLINE VOID OsLmsGetShadowInfo(LmsMemListNode *node, UINTPTR memAddr, LmsAddrInfo *info)
Definition: los_lms.c:238
VOID __asan_load1_noabort(UINTPTR p)
Definition: los_lms.c:719
VOID OsLmsSetShadowValue(LmsMemListNode *node, UINTPTR startAddr, UINTPTR endAddr, UINT8 value)
Definition: los_lms.c:255
VOID OsLmsPrintPoolListInfo(VOID)
Definition: los_lms.c:488
VOID OsLmsLosMallocMark(const VOID *curNodeStart, const VOID *nextNodeStart, UINT32 nodeHeadSize)
Definition: los_lms.c:343
signed int INT32
Definition: los_typedef.h:60
unsigned char UINT8
Definition: los_typedef.h:55
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
size_t BOOL
Definition: los_typedef.h:88
UINTPTR shadowAddr
Definition: los_lms_pri.h:91
UINT32 shadowOffset
Definition: los_lms_pri.h:92
UINT32 shadowValue
Definition: los_lms_pri.h:93
UINTPTR memAddr
Definition: los_lms_pri.h:90
UINT32(* init)(const VOID *pool, UINT32 size)
Definition: los_lms_pri.h:97
UINT32 shadowSize
Definition: los_lms_pri.h:86
UINTPTR shadowStart
Definition: los_lms_pri.h:85
LOS_DL_LIST node
Definition: los_lms_pri.h:81
UINTPTR poolAddr
Definition: los_lms_pri.h:83
UINT32 poolSize
Definition: los_lms_pri.h:84