feat: L0~L1 支持Lms

1.【需求描述】:
   支持内核态和用户态堆内存非法访问检测,包括:越界访问、double free、释放后使用;支持libc常用高频函数内存检测;支持安全函数内存检测;读写检测可配可裁剪。
2.【方案描述】:
   L0 ~ L1:
   (1).影子内存映射与标记
   (2).编译器使能-fsanitize=kernel-address 自动插桩检测点
   (3).实时校验影子内存的合法性;
   (4).错误访问打印回溯栈

BREAKING CHANGE: 新增支持API:

LOS_LmsCheckPoolAdd使能检测指定内存池
LOS_LmsCheckPoolDel不检测指定内存池
LOS_LmsAddrProtect为指定内存段上锁,不允许访问
LOS_LmsAddrDisableProtect去能指定内存段的访问保护

Close #I4HYAV

Signed-off-by: LiteOS2021 <dinglu@huawei.com>
Change-Id: Id8e5c890656da9edc4a22227e6a3c32205c024ce
This commit is contained in:
LiteOS2021
2021-11-27 09:56:51 +08:00
parent 48f645db84
commit e748fdbe57
26 changed files with 2695 additions and 21 deletions

View File

@@ -525,7 +525,9 @@ LITE_OS_SEC_TEXT VOID OsTaskResourcesToFree(LosTaskCB *taskCB)
OsTaskKernelResourcesToFree(syncSignal, topOfStack);
SCHEDULER_LOCK(intSave);
#ifdef LOSCFG_KERNEL_VM
OsClearSigInfoTmpList(&(taskCB->sig));
#endif
OsInsertTCBToFreeList(taskCB);
SCHEDULER_UNLOCK(intSave);
}

View File

@@ -88,6 +88,7 @@ STATIC INLINE VOID OsSchedIrqStartTime(VOID)
} while (0);
#define OS_SCHEDULER_ACTIVE (g_taskScheduled & (1U << ArchCurrCpuid()))
#define OS_SCHEDULER_ALL_ACTIVE (g_taskScheduled == LOSCFG_KERNEL_CPU_MASK)
typedef enum {
INT_NO_RESCH = 0x0, /* no needs to schedule */

View File

@@ -183,7 +183,14 @@ STATIC INLINE BOOL OsIsPageShared(LosVmPage *page)
return BIT_GET(page->flags, FILE_PAGE_SHARED);
}
typedef struct ProcessCB LosProcessCB;
#ifdef LOSCFG_FS_VFS
INT32 OsVfsFileMmap(struct file *filep, LosVmMapRegion *region);
STATUS_T OsNamedMMap(struct file *filep, LosVmMapRegion *region);
VOID OsVmmFileRegionFree(struct file *filep, LosProcessCB *processCB);
#endif
LosFilePage *OsPageCacheAlloc(struct page_mapping *mapping, VM_OFFSET_T pgoff);
LosFilePage *OsFindGetEntry(struct page_mapping *mapping, VM_OFFSET_T pgoff);
LosMapInfo *OsGetMapInfo(LosFilePage *page, LosArchMmu *archMmu, VADDR_T vaddr);
@@ -198,14 +205,11 @@ VOID OsLruCacheDel(LosFilePage *fpage);
LosFilePage *OsDumpDirtyPage(LosFilePage *oldPage);
VOID OsDoFlushDirtyPage(LosFilePage *fpage);
VOID OsDeletePageCacheLru(LosFilePage *page);
STATUS_T OsNamedMMap(struct file *filep, LosVmMapRegion *region);
VOID OsPageRefDecNoLock(LosFilePage *page);
VOID OsPageRefIncLocked(LosFilePage *page);
int OsTryShrinkMemory(size_t nPage);
VOID OsMarkPageDirty(LosFilePage *fpage, LosVmMapRegion *region, int off, int len);
typedef struct ProcessCB LosProcessCB;
VOID OsVmmFileRegionFree(struct file *filep, LosProcessCB *processCB);
#ifdef LOSCFG_DEBUG_VERSION
VOID ResetPageCacheHitInfo(int *try, int *hit);
struct file_map* GetFileMappingList(void);

View File

@@ -39,6 +39,10 @@
#include "los_task_pri.h"
#include "los_hook.h"
#ifdef LOSCFG_KERNEL_LMS
#include "los_lms_pri.h"
#endif
/* Used to cut non-essential functions. */
#define OS_MEM_FREE_BY_TASKID 0
#ifdef LOSCFG_KERNEL_VM
@@ -366,7 +370,9 @@ STATIC INLINE BOOL TryShrinkPool(const VOID *pool, const struct OsMemNodeHead *n
PRINT_ERR("TryShrinkPool free %#x failed!\n", node);
return FALSE;
}
#ifdef LOSCFG_KERNEL_LMS
LOS_LmsCheckPoolDel(node);
#endif
return TRUE;
}
@@ -394,13 +400,24 @@ RETRY:
PRINT_ERR("OsMemPoolExpand alloc failed size = %u\n", size);
return -1;
}
#ifdef LOSCFG_KERNEL_LMS
UINT32 resize = 0;
if (g_lms != NULL) {
/*
* resize == 0, shadow memory init failed, no shadow memory for this pool, set poolSize as original size.
* resize != 0, shadow memory init successful, set poolSize as resize.
*/
resize = g_lms->init(newNode, size);
size = (resize == 0) ? size : resize;
}
#endif
newNode->sizeAndFlag = (size - OS_MEM_NODE_HEAD_SIZE);
newNode->ptr.prev = OS_MEM_END_NODE(newNode, size);
OsMemSentinelNodeSet(endNode, newNode, size);
OsMemFreeNodeAdd(pool, (struct OsMemFreeNodeHead *)newNode);
endNode = OS_MEM_END_NODE(newNode, size);
(VOID)memset_s(endNode, sizeof(*endNode), 0, sizeof(*endNode));
(VOID)memset(endNode, 0, sizeof(*endNode));
endNode->ptr.next = NULL;
endNode->magic = OS_MEM_NODE_MAGIC;
OsMemSentinelNodeSet(endNode, NULL, 0);
@@ -441,6 +458,71 @@ VOID LOS_MemExpandEnable(VOID *pool)
}
#endif
#ifdef LOSCFG_KERNEL_LMS
STATIC INLINE VOID OsLmsFirstNodeMark(VOID *pool, struct OsMemNodeHead *node)
{
if (g_lms == NULL) {
return;
}
g_lms->simpleMark((UINTPTR)pool, (UINTPTR)node, LMS_SHADOW_PAINT_U8);
g_lms->simpleMark((UINTPTR)node, (UINTPTR)node + OS_MEM_NODE_HEAD_SIZE, LMS_SHADOW_REDZONE_U8);
g_lms->simpleMark((UINTPTR)OS_MEM_NEXT_NODE(node), (UINTPTR)OS_MEM_NEXT_NODE(node) + OS_MEM_NODE_HEAD_SIZE,
LMS_SHADOW_REDZONE_U8);
g_lms->simpleMark((UINTPTR)node + OS_MEM_NODE_HEAD_SIZE, (UINTPTR)OS_MEM_NEXT_NODE(node),
LMS_SHADOW_AFTERFREE_U8);
}
STATIC INLINE VOID OsLmsAllocAlignMark(VOID *ptr, VOID *alignedPtr, UINT32 size)
{
struct OsMemNodeHead *allocNode = NULL;
if ((g_lms == NULL) || (ptr == NULL)) {
return;
}
allocNode = (struct OsMemNodeHead *)((struct OsMemUsedNodeHead *)ptr - 1);
if (ptr != alignedPtr) {
g_lms->simpleMark((UINTPTR)ptr, (UINTPTR)ptr + sizeof(UINT32), LMS_SHADOW_PAINT_U8);
g_lms->simpleMark((UINTPTR)ptr + sizeof(UINT32), (UINTPTR)alignedPtr, LMS_SHADOW_REDZONE_U8);
}
/* mark remining as redzone */
g_lms->simpleMark(LMS_ADDR_ALIGN((UINTPTR)alignedPtr + size), (UINTPTR)OS_MEM_NEXT_NODE(allocNode),
LMS_SHADOW_REDZONE_U8);
}
STATIC INLINE VOID OsLmsReallocMergeNodeMark(struct OsMemNodeHead *node)
{
if (g_lms == NULL) {
return;
}
g_lms->simpleMark((UINTPTR)node + OS_MEM_NODE_HEAD_SIZE, (UINTPTR)OS_MEM_NEXT_NODE(node),
LMS_SHADOW_ACCESSABLE_U8);
}
STATIC INLINE VOID OsLmsReallocSplitNodeMark(struct OsMemNodeHead *node)
{
if (g_lms == NULL) {
return;
}
/* mark next node */
g_lms->simpleMark((UINTPTR)OS_MEM_NEXT_NODE(node),
(UINTPTR)OS_MEM_NEXT_NODE(node) + OS_MEM_NODE_HEAD_SIZE, LMS_SHADOW_REDZONE_U8);
g_lms->simpleMark((UINTPTR)OS_MEM_NEXT_NODE(node) + OS_MEM_NODE_HEAD_SIZE,
(UINTPTR)OS_MEM_NEXT_NODE(OS_MEM_NEXT_NODE(node)), LMS_SHADOW_AFTERFREE_U8);
}
STATIC INLINE VOID OsLmsReallocResizeMark(struct OsMemNodeHead *node, UINT32 resize)
{
if (g_lms == NULL) {
return;
}
/* mark remaining as redzone */
g_lms->simpleMark((UINTPTR)node + resize, (UINTPTR)OS_MEM_NEXT_NODE(node), LMS_SHADOW_REDZONE_U8);
}
#endif
#ifdef LOSCFG_MEM_LEAKCHECK
STATIC INLINE VOID OsMemLinkRegisterRecord(struct OsMemNodeHead *node)
{
@@ -738,6 +820,12 @@ STATIC INLINE VOID *OsMemCreateUsedNode(VOID *addr)
OsMemNodeSetTaskID(node);
#endif
#ifdef LOSCFG_KERNEL_LMS
struct OsMemNodeHead *newNode = (struct OsMemNodeHead *)node;
if (g_lms != NULL) {
g_lms->mallocMark(newNode, OS_MEM_NEXT_NODE(newNode), OS_MEM_NODE_HEAD_SIZE);
}
#endif
return node + 1;
}
@@ -746,8 +834,18 @@ STATIC UINT32 OsMemPoolInit(VOID *pool, UINT32 size)
struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool;
struct OsMemNodeHead *newNode = NULL;
struct OsMemNodeHead *endNode = NULL;
(VOID)memset_s(poolHead, sizeof(struct OsMemPoolHead), 0, sizeof(struct OsMemPoolHead));
#ifdef LOSCFG_KERNEL_LMS
UINT32 resize = 0;
if (g_lms != NULL) {
/*
* resize == 0, shadow memory init failed, no shadow memory for this pool, set poolSize as original size.
* resize != 0, shadow memory init successful, set poolSize as resize.
*/
resize = g_lms->init(pool, size);
size = (resize == 0) ? size : resize;
}
#endif
(VOID)memset(poolHead, 0, sizeof(struct OsMemPoolHead));
LOS_SpinInit(&poolHead->spinlock);
poolHead->info.pool = pool;
@@ -775,14 +873,18 @@ STATIC UINT32 OsMemPoolInit(VOID *pool, UINT32 size)
poolHead->info.curUsedSize = sizeof(struct OsMemPoolHead) + OS_MEM_NODE_HEAD_SIZE;
poolHead->info.waterLine = poolHead->info.curUsedSize;
#endif
#ifdef LOSCFG_KERNEL_LMS
if (resize != 0) {
OsLmsFirstNodeMark(pool, newNode);
}
#endif
return LOS_OK;
}
#ifdef LOSCFG_MEM_MUL_POOL
STATIC VOID OsMemPoolDeinit(VOID *pool)
{
(VOID)memset_s(pool, sizeof(struct OsMemPoolHead), 0, sizeof(struct OsMemPoolHead));
(VOID)memset(pool, 0, sizeof(struct OsMemPoolHead));
}
STATIC UINT32 OsMemPoolAdd(VOID *pool, UINT32 size)
@@ -1009,6 +1111,9 @@ VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
MEM_UNLOCK(poolHead, intSave);
alignedPtr = (VOID *)OS_MEM_ALIGN(ptr, boundary);
if (ptr == alignedPtr) {
#ifdef LOSCFG_KERNEL_LMS
OsLmsAllocAlignMark(ptr, alignedPtr, size);
#endif
break;
}
@@ -1018,6 +1123,9 @@ VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
OS_MEM_NODE_SET_ALIGNED_FLAG(allocNode->header.sizeAndFlag);
OS_MEM_NODE_SET_ALIGNED_FLAG(gapSize);
*(UINT32 *)((UINTPTR)alignedPtr - sizeof(gapSize)) = gapSize;
#ifdef LOSCFG_KERNEL_LMS
OsLmsAllocAlignMark(ptr, alignedPtr, size);
#endif
ptr = alignedPtr;
} while (0);
@@ -1141,6 +1249,13 @@ STATIC INLINE UINT32 OsMemFree(struct OsMemPoolHead *pool, struct OsMemNodeHead
node->sizeAndFlag = OS_MEM_NODE_GET_SIZE(node->sizeAndFlag);
#ifdef LOSCFG_MEM_LEAKCHECK
OsMemLinkRegisterRecord(node);
#endif
#ifdef LOSCFG_KERNEL_LMS
struct OsMemNodeHead *nextNodeBackup = OS_MEM_NEXT_NODE(node);
struct OsMemNodeHead *curNodeBackup = node;
if (g_lms != NULL) {
g_lms->check((UINTPTR)node + OS_MEM_NODE_HEAD_SIZE, TRUE);
}
#endif
struct OsMemNodeHead *preNode = node->ptr.prev; /* merage preNode */
if ((preNode != NULL) && !OS_MEM_NODE_GET_USED_FLAG(preNode->sizeAndFlag)) {
@@ -1166,7 +1281,11 @@ STATIC INLINE UINT32 OsMemFree(struct OsMemPoolHead *pool, struct OsMemNodeHead
}
#endif
OsMemFreeNodeAdd(pool, (struct OsMemFreeNodeHead *)node);
#ifdef LOSCFG_KERNEL_LMS
if (g_lms != NULL) {
g_lms->freeMark(curNodeBackup, nextNodeBackup, OS_MEM_NODE_HEAD_SIZE);
}
#endif
return ret;
}
@@ -1219,6 +1338,11 @@ STATIC INLINE VOID OsMemReAllocSmaller(VOID *pool, UINT32 allocSize, struct OsMe
OS_MEM_NODE_SET_USED_FLAG(node->sizeAndFlag);
#ifdef LOSCFG_MEM_WATERLINE
poolInfo->info.curUsedSize -= nodeSize - allocSize;
#endif
#ifdef LOSCFG_KERNEL_LMS
OsLmsReallocSplitNodeMark(node);
} else {
OsLmsReallocResizeMark(node, allocSize);
#endif
}
OS_MEM_NODE_SET_USED_FLAG(node->sizeAndFlag);
@@ -1233,8 +1357,16 @@ STATIC INLINE VOID OsMemMergeNodeForReAllocBigger(VOID *pool, UINT32 allocSize,
node->sizeAndFlag = nodeSize;
OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)nextNode);
OsMemMergeNode(nextNode);
#ifdef LOSCFG_KERNEL_LMS
OsLmsReallocMergeNodeMark(node);
#endif
if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_MIN_ALLOC_SIZE) <= node->sizeAndFlag) {
OsMemSplitNode(pool, node, allocSize);
#ifdef LOSCFG_KERNEL_LMS
OsLmsReallocSplitNodeMark(node);
} else {
OsLmsReallocResizeMark(node, allocSize);
#endif
}
OS_MEM_NODE_SET_USED_FLAG(node->sizeAndFlag);
OsMemWaterUsedRecord((struct OsMemPoolHead *)pool, node->sizeAndFlag - nodeSize);
@@ -1757,7 +1889,7 @@ UINT32 LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *poolStatus)
return LOS_NOK;
}
(VOID)memset_s(poolStatus, sizeof(LOS_MEM_POOL_STATUS), 0, sizeof(LOS_MEM_POOL_STATUS));
(VOID)memset(poolStatus, 0, sizeof(LOS_MEM_POOL_STATUS));
struct OsMemNodeHead *tmpNode = NULL;
struct OsMemNodeHead *endNode = NULL;