1# LMS 2 3 4## Basic Concepts 5 6Lite Memory Sanitizer (LMS) is a tool used to detect memory errors on a real-time basis. LMS can detect buffer overflow, Use-After-Free (UAF), and double free errors in real time, and notify the operating system immediately. Together with locating methods such as Backtrace, LMS can locate the code line that causes the memory error. It greatly improves the efficiency of locating memory errors. 7 8The LMS module of the OpenHarmony LiteOS-A kernel provides the following functions: 9 10- Supports check of multiple memory pools. 11 12- Checks the memory allocated by **LOS_MemAlloc**, **LOS_MemAllocAlign**, and **LOS_MemRealloc**. 13 14- Checks the memory when bounds-checking functions are called (enabled by default). 15 16- Checks the memory when libc frequently accessed functions, including **memset**, **memcpy**, **memmove**, **strcat**, **strcpy**, **strncat** and **strncpy**, are called. 17 18 19## Working Principles 20 21LMS uses shadow memory mapping to mark the system memory state. There are three states: **Accessible**, **RedZone**, and **Freed**. The shadow memory is located in the tail of the memory pool. 22 23- After memory is allocated from the heap, the shadow memory in the data area is set to the **Accessible** state, and the shadow memory in the head node area is set to the **RedZone** state. 24 25- When memory is released from the heap, the shadow memory of the released memory is set to the **Freed** state. 26 27- During code compilation, a function is inserted before the read/write instructions in the code to check the address validity. The tool checks the state value of the shadow memory that accesses the memory. If the shadow memory is in the **RedZone** statue, an overflow error will be reported. If the shadow memory is in the **Freed** state, a UAF error will be reported. 28 29- When memory is released, the tool checks the state value of the shadow memory at the released address. If the shadow memory is in the **RedZone** state, a double free error will be reported. 30 31 32## Available APIs 33 34 35### Kernel Mode 36 37The LMS module of the OpenHarmony LiteOS-A kernel provides the following APIs. For more details, see [API reference](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_lms.h). 38 39 **Table 1** APIs of the LMS module 40 41| Category| API| Description| 42| -------- | -------- | -------- | 43| Adding a memory pool to be checked| LOS_LmsCheckPoolAdd | Adds the address range of a memory pool to the LMS check linked list. LMS performs a validity check when the accessed address is within the linked list. In addition, **LOS_MemInit** calls this API to add the initialized memory pool to the LMS check linked list by default.| 44| Deleting a memory pool from the LMS check linked list| LOS_LmsCheckPoolDel | Cancels the validity check on the specified memory pool.| 45| Protecting a specified memory chunk| LOS_LmsAddrProtect | Locks a memory chunk to prevent it from being read or written. Once the locked memory chunk is accessed, an error will be reported.| 46| Disabling protection of a specified memory chunk| LOS_LmsAddrDisableProtect | Unlocks a memory chunk to make it readable and writable.| 47 48 49### User Mode 50 51The user mode provides only the LMS check library. It does not provide external APIs. 52 53 54## Development Guidelines 55 56 57### Kernel-Mode Development Process 58 59The typical process for enabling LMS is as follows: 60 611. Configure the macros related to the LMS module. 62 Configure the LMS macro **LOSCFG_KERNEL_LMS**, which is disabled by default. Run the **make update_config** command in the **kernel/liteos_a** directory, choose **Kernel**, and select **Enable Lite Memory Sanitizer**. 63 64 | Macro| menuconfig Option| Description| Value | 65 | -------- | -------- | -------- | -------- | 66 | LOSCFG_KERNEL_LMS | Enable Lms Feature | Whether to enable LMS.| YES/NO | 67 | LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | Maximum number of memory pools that can be checked by LMS.| INT | 68 | LOSCFG_LMS_LOAD_CHECK | Enable lms read check | Whether to enable LMS read check.| YES/NO | 69 | LOSCFG_LMS_STORE_CHECK | Enable lms write check | Whether to enable LMS write check.| YES/NO | 70 | LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | Whether to enable LMS byte-by-byte check.| YES/NO | 71 722. Modify the build script of the target module. 73 Add **-fsanitize=kernel-address** to insert memory access checks, and add the **-O0** option to disable optimization performed by the compiler. 74 75 The modifications vary depending on the compiler (GCC or Clang) used. The following is an example: 76 77 ``` 78 if ("$ohos_build_compiler_specified" == "gcc") { 79 cflags_c = [ 80 "-O0", 81 "-fsanitize=kernel-address", 82 ] 83 } else { 84 cflags_c = [ 85 "-O0", 86 "-fsanitize=kernel-address", 87 "-mllvm", 88 "-asan-instrumentation-with-call-threshold=0", 89 "-mllvm", 90 "-asan-stack=0", 91 "-mllvm", 92 "-asan-globals=0", 93 ] 94 } 95 ``` 96 973. Recompile the code and check the serial port output. The memory problem detected will be displayed. 98 99 100#### Kernel-Mode Development Example 101 102This example implements the following: 103 1041. Create a task for LMS. 105 1062. Construct a buffer overflow error and a UAF error. 107 1083. Add "-fsanitize=kernel-address", execute the compilation, and check the output. 109 110 111#### Kernel-Mode Sample Code 112 113The functions of the sample code can be added to **TestTaskEntry** in **kernel /liteos_a/testsuites /kernel /src /osTest.c** for testing. 114The sample code is as follows: 115 116```c 117#define PAGE_SIZE (0x1000U) 118#define INDEX_MAX 20 119UINT32 g_lmsTestTaskId; 120char g_testLmsPool[2 * PAGE_SIZE]; 121STATIC VOID testPoolInit(void) 122{ 123 UINT32 ret = LOS_MemInit(g_testLmsPool, 2 * PAGE_SIZE); 124 if (ret != 0) { 125 PRINT_ERR("%s failed, ret = 0x%x\n", __FUNCTION__, ret); 126 return; 127 } 128} 129static VOID LmsTestOsmallocOverflow(VOID) 130{ 131 PRINTK("\n######%s start ######\n", __FUNCTION__); 132 UINT32 i; 133 CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX); 134 PRINTK("str[%2d]=0x%2x ", INDEX_MAX, str[INDEX_MAX]); /* trigger heap overflow at str[INDEX_MAX] */ 135 PRINTK("\n######%s stop ######\n", __FUNCTION__); 136} 137static VOID LmsTestUseAfterFree(VOID) 138{ 139 PRINTK("\n######%s start ######\n", __FUNCTION__); 140 UINT32 i; 141 CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX); 142 (VOID)LOS_MemFree(g_testLmsPool, str); 143 PRINTK("str[%2d]=0x%2x ", 0, str[0]); /* trigger use after free at str[0] */ 144 PRINTK("\n######%s stop ######\n", __FUNCTION__); 145} 146VOID LmsTestCaseTask(VOID) 147{ 148 testPoolInit(); 149 LmsTestOsmallocOverflow(); 150 LmsTestUseAfterFree(); 151} 152UINT32 Example_Lms_test(VOID) 153{ 154 UINT32 ret; 155 TSK_INIT_PARAM_S lmsTestTask; 156 /* Create a task for LMS. */ 157 memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S)); 158 lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask; 159 lmsTestTask.pcName = "TestLmsTsk"; /* Test task name. */ 160 lmsTestTask.uwStackSize = 0x800; // 0x800: LMS test task stack size 161 lmsTestTask.usTaskPrio = 5; // 5: LMS test task priority 162 lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED; 163 ret = LOS_TaskCreate(&g_lmsTestTaskId, &lmsTestTask); 164 if (ret != LOS_OK) { 165 PRINT_ERR("LmsTestTask create failed .\n"); 166 return LOS_NOK; 167 } 168 return LOS_OK; 169} 170LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED); 171``` 172 173 174#### Kernel-Mode Verification 175 176 The output is as follows: 177 178``` 179######LmsTestOsmallocOverflow start ###### 180[ERR][KProcess:LmsTestCaseTask]* Kernel Address Sanitizer Error Detected Start * 181[ERR][KProcess:LmsTestCaseTask]Heap buffer overflow error detected 182[ERR][KProcess:LmsTestCaseTask]Illegal READ address at: [0x4157a3c8] 183[ERR][KProcess:LmsTestCaseTask]Shadow memory address: [0x4157be3c : 4] Shadow memory value: [2] 184OsBackTrace fp = 0x402c0f88 185runTask->taskName = LmsTestCaseTask 186runTask->taskID = 2 187***backtrace begin*** 188traceback fp fixed, trace using fp = 0x402c0fd0 189traceback 0 -- lr = 0x400655a4 fp = 0x402c0ff8 190traceback 1 -- lr = 0x40065754 fp = 0x402c1010 191traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038 192traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca 193[LMS] Dump info around address [0x4157a3c8]: 194 [0x4157a3a0]: 00 00 00 00 00 00 00 00 | [0x4157be3a | 0]: 1 1 195 [0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2 196 [0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0 197 [0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0 198 [0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0 199 [0x4157a3c8]: [ba] dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: [2] 2 200 [0x4157a3d0]: 2c 1a 00 00 00 00 00 00 | [0x4157be3d | 0]: 2 3 201 [0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3 202 [0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3 203 [0x4157a3e8]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 4]: 3 3 204 [0x4157a3f0]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 0]: 3 3 205[ERR][KProcess:LmsTestCaseTask]* Kernel Address Sanitizer Error Detected End * 206str[20]=0xffffffba 207######LmsTestOsmallocOverflow stop ###### 208###### LmsTestUseAfterFree start ###### 209[ERR][KProcess:LmsTestCaseTask]* Kernel Address Sanitizer Error Detected Start * 210[ERR][KProcess:LmsTestCaseTask]Use after free error detected 211[ERR][KProcess:LmsTestCaseTask]Illegal READ address at: [0x4157a3d4] 212[ERR][KProcess:LmsTestCaseTask]Shadow memory address: [0x4157be3d : 2] Shadow memory value: [3] 213OsBackTrace fp = 0x402c0f90 214runTask->taskName = LmsTestCaseTask 215runTask->taskID = 2 216***backtrace begin*** 217traceback fp fixed, trace using fp = 0x402c0fd8 218traceback 0 -- lr = 0x40065680 fp = 0x402c0ff8 219traceback 1 -- lr = 0x40065758 fp = 0x402c1010 220traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038 221traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca 222[LMS] Dump info around address [0x4157a3d4]: 223 [0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2 224 [0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0 225 [0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0 226 [0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0 227 [0x4157a3c8]: ba dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: 2 2 228 [0x4157a3d0]: 2c 1a 00 00 [00] 00 00 00 | [0x4157be3d | 0]: 2 [3] 229 [0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3 230 [0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3 231 [0x4157a3e8]: ba dc cd ab c8 a3 57 41 | [0x4157be3e | 4]: 2 2 232 [0x4157a3f0]: 0c 1a 00 00 00 00 00 00 | [0x4157be3f | 0]: 2 3 233 [0x4157a3f8]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 4]: 3 3 234[ERR][KProcess:LmsTestCaseTask]* Kernel Address Sanitizer Error Detected End * 235str[ 0]=0x 0 236######LmsTestUseAfterFree stop ###### 237``` 238 239The key output information is as follows: 240 241- Error type: 242 - Heap buffer overflow 243 - UAF 244 245- Incorrect operations: 246 - Illegal read 247 - Illegal write 248 - Illegal double free 249 250- Context: 251 - Task information (**taskName** and **taskId**) 252 - Backtrace 253 254- Memory information of the error addresses: 255 - Memory value and the value of the corresponding shadow memory 256 - Memory address: memory value|[shadow memory address|shadow memory byte offset]: shadow memory value 257 - Shadow memory value. **0** (Accessible), **3** (Freed), **2** (RedZone), and **1** (filled value) 258 259 260### User-Mode Development Process 261 262Add the following to the app build script to be checked. For details about the sample code, see [/kernel/liteos_a/apps/lms/BUILD.gn](https://gitee.com/openharmony/kernel_liteos_a/blob/master/apps/lms/BUILD.gn). 263 264 265``` 266if ("$ohos_build_compiler_specified" == "gcc") { 267 cflags_c = [ 268 "-O0", 269 "-fsanitize=kernel-address", 270 "-funwind-tables", 271 "-fasynchronous-unwind-tables", 272 ] 273 } else { 274 cflags_c = [ 275 "-O0", 276 "-fsanitize=kernel-address", 277 "-mllvm", 278 "-asan-instrumentation-with-call-threshold=0", 279 "-mllvm", 280 "-asan-stack=0", 281 "-mllvm", 282 "-asan-globals=0", 283 "-funwind-tables", 284 "-fasynchronous-unwind-tables", 285 ] 286 } 287 ldflags = [ 288 "-rdynamic", 289 "-lunwind", 290 "-lusrlms", 291 "-Wl,--wrap=realloc", 292 "-Wl,--wrap=calloc", 293 "-Wl,--wrap=malloc", 294 "-Wl,--wrap=free", 295 "-Wl,--wrap=valloc", 296 "-Wl,--wrap=aligned_alloc", 297 "-Wl,--wrap=memset", 298 "-Wl,--wrap=memcpy", 299 "-Wl,--wrap=memmove", 300 "-Wl,--wrap=strcpy", 301 "-Wl,--wrap=strcat", 302 ] 303 deps = [ "//kernel/liteos_a/kernel/extended/lms/usr:usrlmslib" ] 304``` 305 306 307#### User-Mode Development Example 308 309This example implements the following: 310 3111. Construct a buffer overflow error and a UAF error. 312 3132. Modify the build script and perform the build again. 314 315 316#### User-Mode Sample Code 317 318 The code is as follows: 319 320```c 321static void BufWriteTest(void *buf, int start, int end) 322{ 323 for (int i = start; i <= end; i++) { 324 ((char *)buf)[i] = 'a'; 325 } 326} 327static void BufReadTest(void *buf, int start, int end) 328{ 329 char tmp; 330 for (int i = start; i <= end; i++) { 331 tmp = ((char *)buf)[i]; 332 } 333} 334static void LmsMallocTest(void) 335{ 336 printf("\n-------- LmsMallocTest Start --------\n"); 337 char *buf = (char *)malloc(16); // 16: buffer size for test 338 BufReadTest(buf, -1, 16); 339 free(buf); 340 printf("\n-------- LmsMallocTest End --------\n"); 341} 342static void LmsFreeTest(void) 343{ 344 printf("\n-------- LmsFreeTest Start --------\n"); 345 char *buf = (char *)malloc(16); // 16: buffer size for test 346 free(buf); 347 BufReadTest(buf, 1, 1); 348 free(buf); 349 printf("\n-------- LmsFreeTest End --------\n"); 350} 351int main(int argc, char * const * argv) 352{ 353 printf("\n############### Lms Test start ###############\n"); 354 char *tmp = (char *)malloc(5000); // 5000: temp buffer size 355 LmsMallocTest(); 356 LmsFreeTest(); 357 printf("\n############### Lms Test End ###############\n"); 358} 359``` 360 361 362#### User-Mode Verification 363 364 The output is as follows: 365 366``` 367* Lite Memory Sanitizer Error Detected * 368Heap buffer overflow error detected! 369Illegal READ address at: [0x1f8b3edf] 370Shadow memory address: [0x3d34d3ed : 6] Shadow memory value: [2] 371Accessible heap addr 0 372Heap red zone 2 373Heap freed buffer 3 374Dump info around address [0x1f8b3edf]: 375 [0x1f8b3eb8]: 74 55 8b 1f 74 55 8b 1f | [0x3d34d3eb | 4]: 0 0 376 [0x1f8b3ec0]: f8 9c 8b 1f 00 00 00 00 | [0x3d34d3ec | 0]: 0 0 377 [0x1f8b3ec8]: 00 00 00 00 9c fc fc fc | [0x3d34d3ec | 4]: 0 0 378 [0x1f8b3ed0]: 21 00 00 00 41 00 00 00 | [0x3d34d3ed | 0]: 0 0 379 [0x1f8b3ed8]: 60 55 8b 1f 60 55 8b [1f]| [0x3d34d3ed | 4]: 2 [2] 380 [0x1f8b3ee0]: 50 4e 0b 00 00 00 00 00 | [0x3d34d3ee | 0]: 0 0 381 [0x1f8b3ee8]: 09 00 00 00 00 00 00 00 | [0x3d34d3ee | 4]: 0 0 382 [0x1f8b3ef0]: 00 00 00 00 08 03 09 00 | [0x3d34d3ef | 0]: 2 2 383 [0x1f8b3ef8]: 00 00 00 00 00 00 00 00 | [0x3d34d3ef | 4]: 2 2 384* Lite Memory Sanitizer Error Detected End * 385Backtrace() returned 5 addresses 386 #01: <LMS_ReportError+0x284>[0x4d6c] -> ./sample_usr_lms 387 #02: <(null)+0x2004074>[0x4074] -> ./sample_usr_lms 388 #03: <(null)+0x2003714>[0x3714] -> ./sample_usr_lms 389 #04: <main+0x40>[0x363c] -> ./sample_usr_lms 390 #05: <(null)+0x1f856f30>[0x56f30] -> /lib/libc.so 391-------- LMS_malloc_test End -------- 392* Lite Memory Sanitizer Error Detected * 393Use after free error detected! 394Illegal Double free address at: [0x1f8b3ee0] 395Shadow memory address: [0x3d34d3ee : 0] Shadow memory value: [3] 396Accessible heap addr 0 397Heap red zone 2 398Heap freed buffer 3 399Dump info around address [0x1f8b3ee0]: 400 [0x1f8b3ec0]: f8 9c 8b 1f 00 00 00 00 | [0x3d34d3ec | 0]: 0 0 401 [0x1f8b3ec8]: 00 00 00 00 fc fd fc fc | [0x3d34d3ec | 4]: 0 0 402 [0x1f8b3ed0]: 21 00 00 00 20 01 00 00 | [0x3d34d3ed | 0]: 0 0 403 [0x1f8b3ed8]: 60 55 8b 1f 60 55 8b 1f | [0x3d34d3ed | 4]: 2 2 404 [0x1f8b3ee0]: [20] 60 9a 1f 40 61 9a 1f | [0x3d34d3ee | 0]: [3] 3 405 [0x1f8b3ee8]: 60 62 9a 1f 80 63 9a 1f | [0x3d34d3ee | 4]: 3 3 406 [0x1f8b3ef0]: 20 40 8b 1f 20 20 8b 1f | [0x3d34d3ef | 0]: 3 3 407 [0x1f8b3ef8]: 00 00 00 00 00 00 00 00 | [0x3d34d3ef | 4]: 3 3 408 [0x1f8b3f00]: 00 00 00 00 00 00 00 00 | [0x3d34d3f0 | 0]: 3 3 409* Lite Memory Sanitizer Error Detected End * 410Backtrace() returned 5 addresses 411 #01: <LMS_ReportError+0x284>[0x4d6c] -> ./sample_usr_lms 412 #02: <LMS_free+0xcc>[0x5548] -> ./sample_usr_lms 413 #03: <(null)+0x2003fc4>[0x3fc4] -> ./sample_usr_lms 414 #04: <main+0x68>[0x3664] -> ./sample_usr_lms 415 #05: <(null)+0x1f856f30>[0x56f30] -> /lib/libc.so 416-------- LMS_free_test End -------- 417``` 418 419The Backtrace output contains the names of the files where the addresses are located. You can locate the code line corresponding to the address in the related file. 420