blob: a2133b953c561fe7769356f8ae4ea2684ecb6fe2 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright 2006 The Android Open Source Project
3 *
Tao Baoc3292f32016-11-04 10:52:13 -07004 * 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.
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080015 */
Tao Baoc3292f32016-11-04 10:52:13 -070016
17#include "SysUtil.h"
18
Elliott Hughesf267dee2015-06-23 12:31:02 -070019#include <errno.h>
Doug Zongker99916f02014-01-13 14:16:58 -080020#include <fcntl.h>
Tao Bao14b61e72016-11-08 13:24:27 -080021#include <stdint.h>
Elliott Hughesf267dee2015-06-23 12:31:02 -070022#include <sys/mman.h>
23#include <sys/stat.h>
24#include <sys/types.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080025
Tao Baoc3292f32016-11-04 10:52:13 -070026#include <algorithm>
27#include <string>
28#include <vector>
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -070029
Tao Baoc3292f32016-11-04 10:52:13 -070030#include <android-base/file.h>
31#include <android-base/logging.h>
32#include <android-base/strings.h>
33#include <android-base/unique_fd.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080034
Elliott Hughesf267dee2015-06-23 12:31:02 -070035static bool sysMapFD(int fd, MemMapping* pMap) {
Tao Baoc3292f32016-11-04 10:52:13 -070036 CHECK(pMap != nullptr);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080037
Tao Baoc3292f32016-11-04 10:52:13 -070038 struct stat sb;
39 if (fstat(fd, &sb) == -1) {
40 PLOG(ERROR) << "fstat(" << fd << ") failed";
41 return false;
42 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080043
Tao Baoc3292f32016-11-04 10:52:13 -070044 void* memPtr = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
45 if (memPtr == MAP_FAILED) {
46 PLOG(ERROR) << "mmap(" << sb.st_size << ", R, PRIVATE, " << fd << ", 0) failed";
47 return false;
48 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080049
Tao Baoc3292f32016-11-04 10:52:13 -070050 pMap->addr = static_cast<unsigned char*>(memPtr);
51 pMap->length = sb.st_size;
52 pMap->ranges.push_back({ memPtr, static_cast<size_t>(sb.st_size) });
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080053
Tao Baoc3292f32016-11-04 10:52:13 -070054 return true;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080055}
56
Tao Baoc3292f32016-11-04 10:52:13 -070057// A "block map" which looks like this (from uncrypt/uncrypt.cpp):
58//
59// /dev/block/platform/msm_sdcc.1/by-name/userdata # block device
60// 49652 4096 # file size in bytes, block size
61// 3 # count of block ranges
62// 1000 1008 # block range 0
63// 2100 2102 # ... block range 1
64// 30 33 # ... block range 2
65//
66// Each block range represents a half-open interval; the line "30 33"
67// reprents the blocks [30, 31, 32].
68static int sysMapBlockFile(const char* filename, MemMapping* pMap) {
69 CHECK(pMap != nullptr);
Doug Zongker99916f02014-01-13 14:16:58 -080070
Tao Baoc3292f32016-11-04 10:52:13 -070071 std::string content;
72 if (!android::base::ReadFileToString(filename, &content)) {
73 PLOG(ERROR) << "Failed to read " << filename;
74 return -1;
75 }
Doug Zongker99916f02014-01-13 14:16:58 -080076
Tao Baoc3292f32016-11-04 10:52:13 -070077 std::vector<std::string> lines = android::base::Split(android::base::Trim(content), "\n");
78 if (lines.size() < 4) {
79 LOG(ERROR) << "Block map file is too short: " << lines.size();
80 return -1;
81 }
Doug Zongker99916f02014-01-13 14:16:58 -080082
Tao Baoc3292f32016-11-04 10:52:13 -070083 size_t size;
84 unsigned int blksize;
85 if (sscanf(lines[1].c_str(), "%zu %u", &size, &blksize) != 2) {
86 LOG(ERROR) << "Failed to parse file size and block size: " << lines[1];
87 return -1;
88 }
Doug Zongker99916f02014-01-13 14:16:58 -080089
Tao Baoc3292f32016-11-04 10:52:13 -070090 size_t range_count;
91 if (sscanf(lines[2].c_str(), "%zu", &range_count) != 1) {
92 LOG(ERROR) << "Failed to parse block map header: " << lines[2];
93 return -1;
94 }
Doug Zongker99916f02014-01-13 14:16:58 -080095
Tao Baoc3292f32016-11-04 10:52:13 -070096 size_t blocks;
97 if (blksize != 0) {
98 blocks = ((size - 1) / blksize) + 1;
99 }
100 if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0 ||
101 lines.size() != 3 + range_count) {
102 LOG(ERROR) << "Invalid data in block map file: size " << size << ", blksize " << blksize
103 << ", range_count " << range_count << ", lines " << lines.size();
104 return -1;
105 }
Doug Zongker99916f02014-01-13 14:16:58 -0800106
Tao Baoc3292f32016-11-04 10:52:13 -0700107 // Reserve enough contiguous address space for the whole file.
108 void* reserve = mmap64(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
109 if (reserve == MAP_FAILED) {
110 PLOG(ERROR) << "failed to reserve address space";
111 return -1;
112 }
Doug Zongker99916f02014-01-13 14:16:58 -0800113
Tao Baoc3292f32016-11-04 10:52:13 -0700114 const std::string& block_dev = lines[0];
115 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(block_dev.c_str(), O_RDONLY)));
116 if (fd == -1) {
117 PLOG(ERROR) << "failed to open block device " << block_dev;
118 munmap(reserve, blocks * blksize);
119 return -1;
120 }
Doug Zongker99916f02014-01-13 14:16:58 -0800121
Tao Baoc3292f32016-11-04 10:52:13 -0700122 pMap->ranges.resize(range_count);
123
124 unsigned char* next = static_cast<unsigned char*>(reserve);
125 size_t remaining_size = blocks * blksize;
126 bool success = true;
127 for (size_t i = 0; i < range_count; ++i) {
128 const std::string& line = lines[i + 3];
129
130 size_t start, end;
131 if (sscanf(line.c_str(), "%zu %zu\n", &start, &end) != 2) {
132 LOG(ERROR) << "failed to parse range " << i << " in block map: " << line;
Yabin Cui4f2df162016-02-18 11:32:10 -0800133 success = false;
Tao Baoc3292f32016-11-04 10:52:13 -0700134 break;
Yabin Cui4f2df162016-02-18 11:32:10 -0800135 }
Tao Baoc3292f32016-11-04 10:52:13 -0700136 size_t length = (end - start) * blksize;
137 if (end <= start || (end - start) > SIZE_MAX / blksize || length > remaining_size) {
138 LOG(ERROR) << "unexpected range in block map: " << start << " " << end;
139 success = false;
140 break;
141 }
142
143 void* addr = mmap64(next, length, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd,
144 static_cast<off64_t>(start) * blksize);
145 if (addr == MAP_FAILED) {
146 PLOG(ERROR) << "failed to map block " << i;
147 success = false;
148 break;
149 }
150 pMap->ranges[i].addr = addr;
151 pMap->ranges[i].length = length;
152
153 next += length;
154 remaining_size -= length;
155 }
156 if (success && remaining_size != 0) {
157 LOG(ERROR) << "ranges in block map are invalid: remaining_size = " << remaining_size;
158 success = false;
159 }
160 if (!success) {
161 munmap(reserve, blocks * blksize);
162 return -1;
163 }
164
165 pMap->addr = static_cast<unsigned char*>(reserve);
166 pMap->length = size;
167
168 LOG(INFO) << "mmapped " << range_count << " ranges";
169
170 return 0;
171}
172
173int sysMapFile(const char* fn, MemMapping* pMap) {
174 if (fn == nullptr || pMap == nullptr) {
175 LOG(ERROR) << "Invalid argument(s)";
176 return -1;
177 }
178
179 *pMap = {};
180
181 if (fn[0] == '@') {
182 if (sysMapBlockFile(fn + 1, pMap) != 0) {
183 LOG(ERROR) << "Map of '" << fn << "' failed";
184 return -1;
185 }
186 } else {
187 // This is a regular file.
188 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(fn, O_RDONLY)));
189 if (fd == -1) {
190 PLOG(ERROR) << "Unable to open '" << fn << "'";
Yabin Cui4f2df162016-02-18 11:32:10 -0800191 return -1;
Doug Zongker99916f02014-01-13 14:16:58 -0800192 }
193
Tao Baoc3292f32016-11-04 10:52:13 -0700194 if (!sysMapFD(fd, pMap)) {
195 LOG(ERROR) << "Map of '" << fn << "' failed";
196 return -1;
Doug Zongker99916f02014-01-13 14:16:58 -0800197 }
Tao Baoc3292f32016-11-04 10:52:13 -0700198 }
199 return 0;
Doug Zongker99916f02014-01-13 14:16:58 -0800200}
201
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800202/*
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800203 * Release a memory mapping.
204 */
Tao Baoc3292f32016-11-04 10:52:13 -0700205void sysReleaseMap(MemMapping* pMap) {
206 std::for_each(pMap->ranges.cbegin(), pMap->ranges.cend(), [](const MappedRange& range) {
207 if (munmap(range.addr, range.length) == -1) {
208 PLOG(ERROR) << "munmap(" << range.addr << ", " << range.length << ") failed";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800209 }
Tao Baoc3292f32016-11-04 10:52:13 -0700210 });
211 pMap->ranges.clear();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800212}