1/*
2 * Copyright (c) 2021 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 <stdlib.h>
17#include <string.h>
18#include <stdio.h>
19#include <errno.h>
20#include <sys/mman.h>
21#include <sys/file.h>
22#include <sys/types.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <gtest/gtest.h>
26#include "log.h"
27#include "utils.h"
28#include "KernelConstants.h"
29
30using namespace testing::ext;
31
32#define MREMAP_TESTFILE "/storage/testMremap.txt"
33
34class MremapApiTest : public testing::Test {
35};
36
37/**
38 * @tc.number SUB_KERNEL_MEM_SBRK_0100
39 * @tc.name   sbrk function increment 0 test
40 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
41 */
42HWTEST_F(MremapApiTest, testSbrkZero, Function | MediumTest | Level2)
43{
44    void *mem = sbrk(0);
45    LOG("mem = %p", mem);
46    ASSERT_TRUE(mem != nullptr);
47}
48
49/**
50 * @tc.number SUB_KERNEL_MEM_SBRK_0200
51 * @tc.name   sbrk function errno for ENOMEM test
52 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
53 */
54HWTEST_F(MremapApiTest, testSbrkENOMEM, Function | MediumTest | Level3)
55{
56    void *mem = sbrk(GetRandom(4096));
57    LOG("mem = %p, errno = %d", mem, errno);
58    ASSERT_TRUE(mem == (void *)-1);
59    EXPECT_TRUE(errno == ENOMEM) << "ERROR: errno != ENOMEM, errno = " << errno << " ENOMEM = " << ENOMEM;
60}
61
62/**
63 * @tc.number SUB_KERNEL_MEM_MREMAP_0100
64 * @tc.name   mremap function anonymous remap expand area test
65 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
66 */
67HWTEST_F(MremapApiTest, testMremapAnonExpand, Function | MediumTest | Level2)
68{
69    size_t len = PAGE_SIZE;
70    size_t expandSize = len * 2;
71    char testChar = 'A';
72    int prot = PROT_READ | PROT_WRITE;
73    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
74
75    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
76    LOG("mem = %p", mem);
77    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
78
79    mem = (char *)mremap(mem, len, expandSize, 0);
80    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
81    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, expandSize = " << expandSize;
82
83    pid_t pid = fork();
84    EXPECT_TRUE(pid >= 0) << "Fork Error";
85    if (pid == 0) {
86        mem[0] = testChar;
87        mem[len - 1] = testChar + 3;
88        /* expand area operate test */
89        mem[len + 0] = testChar;
90        mem[expandSize - 1] = testChar + 3;
91
92        LOG("mem[0] = 0x%02x", mem[0]);
93        LOG("mem[len - 1] = 0x%02x", mem[len - 1]);
94        LOG("mem[len + 0] = 0x%02x", mem[len + 0]);
95        LOG("mem[expandSize - 1] = 0x%02x", mem[expandSize - 1]);
96
97        exit(0);
98    } else {
99        WaitProcExitedOK(pid);
100        EXPECT_TRUE(munmap(mem, expandSize) == 0) << "ERROR: munmap() != 0" << errno;
101    }
102}
103
104/**
105 * @tc.number SUB_KERNEL_MEM_MREMAP_0200
106 * @tc.name   mremap function anonymous remap shrink area test
107 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
108 */
109HWTEST_F(MremapApiTest, testMremapAnonShrink, Function | MediumTest | Level3)
110{
111    size_t len = PAGE_SIZE * 2;
112    size_t shrinkSize = len / 2;
113    char testChar = 'A';
114    int prot = PROT_READ | PROT_WRITE;
115    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
116
117    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
118    LOG("mem = %p", mem);
119    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
120
121    mem = (char *)mremap(mem, len, shrinkSize, 0);
122    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
123    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, shrinkSize = " << shrinkSize;
124
125    pid_t pid = fork();
126    EXPECT_TRUE(pid >= 0) << "Fork Error";
127    if (pid == 0) {
128        mem[0] = testChar;
129        mem[shrinkSize - 1] = testChar + 3;
130        LOG("mem[0] = 0x%02x", mem[0]);
131        LOG("mem[shrinkSize - 1] = 0x%02x", mem[shrinkSize - 1]);
132        /* this operate will cause process crash */
133        mem[shrinkSize + 4] = testChar;
134
135        exit(0);
136    } else {
137        ExpectProcCrashed(pid);
138        EXPECT_TRUE(munmap(mem, shrinkSize) == 0) << "ERROR: munmap() != 0" << errno;
139    }
140}
141
142/**
143 * @tc.number SUB_KERNEL_MEM_MREMAP_0300
144 * @tc.name   mremap function anonymous remap and expand area to fix address test
145 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
146 */
147HWTEST_F(MremapApiTest, testMremapAnonExpandFixAddr, Function | MediumTest | Level3)
148{
149    size_t len = PAGE_SIZE;
150    size_t expandSize = len * 2;
151    char testChar = 'A';
152    char *fixAddr = (char *)0x27000000;
153    int prot = PROT_READ | PROT_WRITE;
154    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
155    int reFlag = MREMAP_MAYMOVE | MREMAP_FIXED;
156
157    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
158    LOG("mem = %p", mem);
159    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
160
161    mem = (char *)mremap(mem, len, expandSize, reFlag, (void *)fixAddr);
162    LOG("__LINE__ = %d, mem = %p, fixAddr = %p", __LINE__, mem, fixAddr);
163    ASSERT_TRUE(mem == fixAddr) << "mem != fixAddr";
164
165    pid_t pid = fork();
166    EXPECT_TRUE(pid >= 0) << "Fork Error";
167    if (pid == 0) {
168        fixAddr[0] = testChar;
169        fixAddr[len - 1] = testChar + 3;
170        /* expand area operate test */
171        fixAddr[len + 0] = testChar;
172        fixAddr[expandSize - 1] = testChar + 3;
173
174        LOG("fixAddr[0] = 0x%02x", fixAddr[0]);
175        LOG("fixAddr[len - 1] = 0x%02x", fixAddr[len - 1]);
176        LOG("fixAddr[len + 0] = 0x%02x", fixAddr[len + 0]);
177        LOG("fixAddr[expandSize - 1] = 0x%02x", fixAddr[expandSize - 1]);
178
179        exit(0);
180    } else {
181        WaitProcExitedOK(pid);
182        EXPECT_TRUE(munmap(mem, expandSize) == 0) << "ERROR: munmap() != 0" << errno;
183    }
184}
185
186/**
187 * @tc.number SUB_KERNEL_MEM_MREMAP_0400
188 * @tc.name   mremap function anonymous remap and shrink area to fix address test
189 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
190 */
191HWTEST_F(MremapApiTest, testMremapAnonShrinkFixAddr, Function | MediumTest | Level3)
192{
193    size_t len = PAGE_SIZE * 2;
194    size_t shrinkSize = len / 2;
195    char testChar = 'A';
196    char *fixAddr = (char *)0x27000000;
197    int prot = PROT_READ | PROT_WRITE;
198    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
199    int reFlag = MREMAP_MAYMOVE | MREMAP_FIXED;
200
201    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
202    LOG("mem = %p", mem);
203    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
204
205    mem = (char *)mremap(mem, len, shrinkSize, reFlag, (void *)fixAddr);
206    LOG("__LINE__ = %d, mem = %p, fixAddr = %p", __LINE__, mem, fixAddr);
207    ASSERT_TRUE(mem == fixAddr) << "mem != fixAddr";
208
209    pid_t pid = fork();
210    EXPECT_TRUE(pid >= 0) << "Fork Error";
211    if (pid == 0) {
212        fixAddr[0] = testChar;
213        fixAddr[shrinkSize - 1] = testChar + 3;
214        LOG("fixAddr[0] = 0x%02x", fixAddr[0]);
215        LOG("fixAddr[shrinkSize - 1] = 0x%02x", fixAddr[shrinkSize - 1]);
216        /* this operate will cause process crash */
217        fixAddr[shrinkSize + 4] = testChar;
218
219        exit(0);
220    } else {
221        ExpectProcCrashed(pid);
222        EXPECT_TRUE(munmap(mem, shrinkSize) == 0) << "ERROR: munmap() != 0" <<errno;
223    }
224}
225
226/**
227 * @tc.number SUB_KERNEL_MEM_MREMAP_0500
228 * @tc.name   mremap function file remap expand area test
229 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
230 */
231HWTEST_F(MremapApiTest, testMremapFileExpand, Function | MediumTest | Level2)
232{
233    size_t len = PAGE_SIZE;
234    size_t expandSize = len * 2;
235    char testChar = 'A';
236    int prot = PROT_READ | PROT_WRITE;
237    int flags = MAP_SHARED;
238    char buf[PAGE_SIZE * 2] = {0};
239    char file[] = MREMAP_TESTFILE;
240
241    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
242    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
243
244    int wByte = write(fd, buf, expandSize);
245    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
246
247    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
248    LOG("mem = %p", mem);
249    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
250
251    mem = (char *)mremap(mem, len, expandSize, 0);
252    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
253    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, expandSize = " << expandSize;
254
255    pid_t pid = fork();
256    EXPECT_TRUE(pid >= 0) << "Fork Error";
257    if (pid == 0) {
258        mem[0] = testChar;
259        mem[len - 1] = testChar + 3;
260        /* expand area operate test */
261        mem[len + 0] = testChar;
262        mem[expandSize - 1] = testChar + 3;
263        LOG("mem[0] = 0x%02x", mem[0]);
264        LOG("mem[len - 1] = 0x%02x", mem[len - 1]);
265        LOG("mem[len + 0] = 0x%02x", mem[len + 0]);
266        LOG("mem[expandSize - 1] = 0x%02x", mem[expandSize - 1]);
267
268        exit(0);
269    } else {
270        WaitProcExitedOK(pid);
271        EXPECT_TRUE(munmap(mem, expandSize) == 0) << "ERROR: munmap() != 0";
272        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
273        Msleep(1000);
274        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
275    }
276}
277
278/**
279 * @tc.number SUB_KERNEL_MEM_MREMAP_0600
280 * @tc.name   mremap function file remap shrink area test
281 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
282 */
283HWTEST_F(MremapApiTest, testMremapFileShrink, Function | MediumTest | Level3)
284{
285    size_t len = PAGE_SIZE * 2;
286    size_t shrinkSize = len / 2;
287    char testChar = 'A';
288    int prot = PROT_READ | PROT_WRITE;
289    int flags = MAP_SHARED;
290    char buf[PAGE_SIZE * 2] = {0};
291    char file[] = MREMAP_TESTFILE;
292
293    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
294    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
295
296    int wByte = write(fd, buf, len);
297    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
298
299    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
300    LOG("mem = %p", mem);
301    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
302
303    mem = (char *)mremap(mem, len, shrinkSize, 0);
304    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
305    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, shrinkSize = " << shrinkSize;
306
307    pid_t pid = fork();
308    EXPECT_TRUE(pid >= 0) << "Fork Error";
309    if (pid == 0) {
310        mem[0] = testChar;
311        mem[shrinkSize - 1] = testChar + 3;
312        LOG("mem[0] = 0x%02x", mem[0]);
313        LOG("mem[shrinkSize - 1] = 0x%02x", mem[shrinkSize - 1]);
314
315        /* this operate will cause process crash */
316        mem[shrinkSize + 4] = testChar;
317
318        exit(0);
319    } else {
320        ExpectProcCrashed(pid);
321        EXPECT_TRUE(munmap(mem, shrinkSize) == 0) << "ERROR: munmap() != 0";
322        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
323        Msleep(1000);
324        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
325    }
326}
327
328/**
329 * @tc.number SUB_KERNEL_MEM_MREMAP_0700
330 * @tc.name   mremap function file remap and expand area to fix address test
331 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
332 */
333HWTEST_F(MremapApiTest, testMremapFileExpandFixAddr, Function | MediumTest | Level3)
334{
335    size_t len = PAGE_SIZE;
336    size_t expandSize = len * 2;
337    char testChar = 'A';
338    char *fixAddr = (char *)0x27000000;
339    int prot = PROT_READ | PROT_WRITE;
340    int flags = MAP_SHARED;
341    int reFlag = MREMAP_MAYMOVE | MREMAP_FIXED;
342    char buf[PAGE_SIZE * 2] = {0};
343    char file[] = MREMAP_TESTFILE;
344
345    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
346    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
347
348    int wByte = write(fd, buf, expandSize);
349    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
350
351    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
352    LOG("mem = %p", mem);
353    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
354
355    mem = (char *)mremap(mem, len, expandSize, reFlag, (void *)fixAddr);
356    LOG("__LINE__ = %d, mem = %p, fixAddr = %p", __LINE__, mem, fixAddr);
357    ASSERT_TRUE(mem == fixAddr) << "mem != fixAddr";
358
359    pid_t pid = fork();
360    EXPECT_TRUE(pid >= 0) << "Fork Error";
361    if (pid == 0) {
362        fixAddr[0] = testChar;
363        fixAddr[len - 1] = testChar + 3;
364        /* expand area operate test */
365        fixAddr[len + 0] = testChar;
366        fixAddr[expandSize - 1] = testChar + 3;
367
368        LOG("fixAddr[0] = 0x%02x", fixAddr[0]);
369        LOG("fixAddr[len - 1] = 0x%02x", fixAddr[len - 1]);
370        LOG("fixAddr[len + 0] = 0x%02x", fixAddr[len + 0]);
371        LOG("fixAddr[expandSize - 1] = 0x%02x", fixAddr[expandSize - 1]);
372
373        exit(0);
374    } else {
375        WaitProcExitedOK(pid);
376        EXPECT_TRUE(munmap(mem, expandSize) == 0) << "ERROR: munmap() != 0";
377        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
378        Msleep(1000);
379        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
380    }
381}
382
383/**
384 * @tc.number SUB_KERNEL_MEM_MREMAP_0800
385 * @tc.name   mremap function file remap and shrink area to fix address test
386 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
387 */
388HWTEST_F(MremapApiTest, testMremapFileShrinkFixAddr, Function | MediumTest | Level3)
389{
390    size_t len = PAGE_SIZE * 2;
391    size_t shrinkSize = len / 2;
392    char testChar = 'A';
393    char *fixAddr = (char *)0x27000000;
394    int prot = PROT_READ | PROT_WRITE;
395    int flags = MAP_SHARED;
396    int reFlag = MREMAP_MAYMOVE | MREMAP_FIXED;
397
398    char buf[PAGE_SIZE * 2] = {0};
399    char file[] = MREMAP_TESTFILE;
400
401    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
402    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
403
404    int wByte = write(fd, buf, len);
405    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
406
407    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
408    LOG("mem = %p", mem);
409    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
410
411    mem = (char *)mremap(mem, len, shrinkSize, reFlag, (void *)fixAddr);
412    LOG("__LINE__ = %d, mem = %p, fixAddr = %p", __LINE__, mem, fixAddr);
413    ASSERT_TRUE(mem == fixAddr) << "mem != fixAddr";
414
415    pid_t pid = fork();
416    EXPECT_TRUE(pid >= 0) << "Fork Error";
417    if (pid == 0) {
418        fixAddr[0] = testChar;
419        fixAddr[shrinkSize - 1] = testChar + 3;
420        LOG("fixAddr[0] = 0x%02x", fixAddr[0]);
421        LOG("fixAddr[shrinkSize - 1] = 0x%02x", fixAddr[shrinkSize - 1]);
422
423        /* this operate will cause process crash */
424        fixAddr[shrinkSize + 4] = testChar;
425
426        exit(0);
427    } else {
428        ExpectProcCrashed(pid);
429
430        EXPECT_TRUE(munmap(mem, shrinkSize) == 0) << "ERROR: munmap() != 0";
431        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
432        Msleep(1000);
433        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
434    }
435}
436
437/**
438 * @tc.number SUB_KERNEL_MEM_MREMAP_0900
439 * @tc.name   mremap function errno for EINVAL test
440 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
441 */
442HWTEST_F(MremapApiTest, testMremapEINVAL, Function | MediumTest | Level4)
443{
444    void *mem = nullptr;
445    void *newMem = nullptr;
446    size_t len = PAGE_SIZE;
447    unsigned long fixAddr = 0x27700000;
448
449    mem = mmap((void *)fixAddr, len, PROT_READ | PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
450    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
451    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
452
453    fixAddr |= 0x123;
454    newMem = mremap((void *)fixAddr, len, len, 0);
455    LOG("__LINE__ = %d, newMem = %p", __LINE__, newMem);
456    EXPECT_TRUE(newMem == MAP_FAILED) << "mem != MAP_FAILED errno = " << errno;
457    EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
458
459    newMem = mremap(mem, len, len, 0x04);
460    LOG("__LINE__ = %d, newMem = %p", __LINE__, newMem);
461    EXPECT_TRUE(newMem == MAP_FAILED) << "mem != MAP_FAILED errno = " << errno;
462    EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
463
464    newMem = mremap(mem, len, 0, 0);
465    LOG("__LINE__ = %d, newMem = %p", __LINE__, newMem);
466    EXPECT_TRUE(newMem == MAP_FAILED) << "mem != MAP_FAILED errno = " << errno;
467    EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
468
469    EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
470
471    if (newMem != MAP_FAILED && newMem != mem) {
472        EXPECT_TRUE(munmap(newMem, len) == 0) << "ERROR: munmap() != 0" << errno;
473    }
474}
475