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 MPROTECT_TESTFILE "/storage/testMprotect.txt"
33
34class MprotectApiTest : public testing::Test {
35};
36
37/**
38 * @tc.number SUB_KERNEL_MEM_MPROTECT_0100
39 * @tc.name   mprotect function add read permission to the anonymous map area test
40 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
41 */
42HWTEST_F(MprotectApiTest, testMprotectAnonAddReadPerm, Function | MediumTest | Level1)
43{
44    size_t len = PAGE_SIZE;
45    volatile int sum = 0;
46    int prot = PROT_WRITE;
47    int mprot = prot | PROT_READ;
48    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
49
50    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
51    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
52
53    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
54
55    pid_t pid = fork();
56    EXPECT_TRUE(pid >= 0) << "Fork Error";
57    if (pid == 0) {
58        sum = mem[0] + mem[1];
59        LOG("child: sum    = %d (0x%04x)", sum, sum);
60        LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
61        LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
62
63        exit(0);
64    } else {
65        WaitProcExitedOK(pid);
66        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
67    }
68}
69
70/**
71 * @tc.number SUB_KERNEL_MEM_MPROTECT_0200
72 * @tc.name   mprotect function add write permission to the anonymous map area test
73 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
74 */
75HWTEST_F(MprotectApiTest, testMprotectAnonAddWritePerm, Function | MediumTest | Level2)
76{
77    size_t len = PAGE_SIZE;
78    char testChar = 'A';
79    int prot = PROT_READ;
80    int mprot = prot | PROT_WRITE;
81    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
82
83    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
84    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
85
86    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
87
88    pid_t pid = fork();
89    EXPECT_TRUE(pid >= 0) << "Fork Error";
90    if (pid == 0) {
91        mem[0] = testChar;
92        mem[1] = testChar + 3;
93        LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
94        LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
95
96        exit(0);
97    } else {
98        WaitProcExitedOK(pid);
99        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
100    }
101}
102
103/**
104 * @tc.number SUB_KERNEL_MEM_MPROTECT_0300
105 * @tc.name   mprotect function add execute permission to the anonymous map area test
106 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
107 */
108HWTEST_F(MprotectApiTest, testMprotectAnonAddExecutePerm, Function | MediumTest | Level3)
109{
110    size_t len = PAGE_SIZE;
111    int prot = PROT_READ | PROT_WRITE;
112    int mprot = prot | PROT_EXEC;
113    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
114
115    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
116    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
117
118    unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
119                                    0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
120    char *ptr = (char *)fnReturnFive;
121    for (size_t i = 0; i < sizeof(fnReturnFive); i++) {
122        mem[i] = ptr[i];
123    }
124
125    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
126
127    pid_t pid = fork();
128    EXPECT_TRUE(pid >= 0) << "Fork Error";
129    if (pid == 0) {
130        int (*fun)(void) = (int (*)(void))mem;
131        int five = fun();
132        LOG("five = 0x%02x", five);
133        exit(0);
134    } else {
135        WaitProcExitedOK(pid);
136        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
137    }
138}
139
140/**
141 * @tc.number SUB_KERNEL_MEM_MPROTECT_0500
142 * @tc.name   mprotect function delete write permission to the anonymous map area test
143 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
144 */
145HWTEST_F(MprotectApiTest, testMprotectAnonDelWritePerm, Function | MediumTest | Level3)
146{
147    size_t len = PAGE_SIZE;
148    char testChar = 'A';
149    int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
150    int mprot = PROT_READ | PROT_EXEC;
151    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
152
153    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
154    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
155
156    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
157
158    pid_t pid = fork();
159    EXPECT_TRUE(pid >= 0) << "Fork Error";
160    if (pid == 0) {
161        mem[0] = testChar;
162        mem[1] = testChar + 3;
163        LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
164        LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
165        exit(0);
166    } else {
167        ExpectProcCrashed(pid);
168        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
169    }
170}
171
172/**
173 * @tc.number SUB_KERNEL_MEM_MPROTECT_0600
174 * @tc.name   mprotect function delete execute permission to the anonymous map area test
175 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
176 */
177HWTEST_F(MprotectApiTest, testMprotectAnonDelExecutePerm, Function | MediumTest | Level3)
178{
179    size_t len = PAGE_SIZE;
180    int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
181    int mprot = PROT_READ | PROT_WRITE;
182    int flags = MAP_ANONYMOUS | MAP_PRIVATE;
183
184    char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
185    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
186
187    unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
188                                    0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
189    char *ptr = (char *)fnReturnFive;
190
191    for (size_t i = 0; i < sizeof(fnReturnFive); i++) {
192        mem[i] = ptr[i];
193    }
194
195    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
196
197    pid_t pid = fork();
198    EXPECT_TRUE(pid >= 0) << "Fork Error";
199    if (pid == 0) {
200        int (*fun)(void) = (int (*)(void))mem;
201        int five = fun();
202        LOG("five = 0x%02x", five);
203        exit(0);
204    } else {
205        ExpectProcCrashed(pid);
206        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
207    }
208}
209
210/**
211 * @tc.number SUB_KERNEL_MEM_MPROTECT_0700
212 * @tc.name   mprotect function add read permission to the file map area test
213 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
214 */
215HWTEST_F(MprotectApiTest, testMprotectFileAddReadPerm, Function | MediumTest | Level2)
216{
217    size_t len = PAGE_SIZE;
218    char testChar = 'A';
219    int failure = 0;
220    int prot = PROT_WRITE;
221    int mprot = prot | PROT_READ;
222    int flags = MAP_PRIVATE;
223
224    char buf[PAGE_SIZE] = {testChar, (char)(testChar + 3)};
225    char file[] = MPROTECT_TESTFILE;
226
227    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
228    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
229
230    int wByte = write(fd, buf, len);
231    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
232
233    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
234    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
235
236    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
237
238    pid_t pid = fork();
239    EXPECT_TRUE(pid >= 0) << "Fork Error";
240    if (pid == 0) {
241        read(fd, buf, len);
242        if (buf[0] != mem[0] || mem[0] != testChar) {
243            failure = -1;
244        }
245        if (buf[1] != mem[1] || mem[1] != (testChar + 3)) {
246            failure = -1;
247        }
248        LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
249        LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
250        exit(failure);
251    } else {
252        WaitProcExitedOK(pid);
253        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
254        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
255        Msleep(1000);
256        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
257    }
258}
259
260/**
261 * @tc.number SUB_KERNEL_MEM_MPROTECT_0800
262 * @tc.name   mprotect function add write permission to the file map area test
263 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
264 */
265HWTEST_F(MprotectApiTest, testMprotectFileAddWritePerm, Function | MediumTest | Level3)
266{
267    size_t len = PAGE_SIZE;
268    char testChar = 'A';
269    int failure = 0;
270    int prot = PROT_READ;
271    int mprot = prot | PROT_WRITE;
272    int flags = MAP_SHARED;
273
274    char buf[PAGE_SIZE] = {0};
275    char file[] = MPROTECT_TESTFILE;
276
277    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
278    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
279
280    int wByte = write(fd, buf, len);
281    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
282
283    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
284    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
285
286    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
287
288    pid_t pid = fork();
289    EXPECT_TRUE(pid >= 0) << "Fork Error";
290    if (pid == 0) {
291        mem[0] = testChar;
292        mem[1] = testChar + 3;
293        LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
294        LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
295        exit(failure);
296    } else {
297        WaitProcExitedOK(pid);
298        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
299        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
300
301        fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
302        EXPECT_TRUE(fd != -1) << "ERROR: open() == -1";
303
304        read(fd, buf, len);
305
306        LOG("parent: buf[0] = %c (0x%02x)", buf[0], buf[0]);
307        LOG("parent: buf[1] = %c (0x%02x)", buf[1], buf[1]);
308
309        EXPECT_TRUE(buf[0] == testChar) << "ERROR: buf[0] != testChar";
310        EXPECT_TRUE(buf[1] == (testChar + 3)) << "ERROR: buf[1] != (testChar + 3)";
311        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
312        Msleep(1000);
313        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
314    }
315}
316
317/**
318 * @tc.number SUB_KERNEL_MEM_MPROTECT_0900
319 * @tc.name   mprotect function add execute permission to the file map area test
320 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
321 */
322HWTEST_F(MprotectApiTest, testMprotectFileAddExecutePerm, Function | MediumTest | Level3)
323{
324    size_t len = PAGE_SIZE;
325    int prot = PROT_READ | PROT_WRITE;
326    int mprot = prot | PROT_EXEC;
327    int flags = MAP_PRIVATE;
328    char file[] = MPROTECT_TESTFILE;
329
330    unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
331                                    0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
332
333    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
334    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
335
336    int wByte = write(fd, fnReturnFive, sizeof(fnReturnFive));
337    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
338
339    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
340    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
341
342    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
343
344    pid_t pid = fork();
345    EXPECT_TRUE(pid >= 0) << "Fork Error";
346    if (pid == 0) {
347        int (*fun)(void) = (int (*)(void))mem;
348        int five = fun();
349        LOG("five = 0x%02x", five);
350        exit(0);
351    } else {
352        WaitProcExitedOK(pid);
353        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
354        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
355        Msleep(1000);
356        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
357    }
358}
359
360/**
361 * @tc.number SUB_KERNEL_MEM_MPROTECT_1100
362 * @tc.name   mprotect function delete write permission to the file map area test
363 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
364 */
365HWTEST_F(MprotectApiTest, testMprotectFileDelWritePerm, Function | MediumTest | Level3)
366{
367    size_t len = PAGE_SIZE;
368    char testChar = 'A';
369    int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
370    int mprot = PROT_READ | PROT_EXEC;
371    int flags = MAP_PRIVATE;
372
373    char buf[PAGE_SIZE] = {0};
374    char file[] = MPROTECT_TESTFILE;
375
376    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
377    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
378
379    int wByte = write(fd, buf, len);
380    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
381
382    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
383    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
384
385    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
386
387    pid_t pid = fork();
388    EXPECT_TRUE(pid >= 0) << "Fork Error";
389    if (pid == 0) {
390        mem[0] = testChar;
391        mem[1] = testChar + 3;
392        LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
393        LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
394        exit(0);
395    } else {
396        ExpectProcCrashed(pid);
397
398        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
399        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
400        Msleep(1000);
401        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
402    }
403}
404
405/**
406 * @tc.number SUB_KERNEL_MEM_MPROTECT_1200
407 * @tc.name   mprotect function delete execute permission to the file map area test
408 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
409 */
410HWTEST_F(MprotectApiTest, testMprotectFileDelExecutePerm, Function | MediumTest | Level3)
411{
412    size_t len = PAGE_SIZE;
413    int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
414    int mprot = PROT_READ | PROT_WRITE;
415    int flags = MAP_PRIVATE;
416    char file[] = MPROTECT_TESTFILE;
417
418    unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
419                                    0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
420
421    int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
422    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
423
424    int wByte = write(fd, fnReturnFive, sizeof(fnReturnFive));
425    EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
426
427    char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
428    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
429
430    EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
431
432    pid_t pid = fork();
433    EXPECT_TRUE(pid >= 0) << "Fork Error";
434    if (pid == 0) {
435        int (*fun)(void) = (int (*)(void))mem;
436        int five = fun();
437        LOG("five = 0x%02x", five);
438        exit(0);
439    } else {
440        ExpectProcCrashed(pid);
441
442        EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
443        EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
444        Msleep(1000);
445        EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
446    }
447}
448
449/**
450 * @tc.number SUB_KERNEL_MEM_MPROTECT_1300
451 * @tc.name   mprotect function errno for EACCES test
452 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
453 */
454HWTEST_F(MprotectApiTest, testMprotectEACCES, Function | MediumTest | Level4)
455{
456    void *mem = nullptr;
457    size_t len = PAGE_SIZE;
458    char file[] = MPROTECT_TESTFILE;
459
460    int fd = open(file, O_CREAT|O_RDONLY, S_IRUSR|S_IRGRP|S_IROTH);
461    ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
462
463    mem = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
464    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
465    EXPECT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, errno = " << errno;
466
467    int ret = mprotect(mem, len, PROT_WRITE);
468    EXPECT_TRUE(ret == -1) << "mprotect() != -1, ret = " << ret;
469    EXPECT_TRUE(errno == EACCES) << "ERROR: errno != EACCES, errno = " << errno << " EACCES = " << EACCES;
470
471    EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
472    EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
473    Msleep(1000);
474    EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
475}
476
477/**
478 * @tc.number SUB_KERNEL_MEM_MPROTECT_1400
479 * @tc.name   mprotect function errno for EINVAL test
480 * @tc.desc   [C-L*-311] MUST NOT alter NDK API behavior.
481 */
482HWTEST_F(MprotectApiTest, testMprotectEINVAL, Function | MediumTest | Level4)
483{
484    size_t len = PAGE_SIZE;
485
486    void *mem = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
487    LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
488    ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, errno = " << errno;
489
490    size_t invalueAddr = ((size_t)(uintptr_t)mem) | 0x123;
491    int ret = mprotect((void *)invalueAddr, len, PROT_WRITE);
492    EXPECT_TRUE(ret == -1) << "mprotect() != -1, ret = " << ret;
493    EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
494
495    ret = mprotect((void *)nullptr, len, PROT_WRITE);
496    EXPECT_TRUE(ret == -1) << "mprotect() != -1, ret = " << ret;
497    EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
498
499    EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
500}