• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <sys/mman.h>
18 #include <cutils/ashmem.h>
19 #include <gtest/gtest.h>
20 #include <android-base/unique_fd.h>
21 
22 using android::base::unique_fd;
23 
TestCreateRegion(size_t size,unique_fd & fd,int prot)24 void TestCreateRegion(size_t size, unique_fd &fd, int prot) {
25     fd = unique_fd(ashmem_create_region(nullptr, size));
26     ASSERT_TRUE(fd >= 0);
27     ASSERT_TRUE(ashmem_valid(fd));
28     ASSERT_EQ(size, static_cast<size_t>(ashmem_get_size_region(fd)));
29     ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
30 }
31 
TestMmap(const unique_fd & fd,size_t size,int prot,void ** region)32 void TestMmap(const unique_fd &fd, size_t size, int prot, void **region) {
33     *region = mmap(nullptr, size, prot, MAP_SHARED, fd, 0);
34     ASSERT_NE(MAP_FAILED, *region);
35 }
36 
TestProtDenied(const unique_fd & fd,size_t size,int prot)37 void TestProtDenied(const unique_fd &fd, size_t size, int prot) {
38     EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
39 }
40 
FillData(uint8_t * data,size_t dataLen)41 void FillData(uint8_t* data, size_t dataLen) {
42     for (size_t i = 0; i < dataLen; i++) {
43         data[i] = i & 0xFF;
44     }
45 }
46 
TEST(AshmemTest,BasicTest)47 TEST(AshmemTest, BasicTest) {
48     constexpr size_t size = PAGE_SIZE;
49     uint8_t data[size];
50     FillData(data, size);
51 
52     unique_fd fd;
53     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
54 
55     void *region1;
56     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region1));
57 
58     memcpy(region1, &data, size);
59     ASSERT_EQ(0, memcmp(region1, &data, size));
60 
61     EXPECT_EQ(0, munmap(region1, size));
62 
63     void *region2;
64     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region2));
65     ASSERT_EQ(0, memcmp(region2, &data, size));
66     EXPECT_EQ(0, munmap(region2, size));
67 }
68 
TEST(AshmemTest,ForkTest)69 TEST(AshmemTest, ForkTest) {
70     constexpr size_t size = PAGE_SIZE;
71     uint8_t data[size];
72     FillData(data, size);
73 
74     unique_fd fd;
75     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
76 
77     void *region1;
78     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region1));
79 
80     memcpy(region1, &data, size);
81     ASSERT_EQ(0, memcmp(region1, &data, size));
82     EXPECT_EQ(0, munmap(region1, size));
83 
84     ASSERT_EXIT({
85         void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
86         if (region2 == MAP_FAILED) {
87             _exit(1);
88         }
89         if (memcmp(region2, &data, size) != 0) {
90             _exit(2);
91         }
92         memset(region2, 0, size);
93         munmap(region2, size);
94         _exit(0);
95     }, ::testing::ExitedWithCode(0),"");
96 
97     memset(&data, 0, size);
98     void *region2;
99     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region2));
100     ASSERT_EQ(0, memcmp(region2, &data, size));
101     EXPECT_EQ(0, munmap(region2, size));
102 }
103 
TEST(AshmemTest,ProtTest)104 TEST(AshmemTest, ProtTest) {
105     unique_fd fd;
106     constexpr size_t size = PAGE_SIZE;
107     void *region;
108 
109     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ));
110     TestProtDenied(fd, size, PROT_WRITE);
111     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region));
112     EXPECT_EQ(0, munmap(region, size));
113 
114     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_WRITE));
115     TestProtDenied(fd, size, PROT_READ);
116     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_WRITE, &region));
117     EXPECT_EQ(0, munmap(region, size));
118 }
119 
TEST(AshmemTest,ForkProtTest)120 TEST(AshmemTest, ForkProtTest) {
121     unique_fd fd;
122     constexpr size_t size = PAGE_SIZE;
123 
124     int protFlags[] = { PROT_READ, PROT_WRITE };
125     for (int i = 0; i < 2; i++) {
126         ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
127         ASSERT_EXIT({
128             if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
129                 _exit(0);
130             } else {
131                 _exit(1);
132             }
133         }, ::testing::ExitedWithCode(0), "");
134         ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, protFlags[1-i]));
135     }
136 }
137 
TEST(AshmemTest,ForkMultiRegionTest)138 TEST(AshmemTest, ForkMultiRegionTest) {
139     constexpr size_t size = PAGE_SIZE;
140     uint8_t data[size];
141     FillData(data, size);
142 
143     constexpr int nRegions = 16;
144     unique_fd fd[nRegions];
145     for (int i = 0; i < nRegions; i++) {
146         ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd[i], PROT_READ | PROT_WRITE));
147         void *region;
148         ASSERT_NO_FATAL_FAILURE(TestMmap(fd[i], size, PROT_READ | PROT_WRITE, &region));
149         memcpy(region, &data, size);
150         ASSERT_EQ(0, memcmp(region, &data, size));
151         EXPECT_EQ(0, munmap(region, size));
152     }
153 
154     ASSERT_EXIT({
155         for (int i = 0; i < nRegions; i++) {
156             void *region = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
157             if (region == MAP_FAILED) {
158                 _exit(1);
159             }
160             if (memcmp(region, &data, size) != 0) {
161                 munmap(region, size);
162                 _exit(2);
163             }
164             memset(region, 0, size);
165             munmap(region, size);
166         }
167         _exit(0);
168     }, ::testing::ExitedWithCode(0), "");
169 
170     memset(&data, 0, size);
171     for (int i = 0; i < nRegions; i++) {
172         void *region;
173         ASSERT_NO_FATAL_FAILURE(TestMmap(fd[i], size, PROT_READ | PROT_WRITE, &region));
174         ASSERT_EQ(0, memcmp(region, &data, size));
175         EXPECT_EQ(0, munmap(region, size));
176     }
177 }
178