1 /*
2  * Copyright (C) 2008 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 #define LOG_TAG "MemoryHeapBase"
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <linux/memfd.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <sys/syscall.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 
31 #include <binder/MemoryHeapBase.h>
32 #include <cutils/ashmem.h>
33 #include <cutils/atomic.h>
34 #include <log/log.h>
35 
36 namespace android {
37 
38 // ---------------------------------------------------------------------------
39 
40 #ifdef __BIONIC__
memfd_create_region(const char * name,size_t size)41 static int memfd_create_region(const char* name, size_t size) {
42     int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
43     if (fd == -1) {
44         ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
45         return -1;
46     }
47 
48     if (ftruncate(fd, size) == -1) {
49         ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
50               strerror(errno));
51         close(fd);
52         return -1;
53     }
54     return fd;
55 }
56 #endif
57 
MemoryHeapBase()58 MemoryHeapBase::MemoryHeapBase()
59     : mFD(-1), mSize(0), mBase(MAP_FAILED),
60       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
61 {
62 }
63 
MemoryHeapBase(size_t size,uint32_t flags,char const * name)64 MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
65     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
66       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
67 {
68     const size_t pagesize = getpagesize();
69     size = ((size + pagesize - 1) & ~(pagesize - 1));
70     int fd = -1;
71     if (mFlags & FORCE_MEMFD) {
72 #ifdef __BIONIC__
73         ALOGV("MemoryHeapBase: Attempting to force MemFD");
74         fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
75         if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
76         const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) | F_SEAL_GROW |
77                 F_SEAL_SHRINK | ((mFlags & MEMFD_ALLOW_SEALING_FLAG) ? 0 : F_SEAL_SEAL);
78         if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
79             ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error  %s", name,
80                   SEAL_FLAGS, strerror(errno));
81             if (mNeedUnmap) munmap(mBase, mSize);
82             mBase = nullptr;
83             mSize = 0;
84             close(fd);
85         }
86         return;
87 #else
88         mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG);
89 #endif
90     }
91     fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
92     ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
93     if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
94     if (mFlags & READ_ONLY) {
95         ashmem_set_prot_region(fd, PROT_READ);
96     }
97 }
98 
MemoryHeapBase(const char * device,size_t size,uint32_t flags)99 MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
100     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
101       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
102 {
103     if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
104         LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
105     }
106     int open_flags = O_RDWR;
107     if (flags & NO_CACHING)
108         open_flags |= O_SYNC;
109 
110     int fd = open(device, open_flags);
111     ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
112     if (fd >= 0) {
113         const size_t pagesize = getpagesize();
114         size = ((size + pagesize-1) & ~(pagesize-1));
115         if (mapfd(fd, false, size) == NO_ERROR) {
116             mDevice = device;
117         }
118     }
119 }
120 
MemoryHeapBase(int fd,size_t size,uint32_t flags,off_t offset)121 MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
122     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
123       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
124 {
125     if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
126         LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
127     }
128     const size_t pagesize = getpagesize();
129     size = ((size + pagesize-1) & ~(pagesize-1));
130     mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
131 }
132 
init(int fd,void * base,size_t size,int flags,const char * device)133 status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
134 {
135     if (mFD != -1) {
136         return INVALID_OPERATION;
137     }
138     mFD = fd;
139     mBase = base;
140     mSize = size;
141     mFlags = flags;
142     mDevice = device;
143     return NO_ERROR;
144 }
145 
mapfd(int fd,bool writeableByCaller,size_t size,off_t offset)146 status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset)
147 {
148     if (size == 0) {
149         // try to figure out the size automatically
150         struct stat sb;
151         if (fstat(fd, &sb) == 0) {
152             size = (size_t)sb.st_size;
153             // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
154             if ((off_t)size != sb.st_size) {
155                 ALOGE("%s: size of file %lld cannot fit in memory",
156                         __func__, (long long)sb.st_size);
157                 return INVALID_OPERATION;
158             }
159         }
160         // if it didn't work, let mmap() fail.
161     }
162 
163     if ((mFlags & DONT_MAP_LOCALLY) == 0) {
164         int prot = PROT_READ;
165         if (writeableByCaller || (mFlags & READ_ONLY) == 0) {
166             prot |= PROT_WRITE;
167         }
168         void* base = (uint8_t*)mmap(nullptr, size,
169                 prot, MAP_SHARED, fd, offset);
170         if (base == MAP_FAILED) {
171             ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
172                     fd, size, strerror(errno));
173             close(fd);
174             return -errno;
175         }
176         //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
177         mBase = base;
178         mNeedUnmap = true;
179     } else  {
180         mBase = nullptr; // not MAP_FAILED
181         mNeedUnmap = false;
182     }
183     mFD = fd;
184     mSize = size;
185     mOffset = offset;
186     return NO_ERROR;
187 }
188 
~MemoryHeapBase()189 MemoryHeapBase::~MemoryHeapBase()
190 {
191     dispose();
192 }
193 
dispose()194 void MemoryHeapBase::dispose()
195 {
196     int fd = android_atomic_or(-1, &mFD);
197     if (fd >= 0) {
198         if (mNeedUnmap) {
199             //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
200             munmap(mBase, mSize);
201         }
202         mBase = nullptr;
203         mSize = 0;
204         close(fd);
205     }
206 }
207 
getHeapID() const208 int MemoryHeapBase::getHeapID() const {
209     return mFD;
210 }
211 
getBase() const212 void* MemoryHeapBase::getBase() const {
213     return mBase;
214 }
215 
getSize() const216 size_t MemoryHeapBase::getSize() const {
217     return mSize;
218 }
219 
getFlags() const220 uint32_t MemoryHeapBase::getFlags() const {
221     return mFlags;
222 }
223 
getDevice() const224 const char* MemoryHeapBase::getDevice() const {
225     return mDevice;
226 }
227 
getOffset() const228 off_t MemoryHeapBase::getOffset() const {
229     return mOffset;
230 }
231 
232 // ---------------------------------------------------------------------------
233 } // namespace android
234