1*f40fafd4SAndroid Build Coastguard Worker /*
2*f40fafd4SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*f40fafd4SAndroid Build Coastguard Worker *
4*f40fafd4SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*f40fafd4SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*f40fafd4SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*f40fafd4SAndroid Build Coastguard Worker *
8*f40fafd4SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*f40fafd4SAndroid Build Coastguard Worker *
10*f40fafd4SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*f40fafd4SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*f40fafd4SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f40fafd4SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*f40fafd4SAndroid Build Coastguard Worker * limitations under the License.
15*f40fafd4SAndroid Build Coastguard Worker */
16*f40fafd4SAndroid Build Coastguard Worker
17*f40fafd4SAndroid Build Coastguard Worker #include "PrivateVolume.h"
18*f40fafd4SAndroid Build Coastguard Worker #include "EmulatedVolume.h"
19*f40fafd4SAndroid Build Coastguard Worker #include "Utils.h"
20*f40fafd4SAndroid Build Coastguard Worker #include "VolumeEncryption.h"
21*f40fafd4SAndroid Build Coastguard Worker #include "VolumeManager.h"
22*f40fafd4SAndroid Build Coastguard Worker #include "fs/Ext4.h"
23*f40fafd4SAndroid Build Coastguard Worker #include "fs/F2fs.h"
24*f40fafd4SAndroid Build Coastguard Worker
25*f40fafd4SAndroid Build Coastguard Worker #include <android-base/logging.h>
26*f40fafd4SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
27*f40fafd4SAndroid Build Coastguard Worker #include <cutils/fs.h>
28*f40fafd4SAndroid Build Coastguard Worker #include <libdm/dm.h>
29*f40fafd4SAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
30*f40fafd4SAndroid Build Coastguard Worker
31*f40fafd4SAndroid Build Coastguard Worker #include <fcntl.h>
32*f40fafd4SAndroid Build Coastguard Worker #include <stdlib.h>
33*f40fafd4SAndroid Build Coastguard Worker #include <sys/mount.h>
34*f40fafd4SAndroid Build Coastguard Worker #include <sys/param.h>
35*f40fafd4SAndroid Build Coastguard Worker #include <sys/stat.h>
36*f40fafd4SAndroid Build Coastguard Worker #include <sys/sysmacros.h>
37*f40fafd4SAndroid Build Coastguard Worker #include <sys/types.h>
38*f40fafd4SAndroid Build Coastguard Worker #include <sys/wait.h>
39*f40fafd4SAndroid Build Coastguard Worker #include <thread>
40*f40fafd4SAndroid Build Coastguard Worker
41*f40fafd4SAndroid Build Coastguard Worker using android::base::StringPrintf;
42*f40fafd4SAndroid Build Coastguard Worker using android::vold::IsVirtioBlkDevice;
43*f40fafd4SAndroid Build Coastguard Worker
44*f40fafd4SAndroid Build Coastguard Worker namespace android {
45*f40fafd4SAndroid Build Coastguard Worker namespace vold {
46*f40fafd4SAndroid Build Coastguard Worker
47*f40fafd4SAndroid Build Coastguard Worker static const unsigned int kMajorBlockLoop = 7;
48*f40fafd4SAndroid Build Coastguard Worker static const unsigned int kMajorBlockHdd = 8;
49*f40fafd4SAndroid Build Coastguard Worker static const unsigned int kMajorBlockMmc = 179;
50*f40fafd4SAndroid Build Coastguard Worker
PrivateVolume(dev_t device,const KeyBuffer & keyRaw)51*f40fafd4SAndroid Build Coastguard Worker PrivateVolume::PrivateVolume(dev_t device, const KeyBuffer& keyRaw)
52*f40fafd4SAndroid Build Coastguard Worker : VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) {
53*f40fafd4SAndroid Build Coastguard Worker setId(StringPrintf("private:%u,%u", major(device), minor(device)));
54*f40fafd4SAndroid Build Coastguard Worker mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
55*f40fafd4SAndroid Build Coastguard Worker }
56*f40fafd4SAndroid Build Coastguard Worker
~PrivateVolume()57*f40fafd4SAndroid Build Coastguard Worker PrivateVolume::~PrivateVolume() {}
58*f40fafd4SAndroid Build Coastguard Worker
readMetadata()59*f40fafd4SAndroid Build Coastguard Worker status_t PrivateVolume::readMetadata() {
60*f40fafd4SAndroid Build Coastguard Worker status_t res = ReadMetadata(mDmDevPath, &mFsType, &mFsUuid, &mFsLabel);
61*f40fafd4SAndroid Build Coastguard Worker
62*f40fafd4SAndroid Build Coastguard Worker auto listener = getListener();
63*f40fafd4SAndroid Build Coastguard Worker if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
64*f40fafd4SAndroid Build Coastguard Worker
65*f40fafd4SAndroid Build Coastguard Worker return res;
66*f40fafd4SAndroid Build Coastguard Worker }
67*f40fafd4SAndroid Build Coastguard Worker
doCreate()68*f40fafd4SAndroid Build Coastguard Worker status_t PrivateVolume::doCreate() {
69*f40fafd4SAndroid Build Coastguard Worker if (CreateDeviceNode(mRawDevPath, mRawDevice)) {
70*f40fafd4SAndroid Build Coastguard Worker return -EIO;
71*f40fafd4SAndroid Build Coastguard Worker }
72*f40fafd4SAndroid Build Coastguard Worker
73*f40fafd4SAndroid Build Coastguard Worker // Recover from stale vold by tearing down any old mappings
74*f40fafd4SAndroid Build Coastguard Worker auto& dm = dm::DeviceMapper::Instance();
75*f40fafd4SAndroid Build Coastguard Worker // TODO(b/149396179) there appears to be a race somewhere in the system where trying
76*f40fafd4SAndroid Build Coastguard Worker // to delete the device fails with EBUSY; for now, work around this by retrying.
77*f40fafd4SAndroid Build Coastguard Worker bool ret;
78*f40fafd4SAndroid Build Coastguard Worker int tries = 10;
79*f40fafd4SAndroid Build Coastguard Worker while (tries-- > 0) {
80*f40fafd4SAndroid Build Coastguard Worker ret = dm.DeleteDeviceIfExists(getId());
81*f40fafd4SAndroid Build Coastguard Worker if (ret || errno != EBUSY) {
82*f40fafd4SAndroid Build Coastguard Worker break;
83*f40fafd4SAndroid Build Coastguard Worker }
84*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << "Cannot remove dm device " << getId();
85*f40fafd4SAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(100));
86*f40fafd4SAndroid Build Coastguard Worker }
87*f40fafd4SAndroid Build Coastguard Worker if (!ret) {
88*f40fafd4SAndroid Build Coastguard Worker return -EIO;
89*f40fafd4SAndroid Build Coastguard Worker }
90*f40fafd4SAndroid Build Coastguard Worker
91*f40fafd4SAndroid Build Coastguard Worker // TODO: figure out better SELinux labels for private volumes
92*f40fafd4SAndroid Build Coastguard Worker
93*f40fafd4SAndroid Build Coastguard Worker if (!setup_ext_volume(getId(), mRawDevPath, mKeyRaw, &mDmDevPath)) {
94*f40fafd4SAndroid Build Coastguard Worker LOG(ERROR) << getId() << " failed to setup metadata encryption";
95*f40fafd4SAndroid Build Coastguard Worker return -EIO;
96*f40fafd4SAndroid Build Coastguard Worker }
97*f40fafd4SAndroid Build Coastguard Worker
98*f40fafd4SAndroid Build Coastguard Worker return OK;
99*f40fafd4SAndroid Build Coastguard Worker }
100*f40fafd4SAndroid Build Coastguard Worker
doDestroy()101*f40fafd4SAndroid Build Coastguard Worker status_t PrivateVolume::doDestroy() {
102*f40fafd4SAndroid Build Coastguard Worker auto& dm = dm::DeviceMapper::Instance();
103*f40fafd4SAndroid Build Coastguard Worker // TODO(b/149396179) there appears to be a race somewhere in the system where trying
104*f40fafd4SAndroid Build Coastguard Worker // to delete the device fails with EBUSY; for now, work around this by retrying.
105*f40fafd4SAndroid Build Coastguard Worker bool ret;
106*f40fafd4SAndroid Build Coastguard Worker int tries = 10;
107*f40fafd4SAndroid Build Coastguard Worker while (tries-- > 0) {
108*f40fafd4SAndroid Build Coastguard Worker ret = dm.DeleteDevice(getId());
109*f40fafd4SAndroid Build Coastguard Worker if (ret || errno != EBUSY) {
110*f40fafd4SAndroid Build Coastguard Worker break;
111*f40fafd4SAndroid Build Coastguard Worker }
112*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << "Cannot remove dm device " << getId();
113*f40fafd4SAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(100));
114*f40fafd4SAndroid Build Coastguard Worker }
115*f40fafd4SAndroid Build Coastguard Worker if (!ret) {
116*f40fafd4SAndroid Build Coastguard Worker return -EIO;
117*f40fafd4SAndroid Build Coastguard Worker }
118*f40fafd4SAndroid Build Coastguard Worker return DestroyDeviceNode(mRawDevPath);
119*f40fafd4SAndroid Build Coastguard Worker }
120*f40fafd4SAndroid Build Coastguard Worker
doMount()121*f40fafd4SAndroid Build Coastguard Worker status_t PrivateVolume::doMount() {
122*f40fafd4SAndroid Build Coastguard Worker if (readMetadata()) {
123*f40fafd4SAndroid Build Coastguard Worker LOG(ERROR) << getId() << " failed to read metadata";
124*f40fafd4SAndroid Build Coastguard Worker return -EIO;
125*f40fafd4SAndroid Build Coastguard Worker }
126*f40fafd4SAndroid Build Coastguard Worker
127*f40fafd4SAndroid Build Coastguard Worker mPath = StringPrintf("/mnt/expand/%s", mFsUuid.c_str());
128*f40fafd4SAndroid Build Coastguard Worker setPath(mPath);
129*f40fafd4SAndroid Build Coastguard Worker
130*f40fafd4SAndroid Build Coastguard Worker if (PrepareDir(mPath, 0700, AID_ROOT, AID_ROOT)) {
131*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to create mount point " << mPath;
132*f40fafd4SAndroid Build Coastguard Worker return -EIO;
133*f40fafd4SAndroid Build Coastguard Worker }
134*f40fafd4SAndroid Build Coastguard Worker
135*f40fafd4SAndroid Build Coastguard Worker if (mFsType == "ext4") {
136*f40fafd4SAndroid Build Coastguard Worker int res = ext4::Check(mDmDevPath, mPath);
137*f40fafd4SAndroid Build Coastguard Worker if (res == 0 || res == 1) {
138*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << getId() << " passed filesystem check";
139*f40fafd4SAndroid Build Coastguard Worker } else {
140*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed filesystem check";
141*f40fafd4SAndroid Build Coastguard Worker return -EIO;
142*f40fafd4SAndroid Build Coastguard Worker }
143*f40fafd4SAndroid Build Coastguard Worker
144*f40fafd4SAndroid Build Coastguard Worker if (ext4::Mount(mDmDevPath, mPath, false, false, true)) {
145*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to mount";
146*f40fafd4SAndroid Build Coastguard Worker return -EIO;
147*f40fafd4SAndroid Build Coastguard Worker }
148*f40fafd4SAndroid Build Coastguard Worker
149*f40fafd4SAndroid Build Coastguard Worker } else if (mFsType == "f2fs") {
150*f40fafd4SAndroid Build Coastguard Worker int res = f2fs::Check(mDmDevPath);
151*f40fafd4SAndroid Build Coastguard Worker if (res == 0) {
152*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << getId() << " passed filesystem check";
153*f40fafd4SAndroid Build Coastguard Worker } else {
154*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed filesystem check";
155*f40fafd4SAndroid Build Coastguard Worker return -EIO;
156*f40fafd4SAndroid Build Coastguard Worker }
157*f40fafd4SAndroid Build Coastguard Worker
158*f40fafd4SAndroid Build Coastguard Worker if (f2fs::Mount(mDmDevPath, mPath)) {
159*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to mount";
160*f40fafd4SAndroid Build Coastguard Worker return -EIO;
161*f40fafd4SAndroid Build Coastguard Worker }
162*f40fafd4SAndroid Build Coastguard Worker
163*f40fafd4SAndroid Build Coastguard Worker } else {
164*f40fafd4SAndroid Build Coastguard Worker LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
165*f40fafd4SAndroid Build Coastguard Worker return -EIO;
166*f40fafd4SAndroid Build Coastguard Worker }
167*f40fafd4SAndroid Build Coastguard Worker
168*f40fafd4SAndroid Build Coastguard Worker RestoreconRecursive(mPath);
169*f40fafd4SAndroid Build Coastguard Worker
170*f40fafd4SAndroid Build Coastguard Worker int attrs = 0;
171*f40fafd4SAndroid Build Coastguard Worker if (!IsSdcardfsUsed()) attrs = FS_CASEFOLD_FL;
172*f40fafd4SAndroid Build Coastguard Worker
173*f40fafd4SAndroid Build Coastguard Worker // Verify that common directories are ready to roll
174*f40fafd4SAndroid Build Coastguard Worker if (PrepareDir(mPath + "/app", 0771, AID_SYSTEM, AID_SYSTEM) ||
175*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/user", 0511, AID_SYSTEM, AID_SYSTEM) ||
176*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/user_de", 0511, AID_SYSTEM, AID_SYSTEM) ||
177*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/misc_ce", 0511, AID_SYSTEM, AID_SYSTEM) ||
178*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/misc_de", 0511, AID_SYSTEM, AID_SYSTEM) ||
179*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/media", 0550, AID_MEDIA_RW, AID_MEDIA_RW, attrs) ||
180*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/media/0", 0770, AID_MEDIA_RW, AID_MEDIA_RW) ||
181*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/local", 0751, AID_ROOT, AID_ROOT) ||
182*f40fafd4SAndroid Build Coastguard Worker PrepareDir(mPath + "/local/tmp", 0771, AID_SHELL, AID_SHELL)) {
183*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to prepare";
184*f40fafd4SAndroid Build Coastguard Worker return -EIO;
185*f40fafd4SAndroid Build Coastguard Worker }
186*f40fafd4SAndroid Build Coastguard Worker
187*f40fafd4SAndroid Build Coastguard Worker return OK;
188*f40fafd4SAndroid Build Coastguard Worker }
189*f40fafd4SAndroid Build Coastguard Worker
doPostMount()190*f40fafd4SAndroid Build Coastguard Worker void PrivateVolume::doPostMount() {
191*f40fafd4SAndroid Build Coastguard Worker auto vol_manager = VolumeManager::Instance();
192*f40fafd4SAndroid Build Coastguard Worker std::string mediaPath(mPath + "/media");
193*f40fafd4SAndroid Build Coastguard Worker
194*f40fafd4SAndroid Build Coastguard Worker // Create a new emulated volume stacked above us for all added users, they will automatically
195*f40fafd4SAndroid Build Coastguard Worker // be destroyed during unmount
196*f40fafd4SAndroid Build Coastguard Worker for (userid_t user : vol_manager->getStartedUsers()) {
197*f40fafd4SAndroid Build Coastguard Worker auto vol = std::shared_ptr<VolumeBase>(
198*f40fafd4SAndroid Build Coastguard Worker new EmulatedVolume(mediaPath, mRawDevice, mFsUuid, user));
199*f40fafd4SAndroid Build Coastguard Worker vol->setMountUserId(user);
200*f40fafd4SAndroid Build Coastguard Worker addVolume(vol);
201*f40fafd4SAndroid Build Coastguard Worker vol->create();
202*f40fafd4SAndroid Build Coastguard Worker }
203*f40fafd4SAndroid Build Coastguard Worker }
204*f40fafd4SAndroid Build Coastguard Worker
doUnmount()205*f40fafd4SAndroid Build Coastguard Worker status_t PrivateVolume::doUnmount() {
206*f40fafd4SAndroid Build Coastguard Worker ForceUnmount(mPath);
207*f40fafd4SAndroid Build Coastguard Worker
208*f40fafd4SAndroid Build Coastguard Worker if (TEMP_FAILURE_RETRY(rmdir(mPath.c_str()))) {
209*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to rmdir mount point " << mPath;
210*f40fafd4SAndroid Build Coastguard Worker }
211*f40fafd4SAndroid Build Coastguard Worker
212*f40fafd4SAndroid Build Coastguard Worker return OK;
213*f40fafd4SAndroid Build Coastguard Worker }
214*f40fafd4SAndroid Build Coastguard Worker
doFormat(const std::string & fsType)215*f40fafd4SAndroid Build Coastguard Worker status_t PrivateVolume::doFormat(const std::string& fsType) {
216*f40fafd4SAndroid Build Coastguard Worker std::string resolvedFsType = fsType;
217*f40fafd4SAndroid Build Coastguard Worker if (fsType == "auto") {
218*f40fafd4SAndroid Build Coastguard Worker // For now, assume that all MMC devices are flash-based SD cards, and
219*f40fafd4SAndroid Build Coastguard Worker // give everyone else ext4 because sysfs rotational isn't reliable.
220*f40fafd4SAndroid Build Coastguard Worker // Additionally, prefer f2fs for loop-based devices
221*f40fafd4SAndroid Build Coastguard Worker if ((major(mRawDevice) == kMajorBlockMmc ||
222*f40fafd4SAndroid Build Coastguard Worker major(mRawDevice) == kMajorBlockHdd ||
223*f40fafd4SAndroid Build Coastguard Worker major(mRawDevice) == kMajorBlockLoop ||
224*f40fafd4SAndroid Build Coastguard Worker IsVirtioBlkDevice(major(mRawDevice))) && f2fs::IsSupported()) {
225*f40fafd4SAndroid Build Coastguard Worker resolvedFsType = "f2fs";
226*f40fafd4SAndroid Build Coastguard Worker } else {
227*f40fafd4SAndroid Build Coastguard Worker resolvedFsType = "ext4";
228*f40fafd4SAndroid Build Coastguard Worker }
229*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Resolved auto to " << resolvedFsType;
230*f40fafd4SAndroid Build Coastguard Worker }
231*f40fafd4SAndroid Build Coastguard Worker
232*f40fafd4SAndroid Build Coastguard Worker if (resolvedFsType == "ext4") {
233*f40fafd4SAndroid Build Coastguard Worker // TODO: change reported mountpoint once we have better selinux support
234*f40fafd4SAndroid Build Coastguard Worker if (ext4::Format(mDmDevPath, 0, "/data")) {
235*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to format";
236*f40fafd4SAndroid Build Coastguard Worker return -EIO;
237*f40fafd4SAndroid Build Coastguard Worker }
238*f40fafd4SAndroid Build Coastguard Worker } else if (resolvedFsType == "f2fs") {
239*f40fafd4SAndroid Build Coastguard Worker if (f2fs::Format(mDmDevPath, false, {}, {})) {
240*f40fafd4SAndroid Build Coastguard Worker PLOG(ERROR) << getId() << " failed to format";
241*f40fafd4SAndroid Build Coastguard Worker return -EIO;
242*f40fafd4SAndroid Build Coastguard Worker }
243*f40fafd4SAndroid Build Coastguard Worker } else {
244*f40fafd4SAndroid Build Coastguard Worker LOG(ERROR) << getId() << " unsupported filesystem " << fsType;
245*f40fafd4SAndroid Build Coastguard Worker return -EINVAL;
246*f40fafd4SAndroid Build Coastguard Worker }
247*f40fafd4SAndroid Build Coastguard Worker
248*f40fafd4SAndroid Build Coastguard Worker return OK;
249*f40fafd4SAndroid Build Coastguard Worker }
250*f40fafd4SAndroid Build Coastguard Worker
251*f40fafd4SAndroid Build Coastguard Worker } // namespace vold
252*f40fafd4SAndroid Build Coastguard Worker } // namespace android
253