xref: /test/xts/hats/kernel/mmap/MmapApiTest.cpp (revision 9762338d)
1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <gtest/gtest.h>
17#include <fcntl.h>
18#include <cinttypes>
19#include <climits>
20#include <cstdio>
21#include <cstdlib>
22#include <unistd.h>
23#include <iomanip>
24#include <iostream>
25#include <string>
26#include <vector>
27#include <sys/mman.h>
28#include <sys/utsname.h>
29#include <string>
30#include <memory.h>
31#include <csetjmp>
32#include "securec.h"
33
34#define PAGE_SIZE 4096
35
36using namespace testing::ext;
37using namespace std;
38
39class MmapApiTest : public testing::Test {
40public:
41    static void SetUpTestCase();
42    static void TearDownTestCase();
43    void SetUp();
44    void TearDown();
45private:
46};
47void MmapApiTest::SetUp()
48{
49}
50void MmapApiTest::TearDown()
51{
52}
53void MmapApiTest::SetUpTestCase()
54{
55}
56void MmapApiTest::TearDownTestCase()
57{
58}
59
60static int g_sigStarted = 0;
61
62static void SigsegvHandler(int signum)
63{
64    if (g_sigStarted) {
65        g_sigStarted = 0;
66    } else {
67        std::cout << "case failed.\n" << std::endl;
68        ASSERT_TRUE(g_sigStarted != 0);
69    }
70}
71
72static void CreateFile()
73{
74    FILE *file;
75    int ret = -1;
76    char *buffer =  static_cast<char *>(malloc(PAGE_SIZE));
77    if (buffer != nullptr) {
78        ret = memset_s(buffer, PAGE_SIZE, 'a', PAGE_SIZE);
79        ASSERT_TRUE(ret == 0);
80        file = fopen("output_file.txt", "wb");
81        if (fwrite(buffer, 1, PAGE_SIZE, file) != PAGE_SIZE) {
82            std::cout << "Error fwrite file.\n" << std::endl;
83            ASSERT_TRUE(ret != 0);
84        }
85        fclose(file);
86    }
87    free(buffer);
88}
89
90/*
91 * @tc.number SUB_KERNEL_MEM_MAP_0100
92 * @tc.name   MremapDontunmap001
93 * @tc.desc   mremap use MREMAP_DONTUNMAP with old len == new len
94*/
95HWTEST_F(MmapApiTest, MremapDontunmap001, Function | MediumTest | Level1)
96{
97    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
98    ASSERT_TRUE(addr != MAP_FAILED);
99    void *fixAddr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
100    ASSERT_TRUE(fixAddr != MAP_FAILED);
101    void *newAddr = mremap(addr, PAGE_SIZE, PAGE_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP, fixAddr);
102    ASSERT_TRUE(newAddr != MAP_FAILED);
103    int ret = munmap(addr, PAGE_SIZE);
104    ASSERT_TRUE(ret == 0);
105    ret = munmap(fixAddr, PAGE_SIZE);
106    ASSERT_TRUE(ret == 0);
107    ret = munmap(newAddr, PAGE_SIZE);
108    ASSERT_TRUE(ret == 0);
109    addr = nullptr;
110    fixAddr = nullptr;
111    newAddr = nullptr;
112}
113
114/*
115 * @tc.number SUB_KERNEL_MEM_MAP_0200
116 * @tc.name   MremapDontunmap002
117 * @tc.desc   mremap use MREMAP_DONTUNMAP with MAP_SHARED
118*/
119HWTEST_F(MmapApiTest, MremapDontunmap002, Function | MediumTest | Level2)
120{
121    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
122    ASSERT_TRUE(addr != MAP_FAILED);
123    void *fixAddr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
124    ASSERT_TRUE(fixAddr != MAP_FAILED);
125    void *newAddr = mremap(fixAddr, PAGE_SIZE, PAGE_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP, addr);
126    ASSERT_TRUE(newAddr != MAP_FAILED);
127    int ret = munmap(addr, PAGE_SIZE);
128    ASSERT_TRUE(ret == 0);
129    ret = munmap(fixAddr, PAGE_SIZE);
130    ASSERT_TRUE(ret == 0);
131    ret = munmap(newAddr, PAGE_SIZE);
132    ASSERT_TRUE(ret == 0);
133    addr = nullptr;
134    fixAddr = nullptr;
135    newAddr = nullptr;
136}
137
138/*
139 * @tc.number SUB_KERNEL_MEM_MAP_0300
140 * @tc.name   MremapDontunmap003
141 * @tc.desc   mremap use MREMAP_DONTUNMAP with old len != new len
142*/
143HWTEST_F(MmapApiTest, MremapDontunmap003, Function | MediumTest | Level1)
144{
145    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
146    ASSERT_TRUE(addr != MAP_FAILED);
147    void *fixAddr = mmap(nullptr, PAGE_SIZE * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
148    ASSERT_TRUE(fixAddr != MAP_FAILED);
149    void *newAddr = mremap(addr, PAGE_SIZE, PAGE_SIZE * 2, MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP, fixAddr);
150    ASSERT_TRUE(newAddr == MAP_FAILED);
151    int ret = munmap(addr, PAGE_SIZE);
152    ASSERT_TRUE(ret == 0);
153    ret = munmap(fixAddr, PAGE_SIZE * 2);
154    ASSERT_TRUE(ret == 0);
155    addr = nullptr;
156    fixAddr = nullptr;
157    newAddr = nullptr;
158}
159/*
160 * @tc.number SUB_KERNEL_MEM_MAP_0400
161 * @tc.name   MremapDontunmap004
162 * @tc.desc   mremap use MREMAP_DONTUNMAP without MREMAP_MAYMOVE
163*/
164HWTEST_F(MmapApiTest, MremapDontunmap004, Function | MediumTest | Level1)
165{
166    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
167    ASSERT_TRUE(addr != MAP_FAILED);
168    void *newAddr = mremap(addr, PAGE_SIZE, PAGE_SIZE,  MREMAP_FIXED | MREMAP_DONTUNMAP);
169    ASSERT_TRUE(newAddr == MAP_FAILED);
170    int ret = munmap(addr, PAGE_SIZE);
171    ASSERT_TRUE(ret == 0);
172    addr = nullptr;
173    newAddr = nullptr;
174}
175
176/*
177 * @tc.number SUB_KERNEL_MEM_MAP_0500
178 * @tc.name   MremapDontunmap005
179 * @tc.desc   mremap use MREMAP_DONTUNMAP with MREMAP_MAYMOVE
180*/
181HWTEST_F(MmapApiTest, MremapDontunmap005, Function | MediumTest | Level1)
182{
183    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
184    ASSERT_TRUE(addr != MAP_FAILED);
185    void *newAddr = mremap(addr, PAGE_SIZE, PAGE_SIZE,  MREMAP_MAYMOVE | MREMAP_DONTUNMAP);
186    ASSERT_TRUE(newAddr != MAP_FAILED);
187    int ret = munmap(addr, PAGE_SIZE);
188    ASSERT_TRUE(ret == 0);
189    ret = munmap(newAddr, PAGE_SIZE);
190    ASSERT_TRUE(ret == 0);
191    addr = nullptr;
192    newAddr = nullptr;
193}
194
195/*
196 * @tc.number  SUB_KERNEL_MEM_MAP_0800
197 * @tc.name    MMAPShardValidate001
198 * @tc.desc    mmap use MAP_SHARED_VALIDATE or MAP_SHARED with MAP_SYNC
199*/
200HWTEST_F(MmapApiTest, MMAPShardValidate001, Function | MediumTest | Level1)
201{
202    void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON | MAP_SYNC, -1, 0);
203    ASSERT_TRUE(va != MAP_FAILED);
204    void *newVa = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED_VALIDATE | MAP_ANON | MAP_SYNC, -1, 0);
205    ASSERT_TRUE(newVa == MAP_FAILED);
206    int ret = munmap(va, PAGE_SIZE);
207    ASSERT_TRUE(ret == 0);
208    va = nullptr;
209    newVa = nullptr;
210}
211
212/*
213 * @tc.number SUB_KERNEL_MEM_MAP_0900
214 * @tc.name   MMAPShardValidate002
215 * @tc.desc   mmap use MAP_SHARED_VALIDATE  with no error param
216*/
217HWTEST_F(MmapApiTest, MMAPShardValidate002, Function | MediumTest | Level1)
218{
219    CreateFile();
220    int fd = open("output_file.txt", O_RDWR);
221    ASSERT_TRUE(fd > 0);
222    void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED_VALIDATE, fd, 0);
223    ASSERT_TRUE(va != MAP_FAILED);
224    int ret = munmap(va, PAGE_SIZE);
225    ASSERT_TRUE(ret == 0);
226    va = nullptr;
227    close(fd);
228    ret = unlink("output_file.txt");
229    ASSERT_TRUE(ret == 0);
230}
231
232/*
233 * @tc.number SUB_KERNEL_MEM_MAP_1000
234 * @tc.name   MMAPNonBlock001
235 * @tc.desc   mmap use MAP_NONBLOCK
236*/
237HWTEST_F(MmapApiTest, MMAPNonBlock001, Function | MediumTest | Level1)
238{
239    void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NONBLOCK, -1, 0);
240    ASSERT_TRUE(va != MAP_FAILED);
241    int ret = munmap(va, PAGE_SIZE);
242    ASSERT_TRUE(ret == 0);
243    va = nullptr;
244}
245
246/*
247 * @tc.number SUB_KERNEL_MEM_MAP_1400
248 * @tc.name   MMAPGrownsDown001
249 * @tc.desc   MAP_GROWSDONW when the pre-vregion is not MAP_GROWSDONW
250*/
251HWTEST_F(MmapApiTest, MMAPGrownsDown001, Function | MediumTest | Level1)
252{
253    const size_t lenGdGap = (2UL << 20);
254    const size_t lenLeftMap = 0x1000;
255    const size_t lenGd = 0x1000;
256    const size_t lenReserve = lenLeftMap + lenGdGap + lenGd;
257
258    char *addReserve = nullptr;
259    char *addrGd = nullptr;
260    int ret = -1;
261
262    addReserve = (char *)mmap(nullptr, lenReserve, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
263    ASSERT_TRUE(addReserve != MAP_FAILED);
264    void *addr1 = mmap(addReserve, lenLeftMap, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
265    ASSERT_TRUE(addr1 != MAP_FAILED);
266    addrGd = (char *)mmap(addReserve + lenLeftMap + lenGdGap, lenGd, PROT_READ | PROT_WRITE,
267         MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
268    ASSERT_TRUE(addrGd != MAP_FAILED);
269
270    g_sigStarted = 1;
271    struct sigaction sa;
272    sa.sa_handler = SigsegvHandler;
273    sigemptyset(&sa.sa_mask);
274    sa.sa_flags = 0;
275    ret = sigaction(SIGSEGV, &sa, nullptr);
276    ASSERT_TRUE(ret == 0);
277    int cpage = 256;
278    addrGd[cpage * -0x1000] = '1';
279    ret = munmap(addReserve, lenReserve);
280    ASSERT_TRUE(ret == 0);
281    ret = munmap(addr1, lenLeftMap);
282    ASSERT_TRUE(ret == 0);
283    ret = munmap(addrGd, lenGd);
284    ASSERT_TRUE(ret == 0);
285    addReserve = nullptr;
286    addr1 = nullptr;
287    addrGd = nullptr;
288}
289
290/*
291 * @tc.number SUB_KERNEL_MEM_MAP_1500
292 * @tc.name   MMAPGrownsDown002
293 * @tc.desc   mprotect use PROT_GROWSDONW
294*/
295HWTEST_F(MmapApiTest, MMAPGrownsDown002, Function | MediumTest | Level1)
296{
297    const size_t lenGdGap = (2UL << 20);
298    const size_t lenLeftMap = 0x1000;
299    const size_t lenGd = 0x1000;
300    const size_t lenReserve = lenLeftMap + lenGdGap + lenGd;
301    char *addReserve = nullptr;
302    char *addrGd = nullptr;
303    int ret = -1;
304
305    addReserve = (char *)mmap(nullptr, lenReserve, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
306    ASSERT_TRUE(addReserve != MAP_FAILED);
307    void *addr1 = mmap(addReserve, lenLeftMap, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
308    ASSERT_TRUE(addr1 != MAP_FAILED);
309    addrGd = (char *)mmap(addReserve + lenLeftMap + lenGdGap, lenGd, PROT_READ,
310         MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
311    ASSERT_TRUE(addrGd != MAP_FAILED);
312
313    ret = mprotect(addrGd, lenGd, PROT_READ | PROT_WRITE | PROT_GROWSDOWN);
314    ASSERT_TRUE(ret == 0);
315    g_sigStarted = 1;
316    struct sigaction sa;
317    sa.sa_handler = SigsegvHandler;
318    sigemptyset(&sa.sa_mask);
319    sa.sa_flags = 0;
320    ret = sigaction(SIGSEGV, &sa, nullptr);
321    ASSERT_TRUE(ret == 0);
322    int cpage = 256;
323    addrGd[cpage * -0x1000] = '1';
324    ret = munmap(addReserve, lenReserve);
325    ASSERT_TRUE(ret == 0);
326    ret = munmap(addr1, lenLeftMap);
327    ASSERT_TRUE(ret == 0);
328    ret = munmap(addrGd, lenGd);
329    ASSERT_TRUE(ret == 0);
330    addReserve = nullptr;
331    addr1 = nullptr;
332    addrGd = nullptr;
333}
334
335/*
336 * @tc.number SUB_KERNEL_MEM_MAP_1600
337 * @tc.name   MMAPGrownsDown003
338 * @tc.desc   MAP_GROWSDONW when MAP_SHARED
339*/
340HWTEST_F(MmapApiTest, MMAPGrownsDown003, Function | MediumTest | Level1)
341{
342    void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED | MAP_GROWSDOWN, -1, 0);
343    ASSERT_TRUE(va == MAP_FAILED);
344    va = nullptr;
345}
346
347/*
348 * @tc.number SUB_KERNEL_MEM_MAP_1700
349 * @tc.name   MMAPGrownsDown004
350 * @tc.desc   MAP_GROWSDONW when the pre-vregion is  MAP_GROWSDONW
351*/
352HWTEST_F(MmapApiTest, MMAPGrownsDown004, Function | MediumTest | Level1)
353{
354    const size_t lenGd1 = 0x2000;
355    const size_t lenGd2 = 0x2000;
356    const size_t lenReserve = 0x1000 * 6;
357
358    char *addReserve = nullptr;
359    char *addrGd1 = nullptr;
360    char *addrGd2 = nullptr;
361    int ret = -1;
362
363    addReserve = (char *)mmap(nullptr, lenReserve, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
364    ASSERT_TRUE(addReserve != MAP_FAILED);
365    addrGd1 = (char *)mmap(addReserve, lenGd1, PROT_READ  | PROT_WRITE,
366         MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
367    ASSERT_TRUE(addrGd1 != MAP_FAILED);
368    addrGd2 = (char *)mmap(addReserve + (lenReserve - lenGd2), lenGd2, PROT_READ  | PROT_WRITE,
369         MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
370    ASSERT_TRUE(addrGd2 != MAP_FAILED);
371    g_sigStarted = 1;
372    struct sigaction sa;
373    sa.sa_handler = SigsegvHandler;
374    sigemptyset(&sa.sa_mask);
375    sa.sa_flags = 0;
376    ret = sigaction(SIGSEGV, &sa, nullptr);
377    ASSERT_TRUE(ret == 0);
378    addrGd2[-0x1000] = '1';
379    addrGd2[-0x2000] = '1';
380    ret = munmap(addReserve, lenReserve);
381    ASSERT_TRUE(ret == 0);
382    ret = munmap(addrGd1, lenGd1);
383    ASSERT_TRUE(ret == 0);
384    ret = munmap(addrGd2, lenGd2);
385    ASSERT_TRUE(ret == 0);
386    addReserve = nullptr;
387    addrGd1 = nullptr;
388    addrGd2 = nullptr;
389}