* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <gtest/gtest.h>
#include "log.h"
#include "utils.h"
#include "KernelConstants.h"
using namespace testing::ext;
#define MPROTECT_TESTFILE "/storage/testMprotect.txt"
class MprotectApiTest : public testing::Test {
};
* @tc.name testMprotectAnonAddReadPerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0100
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL1
*/
HWTEST_F(MprotectApiTest, testMprotectAnonAddReadPerm, Function | MediumTest | Level1)
{
size_t len = PAGE_SIZE;
volatile int sum = 0;
int prot = PROT_WRITE;
int mprot = prot | PROT_READ;
int flags = MAP_ANONYMOUS | MAP_PRIVATE;
char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
sum = mem[0] + mem[1];
LOG("child: sum = %d (0x%04x)", sum, sum);
LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
exit(0);
} else {
WaitProcExitedOK(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
}
}
* @tc.name testMprotectAnonAddWritePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0200
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL2
*/
HWTEST_F(MprotectApiTest, testMprotectAnonAddWritePerm, Function | MediumTest | Level2)
{
size_t len = PAGE_SIZE;
char testChar = 'A';
int prot = PROT_READ;
int mprot = prot | PROT_WRITE;
int flags = MAP_ANONYMOUS | MAP_PRIVATE;
char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
mem[0] = testChar;
mem[1] = testChar + 3;
LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
exit(0);
} else {
WaitProcExitedOK(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
}
}
* @tc.name testMprotectAnonAddExecutePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0300
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectAnonAddExecutePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
int prot = PROT_READ | PROT_WRITE;
int mprot = prot | PROT_EXEC;
int flags = MAP_ANONYMOUS | MAP_PRIVATE;
char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
char *ptr = (char *)fnReturnFive;
for (size_t i = 0; i < sizeof(fnReturnFive); i++) {
mem[i] = ptr[i];
}
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
int (*fun)(void) = (int (*)(void))mem;
int five = fun();
LOG("five = 0x%02x", five);
exit(0);
} else {
WaitProcExitedOK(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
}
}
* @tc.name testMprotectAnonDelWritePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0500
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectAnonDelWritePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
char testChar = 'A';
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int mprot = PROT_READ | PROT_EXEC;
int flags = MAP_ANONYMOUS | MAP_PRIVATE;
char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
mem[0] = testChar;
mem[1] = testChar + 3;
LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
exit(0);
} else {
ExpectProcCrashed(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
}
}
* @tc.name testMprotectAnonDelExecutePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0600
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectAnonDelExecutePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int mprot = PROT_READ | PROT_WRITE;
int flags = MAP_ANONYMOUS | MAP_PRIVATE;
char *mem = (char *)mmap(nullptr, len, prot, flags, -1, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
char *ptr = (char *)fnReturnFive;
for (size_t i = 0; i < sizeof(fnReturnFive); i++) {
mem[i] = ptr[i];
}
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
int (*fun)(void) = (int (*)(void))mem;
int five = fun();
LOG("five = 0x%02x", five);
exit(0);
} else {
ExpectProcCrashed(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
}
}
* @tc.name testMprotectFileAddReadPerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0700
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL2
*/
HWTEST_F(MprotectApiTest, testMprotectFileAddReadPerm, Function | MediumTest | Level2)
{
size_t len = PAGE_SIZE;
char testChar = 'A';
int failure = 0;
int prot = PROT_WRITE;
int mprot = prot | PROT_READ;
int flags = MAP_PRIVATE;
char buf[PAGE_SIZE] = {testChar, (char)(testChar + 3)};
char file[] = MPROTECT_TESTFILE;
int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
int wByte = write(fd, buf, len);
EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
read(fd, buf, len);
if (buf[0] != mem[0] || mem[0] != testChar) {
failure = -1;
}
if (buf[1] != mem[1] || mem[1] != (testChar + 3)) {
failure = -1;
}
LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
exit(failure);
} else {
WaitProcExitedOK(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
Msleep(1000);
EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
}
}
* @tc.name testMprotectFileAddWritePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0800
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectFileAddWritePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
char testChar = 'A';
int failure = 0;
int prot = PROT_READ;
int mprot = prot | PROT_WRITE;
int flags = MAP_SHARED;
char buf[PAGE_SIZE] = {0};
char file[] = MPROTECT_TESTFILE;
int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
int wByte = write(fd, buf, len);
EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
mem[0] = testChar;
mem[1] = testChar + 3;
LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
exit(failure);
} else {
WaitProcExitedOK(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
EXPECT_TRUE(fd != -1) << "ERROR: open() == -1";
read(fd, buf, len);
LOG("parent: buf[0] = %c (0x%02x)", buf[0], buf[0]);
LOG("parent: buf[1] = %c (0x%02x)", buf[1], buf[1]);
EXPECT_TRUE(buf[0] == testChar) << "ERROR: buf[0] != testChar";
EXPECT_TRUE(buf[1] == (testChar + 3)) << "ERROR: buf[1] != (testChar + 3)";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
Msleep(1000);
EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
}
}
* @tc.name testMprotectFileAddExecutePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_0900
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectFileAddExecutePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
int prot = PROT_READ | PROT_WRITE;
int mprot = prot | PROT_EXEC;
int flags = MAP_PRIVATE;
char file[] = MPROTECT_TESTFILE;
unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
int wByte = write(fd, fnReturnFive, sizeof(fnReturnFive));
EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
int (*fun)(void) = (int (*)(void))mem;
int five = fun();
LOG("five = 0x%02x", five);
exit(0);
} else {
WaitProcExitedOK(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
Msleep(1000);
EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
}
}
* @tc.name testMprotectFileDelWritePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_1100
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectFileDelWritePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
char testChar = 'A';
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int mprot = PROT_READ | PROT_EXEC;
int flags = MAP_PRIVATE;
char buf[PAGE_SIZE] = {0};
char file[] = MPROTECT_TESTFILE;
int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
int wByte = write(fd, buf, len);
EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
mem[0] = testChar;
mem[1] = testChar + 3;
LOG("child: mem[0] = %c (0x%02x)", mem[0], mem[0]);
LOG("child: mem[1] = %c (0x%02x)", mem[1], mem[1]);
exit(0);
} else {
ExpectProcCrashed(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
Msleep(1000);
EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
}
}
* @tc.name testMprotectFileDelExecutePerm
* @tc.number SUB_KERNEL_MEM_MPROTECT_1200
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL3
*/
HWTEST_F(MprotectApiTest, testMprotectFileDelExecutePerm, Function | MediumTest | Level3)
{
size_t len = PAGE_SIZE;
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int mprot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE;
char file[] = MPROTECT_TESTFILE;
unsigned long fnReturnFive[] = {0xe52db004, 0xe28db000, 0xe3a03005,
0xe1a00003, 0xe28bd000, 0xe49db004, 0xe12fff1e};
int fd = open(file, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
int wByte = write(fd, fnReturnFive, sizeof(fnReturnFive));
EXPECT_TRUE(wByte > 0) << "ERROR: write() <= 0";
char *mem = (char *)mmap(nullptr, len, prot, flags, fd, 0);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED";
EXPECT_TRUE(mprotect(mem, len, mprot) == 0) << "ERROR: mprotect() != 0";
pid_t pid = fork();
EXPECT_TRUE(pid >= 0) << "Fork Error";
if (pid == 0) {
int (*fun)(void) = (int (*)(void))mem;
int five = fun();
LOG("five = 0x%02x", five);
exit(0);
} else {
ExpectProcCrashed(pid);
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
Msleep(1000);
EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
}
}
* @tc.name testMprotectEACCES
* @tc.number SUB_KERNEL_MEM_MPROTECT_1300
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL4
*/
HWTEST_F(MprotectApiTest, testMprotectEACCES, Function | MediumTest | Level4)
{
void *mem = nullptr;
size_t len = PAGE_SIZE;
char file[] = MPROTECT_TESTFILE;
int fd = open(file, O_CREAT|O_RDONLY, S_IRUSR|S_IRGRP|S_IROTH);
ASSERT_TRUE(fd != -1) << "ERROR: open() == -1";
mem = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
EXPECT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, errno = " << errno;
int ret = mprotect(mem, len, PROT_WRITE);
EXPECT_TRUE(ret == -1) << "mprotect() != -1, ret = " << ret;
EXPECT_TRUE(errno == EACCES) << "ERROR: errno != EACCES, errno = " << errno << " EACCES = " << EACCES;
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
EXPECT_TRUE(close(fd) != -1) << "ERROR: close() == -1";
Msleep(1000);
EXPECT_TRUE(remove(file) == 0) << "ERROR: remove() != 0" << errno;
}
* @tc.name testMprotectEINVAL
* @tc.number SUB_KERNEL_MEM_MPROTECT_1400
* @tc.desc [C-L*-311] MUST NOT alter NDK API behavior.
* @tc.type FUNCTION
* @tc.size MEDIUMTEST
* @tc.level LEVEL4
*/
HWTEST_F(MprotectApiTest, testMprotectEINVAL, Function | MediumTest | Level4)
{
size_t len = PAGE_SIZE;
void *mem = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
LOG("__LINE__ = %d, mem = %p", __LINE__, mem);
ASSERT_TRUE(mem != MAP_FAILED) << "mem == MAP_FAILED, errno = " << errno;
size_t invalueAddr = ((size_t)(uintptr_t)mem) | 0x123;
int ret = mprotect((void *)invalueAddr, len, PROT_WRITE);
EXPECT_TRUE(ret == -1) << "mprotect() != -1, ret = " << ret;
EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
ret = mprotect((void *)nullptr, len, PROT_WRITE);
EXPECT_TRUE(ret == -1) << "mprotect() != -1, ret = " << ret;
EXPECT_TRUE(errno == EINVAL) << "ERROR: errno != EINVAL, errno = " << errno << " EINVAL = " << EINVAL;
EXPECT_TRUE(munmap(mem, len) == 0) << "ERROR: munmap() != 0";
}