blob: f322e032632e591024fd0595679cc7e611cfc63f [file] [log] [blame]
Jeff Sharkey9c484982015-03-31 10:35:33 -07001/*
2 * Copyright (C) 2015 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
Jeff Sharkey9c484982015-03-31 10:35:33 -070017#include "PrivateVolume.h"
Jeff Sharkey3161fb32015-04-12 16:03:33 -070018#include "EmulatedVolume.h"
Jeff Sharkey9c484982015-03-31 10:35:33 -070019#include "Utils.h"
20#include "VolumeManager.h"
Jeff Sharkey9c484982015-03-31 10:35:33 -070021#include "cryptfs.h"
Paul Crowley14c8c072018-09-18 13:30:21 -070022#include "fs/Ext4.h"
23#include "fs/F2fs.h"
Gaurav Kashyap64e4ccd2019-07-17 18:11:57 -070024#include "MetadataCrypt.h"
25#include "FsCrypt.h"
Jeff Sharkey9c484982015-03-31 10:35:33 -070026
Elliott Hughes7e128fb2015-12-04 15:50:53 -080027#include <android-base/logging.h>
Paul Crowley14c8c072018-09-18 13:30:21 -070028#include <android-base/stringprintf.h>
Jeff Sharkey9c484982015-03-31 10:35:33 -070029#include <cutils/fs.h>
30#include <private/android_filesystem_config.h>
31
32#include <fcntl.h>
33#include <stdlib.h>
34#include <sys/mount.h>
Jeff Sharkey9c484982015-03-31 10:35:33 -070035#include <sys/param.h>
Paul Crowley14c8c072018-09-18 13:30:21 -070036#include <sys/stat.h>
37#include <sys/sysmacros.h>
38#include <sys/types.h>
39#include <sys/wait.h>
Jeff Sharkey9c484982015-03-31 10:35:33 -070040
Shivaprasad Hongal6fe1ecb2018-10-24 17:49:39 -070041#define RETRY_MOUNT_ATTEMPTS 10
42#define RETRY_MOUNT_DELAY_SECONDS 1
43
Gaurav Kashyap64e4ccd2019-07-17 18:11:57 -070044constexpr int FS_AES_256_XTS_KEY_SIZE = 64;
45
Jeff Sharkey9c484982015-03-31 10:35:33 -070046using android::base::StringPrintf;
47
48namespace android {
49namespace vold {
50
Jeff Sharkeyd0640f62015-05-21 22:35:42 -070051static const unsigned int kMajorBlockMmc = 179;
52
Gaurav Kashyap64e4ccd2019-07-17 18:11:57 -070053PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw, int flags)
54 : VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw),
55 mDiskFlags(flags) {
Jeff Sharkey9c484982015-03-31 10:35:33 -070056 setId(StringPrintf("private:%u,%u", major(device), minor(device)));
57 mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
Jeff Sharkey9c484982015-03-31 10:35:33 -070058}
59
Paul Crowley14c8c072018-09-18 13:30:21 -070060PrivateVolume::~PrivateVolume() {}
Jeff Sharkey9c484982015-03-31 10:35:33 -070061
62status_t PrivateVolume::readMetadata() {
Jeff Sharkey3472e522017-10-06 18:02:53 -060063 status_t res = ReadMetadata(mDmDevPath, &mFsType, &mFsUuid, &mFsLabel);
Jeff Sharkeycbe69fc2017-09-15 16:50:28 -060064
Jeff Sharkey814e9d32017-09-13 11:49:44 -060065 auto listener = getListener();
66 if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
Jeff Sharkeycbe69fc2017-09-15 16:50:28 -060067
Jeff Sharkey9c484982015-03-31 10:35:33 -070068 return res;
69}
70
71status_t PrivateVolume::doCreate() {
72 if (CreateDeviceNode(mRawDevPath, mRawDevice)) {
73 return -EIO;
74 }
Gaurav Kashyap64e4ccd2019-07-17 18:11:57 -070075
76 if (is_ice_supported_external(mDiskFlags)) {
77 if (mKeyRaw.size() != FS_AES_256_XTS_KEY_SIZE) {
78 PLOG(ERROR) << getId() << " Keysize " << mKeyRaw.size()
79 << " does not match AES XTS keysize " << FS_AES_256_XTS_KEY_SIZE;
80 return -EIO;
81 }
82 } else {
83 if (mKeyRaw.size() != cryptfs_get_keysize()) {
84 PLOG(ERROR) << getId() << " Raw keysize " << mKeyRaw.size()
85 << " does not match crypt keysize " << cryptfs_get_keysize();
86 return -EIO;
87 }
Greg Kaiser57f9af62018-02-16 13:13:58 -080088 }
Jeff Sharkey9c484982015-03-31 10:35:33 -070089
90 // Recover from stale vold by tearing down any old mappings
91 cryptfs_revert_ext_volume(getId().c_str());
92
93 // TODO: figure out better SELinux labels for private volumes
94
Paul Crowley14c8c072018-09-18 13:30:21 -070095 unsigned char* key = (unsigned char*)mKeyRaw.data();
Jeff Sharkey9c484982015-03-31 10:35:33 -070096 char crypto_blkdev[MAXPATHLEN];
Gaurav Kashyap64e4ccd2019-07-17 18:11:57 -070097 int res = 0;
98
99 if (is_ice_supported_external(mDiskFlags))
100 res = fscrypt_setup_ufscard_volume (getId(), mRawDevPath, mKeyRaw, mDmDevPath);
101 else {
102 res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(),
103 key, crypto_blkdev);
104 mDmDevPath = crypto_blkdev;
105 }
106
Jeff Sharkey9c484982015-03-31 10:35:33 -0700107 if (res != 0) {
108 PLOG(ERROR) << getId() << " failed to setup cryptfs";
109 return -EIO;
110 }
111
Shivaprasad Hongal6fe1ecb2018-10-24 17:49:39 -0700112 int fd = 0;
113 int retries = RETRY_MOUNT_ATTEMPTS;
Gaurav Kashyap28d51782019-09-11 15:19:55 -0700114 while ((fd = open(mDmDevPath.c_str(), O_WRONLY|O_CLOEXEC)) < 0) {
Shivaprasad Hongal6fe1ecb2018-10-24 17:49:39 -0700115 if (retries > 0) {
116 retries--;
Gaurav Kashyap28d51782019-09-11 15:19:55 -0700117 PLOG(ERROR) << "Error opening crypto_blkdev " << mDmDevPath.c_str()
Shivaprasad Hongal6fe1ecb2018-10-24 17:49:39 -0700118 << " for private volume. err=" << errno
119 << "(" << strerror(errno) << "), retrying for the "
120 << RETRY_MOUNT_ATTEMPTS - retries << " time";
121 sleep(RETRY_MOUNT_DELAY_SECONDS);
122 } else {
Gaurav Kashyap28d51782019-09-11 15:19:55 -0700123 PLOG(ERROR) << "Error opening crypto_blkdev " << mDmDevPath.c_str()
Shivaprasad Hongal6fe1ecb2018-10-24 17:49:39 -0700124 << " for private volume. err=" << errno
125 << "(" << strerror(errno) << "), retried "
126 << RETRY_MOUNT_ATTEMPTS << " times";
127 close(fd);
128 return -EIO;
129 }
130 }
131 close(fd);
Jeff Sharkey9c484982015-03-31 10:35:33 -0700132 return OK;
133}
134
135status_t PrivateVolume::doDestroy() {
136 if (cryptfs_revert_ext_volume(getId().c_str())) {
137 LOG(ERROR) << getId() << " failed to revert cryptfs";
138 }
139 return DestroyDeviceNode(mRawDevPath);
140}
141
142status_t PrivateVolume::doMount() {
143 if (readMetadata()) {
144 LOG(ERROR) << getId() << " failed to read metadata";
145 return -EIO;
146 }
147
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700148 mPath = StringPrintf("/mnt/expand/%s", mFsUuid.c_str());
149 setPath(mPath);
150
151 if (PrepareDir(mPath, 0700, AID_ROOT, AID_ROOT)) {
152 PLOG(ERROR) << getId() << " failed to create mount point " << mPath;
153 return -EIO;
154 }
155
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700156 if (mFsType == "ext4") {
Michael Bestas86918bf2015-12-06 23:53:55 +0200157 int res = ext4::Check(mDmDevPath, mPath, true);
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700158 if (res == 0 || res == 1) {
159 LOG(DEBUG) << getId() << " passed filesystem check";
160 } else {
161 PLOG(ERROR) << getId() << " failed filesystem check";
162 return -EIO;
163 }
Jeff Sharkey9c484982015-03-31 10:35:33 -0700164
Sam Mortimer09aef342015-11-27 15:27:03 -0800165 if (ext4::Mount(mDmDevPath, mPath, false, false, true, "", true)) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700166 PLOG(ERROR) << getId() << " failed to mount";
167 return -EIO;
168 }
169
170 } else if (mFsType == "f2fs") {
Michael Bestas86918bf2015-12-06 23:53:55 +0200171 int res = f2fs::Check(mDmDevPath, true);
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700172 if (res == 0) {
173 LOG(DEBUG) << getId() << " passed filesystem check";
174 } else {
175 PLOG(ERROR) << getId() << " failed filesystem check";
176 return -EIO;
177 }
178
Sam Mortimer09aef342015-11-27 15:27:03 -0800179 if (f2fs::Mount(mDmDevPath, mPath, "", true)) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700180 PLOG(ERROR) << getId() << " failed to mount";
181 return -EIO;
182 }
183
184 } else {
185 LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700186 return -EIO;
187 }
188
Jeff Sharkeyd24aeda2016-07-15 16:20:22 -0600189 RestoreconRecursive(mPath);
Jeff Sharkey34824122015-06-09 10:59:17 -0700190
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700191 // Verify that common directories are ready to roll
192 if (PrepareDir(mPath + "/app", 0771, AID_SYSTEM, AID_SYSTEM) ||
Paul Crowley14c8c072018-09-18 13:30:21 -0700193 PrepareDir(mPath + "/user", 0711, AID_SYSTEM, AID_SYSTEM) ||
194 PrepareDir(mPath + "/user_de", 0711, AID_SYSTEM, AID_SYSTEM) ||
195 PrepareDir(mPath + "/media", 0770, AID_MEDIA_RW, AID_MEDIA_RW) ||
196 PrepareDir(mPath + "/media/0", 0770, AID_MEDIA_RW, AID_MEDIA_RW) ||
197 PrepareDir(mPath + "/local", 0751, AID_ROOT, AID_ROOT) ||
198 PrepareDir(mPath + "/local/tmp", 0771, AID_SHELL, AID_SHELL)) {
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700199 PLOG(ERROR) << getId() << " failed to prepare";
200 return -EIO;
201 }
202
Jeff Sharkey3161fb32015-04-12 16:03:33 -0700203 // Create a new emulated volume stacked above us, it will automatically
204 // be destroyed during unmount
205 std::string mediaPath(mPath + "/media");
Paul Crowley14c8c072018-09-18 13:30:21 -0700206 auto vol = std::shared_ptr<VolumeBase>(new EmulatedVolume(mediaPath, mRawDevice, mFsUuid));
Jeff Sharkey3161fb32015-04-12 16:03:33 -0700207 addVolume(vol);
208 vol->create();
209
Jeff Sharkey9c484982015-03-31 10:35:33 -0700210 return OK;
211}
212
213status_t PrivateVolume::doUnmount() {
214 ForceUnmount(mPath);
215
216 if (TEMP_FAILURE_RETRY(rmdir(mPath.c_str()))) {
217 PLOG(ERROR) << getId() << " failed to rmdir mount point " << mPath;
218 }
219
220 return OK;
221}
222
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700223status_t PrivateVolume::doFormat(const std::string& fsType) {
224 std::string resolvedFsType = fsType;
225 if (fsType == "auto") {
226 // For now, assume that all MMC devices are flash-based SD cards, and
227 // give everyone else ext4 because sysfs rotational isn't reliable.
Gaurav Kashyap64e4ccd2019-07-17 18:11:57 -0700228 if (((major(mRawDevice) == kMajorBlockMmc) ||
229 ((mDiskFlags & android::vold::Disk::Flags::kUfsCard) ==
230 android::vold::Disk::Flags::kUfsCard)) &&
231 f2fs::IsSupported()) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700232 resolvedFsType = "f2fs";
233 } else {
234 resolvedFsType = "ext4";
235 }
236 LOG(DEBUG) << "Resolved auto to " << resolvedFsType;
237 }
238
239 if (resolvedFsType == "ext4") {
240 // TODO: change reported mountpoint once we have better selinux support
241 if (ext4::Format(mDmDevPath, 0, "/data")) {
242 PLOG(ERROR) << getId() << " failed to format";
243 return -EIO;
244 }
245 } else if (resolvedFsType == "f2fs") {
246 if (f2fs::Format(mDmDevPath)) {
247 PLOG(ERROR) << getId() << " failed to format";
248 return -EIO;
249 }
250 } else {
251 LOG(ERROR) << getId() << " unsupported filesystem " << fsType;
252 return -EINVAL;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700253 }
254
255 return OK;
256}
257
258} // namespace vold
259} // namespace android