• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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