• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include "EmulatedVolume.h"
18 
19 #include "AppFuseUtil.h"
20 #include "Utils.h"
21 #include "VolumeBase.h"
22 #include "VolumeManager.h"
23 
24 #include <android-base/logging.h>
25 #include <android-base/properties.h>
26 #include <android-base/scopeguard.h>
27 #include <android-base/stringprintf.h>
28 #include <cutils/fs.h>
29 #include <private/android_filesystem_config.h>
30 #include <utils/Timers.h>
31 
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
36 #include <sys/sysmacros.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <android_vold_flags.h>
40 
41 using android::base::StringPrintf;
42 namespace flags = android::vold::flags;
43 
44 
45 namespace android {
46 namespace vold {
47 
48 static const char* kSdcardFsPath = "/system/bin/sdcard";
49 
EmulatedVolume(const std::string & rawPath,int userId)50 EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId)
51     : VolumeBase(Type::kEmulated) {
52     setId(StringPrintf("emulated;%u", userId));
53     mRawPath = rawPath;
54     mLabel = "emulated";
55     mFuseMounted = false;
56     mUseSdcardFs = IsSdcardfsUsed();
57     mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
58 }
59 
EmulatedVolume(const std::string & rawPath,dev_t device,const std::string & fsUuid,int userId)60 EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid,
61                                int userId)
62     : VolumeBase(Type::kEmulated) {
63     setId(StringPrintf("emulated:%u,%u;%u", major(device), minor(device), userId));
64     mRawPath = rawPath;
65     mLabel = fsUuid;
66     mFuseMounted = false;
67     mUseSdcardFs = IsSdcardfsUsed();
68     mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
69 }
70 
~EmulatedVolume()71 EmulatedVolume::~EmulatedVolume() {}
72 
getLabel() const73 std::string EmulatedVolume::getLabel() const {
74     // We could have migrated storage to an adopted private volume, so always
75     // call primary storage "emulated" to avoid media rescans.
76     if (getMountFlags() & MountFlags::kPrimary) {
77         return "emulated";
78     } else {
79         return mLabel;
80     }
81 }
82 
83 // Creates a bind mount from source to target
doFuseBindMount(const std::string & source,const std::string & target,std::list<std::string> & pathsToUnmount)84 static status_t doFuseBindMount(const std::string& source, const std::string& target,
85                                 std::list<std::string>& pathsToUnmount) {
86     LOG(INFO) << "Bind mounting " << source << " on " << target;
87     auto status = BindMount(source, target);
88     if (status != OK) {
89         return status;
90     }
91     LOG(INFO) << "Bind mounted " << source << " on " << target;
92     pathsToUnmount.push_front(target);
93     return OK;
94 }
95 
96 // Bind mounts the volume 'volume' onto this volume.
bindMountVolume(const EmulatedVolume & volume,std::list<std::string> & pathsToUnmount)97 status_t EmulatedVolume::bindMountVolume(const EmulatedVolume& volume,
98                                          std::list<std::string>& pathsToUnmount) {
99     int myUserId = getMountUserId();
100     int volumeUserId = volume.getMountUserId();
101     std::string label = volume.getLabel();
102 
103     // eg /mnt/user/10/emulated/10
104     std::string srcUserPath = GetFuseMountPathForUser(volumeUserId, label);
105     std::string srcPath = StringPrintf("%s/%d", srcUserPath.c_str(), volumeUserId);
106     // eg /mnt/user/0/emulated/10
107     std::string dstUserPath = GetFuseMountPathForUser(myUserId, label);
108     std::string dstPath = StringPrintf("%s/%d", dstUserPath.c_str(), volumeUserId);
109 
110     auto status = doFuseBindMount(srcPath, dstPath, pathsToUnmount);
111     if (status == OK) {
112         // Store the mount path, so we can unmount it when this volume goes away
113         mSharedStorageMountPath = dstPath;
114     }
115 
116     return status;
117 }
118 
getSharedStorageVolume(int userId)119 std::shared_ptr<android::vold::VolumeBase> getSharedStorageVolume(int userId) {
120     userid_t sharedStorageUserId = VolumeManager::Instance()->getSharedStorageUser(userId);
121     if (sharedStorageUserId != USER_UNKNOWN) {
122         auto filter_fn = [&](const VolumeBase &vol) {
123             if (vol.getState() != VolumeBase::State::kMounted) {
124                 // The volume must be mounted
125                 return false;
126             }
127             if (vol.getType() != VolumeBase::Type::kEmulated) {
128                 return false;
129             }
130             if (vol.getMountUserId() != sharedStorageUserId) {
131                 return false;
132             }
133             if ((vol.getMountFlags() & EmulatedVolume::MountFlags::kPrimary) == 0) {
134                 // We only care about the primary emulated volume, so not a private
135                 // volume with an emulated volume stacked on top.
136                 return false;
137             }
138             return true;
139         };
140         return VolumeManager::Instance()->findVolumeWithFilter(filter_fn);
141     }
142     return nullptr;
143 }
144 
mountFuseBindMounts()145 status_t EmulatedVolume::mountFuseBindMounts() {
146     std::string androidSource;
147     std::string label = getLabel();
148     int userId = getMountUserId();
149     std::list<std::string> pathsToUnmount;
150 
151     auto unmounter = [&]() {
152         LOG(INFO) << "mountFuseBindMounts() unmount scope_guard running";
153         for (const auto& path : pathsToUnmount) {
154             LOG(INFO) << "Unmounting " << path;
155             auto status = UnmountTree(path);
156             if (status != OK) {
157                 LOG(INFO) << "Failed to unmount " << path;
158             } else {
159                 LOG(INFO) << "Unmounted " << path;
160             }
161         }
162     };
163     auto unmount_guard = android::base::make_scope_guard(unmounter);
164 
165     if (mUseSdcardFs) {
166         androidSource = StringPrintf("/mnt/runtime/default/%s/%d/Android", label.c_str(), userId);
167     } else {
168         androidSource = StringPrintf("/%s/%d/Android", mRawPath.c_str(), userId);
169     }
170 
171     status_t status = OK;
172     // Zygote will unmount these dirs if app data isolation is enabled, so apps
173     // cannot access these dirs directly.
174     std::string androidDataSource = StringPrintf("%s/data", androidSource.c_str());
175     std::string androidDataTarget(
176             StringPrintf("/mnt/user/%d/%s/%d/Android/data", userId, label.c_str(), userId));
177     status = doFuseBindMount(androidDataSource, androidDataTarget, pathsToUnmount);
178     if (status != OK) {
179         return status;
180     }
181 
182     std::string androidObbSource = StringPrintf("%s/obb", androidSource.c_str());
183     std::string androidObbTarget(
184             StringPrintf("/mnt/user/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
185     status = doFuseBindMount(androidObbSource, androidObbTarget, pathsToUnmount);
186     if (status != OK) {
187         return status;
188     }
189 
190     // Installers get the same view as all other apps, with the sole exception that the
191     // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires
192     // a special bind mount, since app-private and OBB dirs share the same GID, but we
193     // only want to give access to the latter.
194     if (mUseSdcardFs) {
195         std::string obbSource(StringPrintf("/mnt/runtime/write/%s/%d/Android/obb",
196                 label.c_str(), userId));
197         std::string obbInstallerTarget(StringPrintf("/mnt/installer/%d/%s/%d/Android/obb",
198                 userId, label.c_str(), userId));
199 
200         status = doFuseBindMount(obbSource, obbInstallerTarget, pathsToUnmount);
201         if (status != OK) {
202             return status;
203         }
204     }
205 
206     // For users that share their volume with another user (eg a clone
207     // profile), the current mount setup can cause page cache inconsistency
208     // issues.  Let's say this is user 10, and the user it shares storage with
209     // is user 0.
210     // Then:
211     // * The FUSE daemon for user 0 serves /mnt/user/0
212     // * The FUSE daemon for user 10 serves /mnt/user/10
213     // The emulated volume for user 10 would be located at two paths:
214     // /mnt/user/0/emulated/10
215     // /mnt/user/10/emulated/10
216     // Since these paths refer to the same files but are served by different FUSE
217     // daemons, this can result in page cache inconsistency issues. To prevent this,
218     // bind mount the relevant paths for the involved users:
219     // 1. /mnt/user/10/emulated/10 =B=> /mnt/user/0/emulated/10
220     // 2. /mnt/user/0/emulated/0 =B=> /mnt/user/10/emulated/0
221     //
222     // This will ensure that any access to the volume for a specific user always
223     // goes through a single FUSE daemon.
224     auto vol = getSharedStorageVolume(userId);
225     if (vol != nullptr) {
226         auto sharedVol = static_cast<EmulatedVolume*>(vol.get());
227         // Bind mount this volume in the other user's primary volume
228         status = sharedVol->bindMountVolume(*this, pathsToUnmount);
229         if (status != OK) {
230             return status;
231         }
232         // And vice-versa
233         status = bindMountVolume(*sharedVol, pathsToUnmount);
234         if (status != OK) {
235             return status;
236         }
237     }
238 
239     unmount_guard.Disable();
240     return OK;
241 }
242 
unbindSharedStorageMountPath()243 status_t EmulatedVolume::unbindSharedStorageMountPath() {
244     if (!mSharedStorageMountPath.empty()) {
245         LOG(INFO) << "Unmounting " << mSharedStorageMountPath;
246         auto status = UnmountTree(mSharedStorageMountPath);
247         if (status != OK) {
248             LOG(ERROR) << "Failed to unmount " << mSharedStorageMountPath;
249         }
250         mSharedStorageMountPath = "";
251         return status;
252     }
253     return OK;
254 }
255 
256 
unmountFuseBindMounts()257 status_t EmulatedVolume::unmountFuseBindMounts() {
258     std::string label = getLabel();
259     int userId = getMountUserId();
260 
261     if (!mSharedStorageMountPath.empty()) {
262         unbindSharedStorageMountPath();
263         auto vol = getSharedStorageVolume(userId);
264         if (vol != nullptr) {
265             auto sharedVol = static_cast<EmulatedVolume*>(vol.get());
266             sharedVol->unbindSharedStorageMountPath();
267         }
268     }
269 
270     if (mUseSdcardFs || mAppDataIsolationEnabled) {
271         std::string installerTarget(
272                 StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
273         LOG(INFO) << "Unmounting " << installerTarget;
274         auto status = UnmountTree(installerTarget);
275         if (status != OK) {
276             LOG(ERROR) << "Failed to unmount " << installerTarget;
277             // Intentional continue to try to unmount the other bind mount
278         }
279     }
280     if (mAppDataIsolationEnabled) {
281         std::string obbTarget( StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/obb",
282                 userId, label.c_str(), userId));
283         LOG(INFO) << "Unmounting " << obbTarget;
284         auto status = UnmountTree(obbTarget);
285         if (status != OK) {
286             LOG(ERROR) << "Failed to unmount " << obbTarget;
287             // Intentional continue to try to unmount the other bind mount
288         }
289         std::string dataTarget(StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/data",
290                 userId, label.c_str(), userId));
291         LOG(INFO) << "Unmounting " << dataTarget;
292         status = UnmountTree(dataTarget);
293         if (status != OK) {
294             LOG(ERROR) << "Failed to unmount " << dataTarget;
295             // Intentional continue to try to unmount the other bind mount
296         }
297     }
298 
299     // When app data isolation is enabled, kill all apps that obb/ is mounted, otherwise we should
300     // umount the whole Android/ dir.
301     if (mAppDataIsolationEnabled) {
302         std::string appObbDir(StringPrintf("%s/%d/Android/obb", getPath().c_str(), userId));
303         // Here we assume obb/data dirs is mounted as tmpfs, then it must be caused by
304         // app data isolation.
305         KillProcessesWithTmpfsMountPrefix(appObbDir);
306     }
307 
308     // Always unmount data and obb dirs as they are mounted to lowerfs for speeding up access.
309     std::string androidDataTarget(
310             StringPrintf("/mnt/user/%d/%s/%d/Android/data", userId, label.c_str(), userId));
311 
312     LOG(INFO) << "Unmounting " << androidDataTarget;
313     auto status = UnmountTree(androidDataTarget);
314     if (status != OK) {
315         return status;
316     }
317     LOG(INFO) << "Unmounted " << androidDataTarget;
318 
319     std::string androidObbTarget(
320             StringPrintf("/mnt/user/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
321 
322     LOG(INFO) << "Unmounting " << androidObbTarget;
323     status = UnmountTree(androidObbTarget);
324     if (status != OK) {
325         return status;
326     }
327     LOG(INFO) << "Unmounted " << androidObbTarget;
328     return OK;
329 }
330 
unmountSdcardFs()331 status_t EmulatedVolume::unmountSdcardFs() {
332     if (!mUseSdcardFs || getMountUserId() != 0) {
333         // For sdcardfs, only unmount for user 0, since user 0 will always be running
334         // and the paths don't change for different users.
335         return OK;
336     }
337 
338     ForceUnmount(mSdcardFsDefault);
339     ForceUnmount(mSdcardFsRead);
340     ForceUnmount(mSdcardFsWrite);
341     ForceUnmount(mSdcardFsFull);
342 
343     rmdir(mSdcardFsDefault.c_str());
344     rmdir(mSdcardFsRead.c_str());
345     rmdir(mSdcardFsWrite.c_str());
346     rmdir(mSdcardFsFull.c_str());
347 
348     mSdcardFsDefault.clear();
349     mSdcardFsRead.clear();
350     mSdcardFsWrite.clear();
351     mSdcardFsFull.clear();
352 
353     return OK;
354 }
355 
doMount()356 status_t EmulatedVolume::doMount() {
357     std::string label = getLabel();
358     bool isVisible = isVisibleForWrite();
359 
360     mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str());
361     mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", label.c_str());
362     mSdcardFsWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str());
363     mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", label.c_str());
364 
365     setInternalPath(mRawPath);
366     setPath(StringPrintf("/storage/%s", label.c_str()));
367 
368     if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
369         fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
370         fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) ||
371         fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) {
372         PLOG(ERROR) << getId() << " failed to create mount points";
373         return -errno;
374     }
375 
376     dev_t before = GetDevice(mSdcardFsFull);
377 
378     // Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the
379     // FUSE volume for various reasons.
380     if (mUseSdcardFs && getMountUserId() == 0) {
381         LOG(INFO) << "Executing sdcardfs";
382         int sdcardFsPid;
383         if (!(sdcardFsPid = fork())) {
384             // clang-format off
385             if (execl(kSdcardFsPath, kSdcardFsPath,
386                     "-u", "1023", // AID_MEDIA_RW
387                     "-g", "1023", // AID_MEDIA_RW
388                     "-m",
389                     "-w",
390                     "-G",
391                     "-i",
392                     "-o",
393                     mRawPath.c_str(),
394                     label.c_str(),
395                     NULL)) {
396                 // clang-format on
397                 PLOG(ERROR) << "Failed to exec";
398             }
399 
400             LOG(ERROR) << "sdcardfs exiting";
401             _exit(1);
402         }
403 
404         if (sdcardFsPid == -1) {
405             PLOG(ERROR) << getId() << " failed to fork";
406             return -errno;
407         }
408 
409         nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
410         while (before == GetDevice(mSdcardFsFull)) {
411             LOG(DEBUG) << "Waiting for sdcardfs to spin up...";
412             usleep(50000);  // 50ms
413 
414             nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
415             if (nanoseconds_to_milliseconds(now - start) > 5000) {
416                 LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up";
417                 return -ETIMEDOUT;
418             }
419         }
420         /* sdcardfs will have exited already. The filesystem will still be running */
421         TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
422         sdcardFsPid = 0;
423     }
424 
425     if (isVisible) {
426         // Make sure we unmount sdcardfs if we bail out with an error below
427         auto sdcardfs_unmounter = [&]() {
428             LOG(INFO) << "sdcardfs_unmounter scope_guard running";
429             unmountSdcardFs();
430         };
431         auto sdcardfs_guard = android::base::make_scope_guard(sdcardfs_unmounter);
432 
433         LOG(INFO) << "Mounting emulated fuse volume";
434         android::base::unique_fd fd;
435         int user_id = getMountUserId();
436         auto volumeRoot = getRootPath();
437 
438         // Make sure Android/ dirs exist for bind mounting
439         status_t res = PrepareAndroidDirs(volumeRoot);
440         if (res != OK) {
441             LOG(ERROR) << "Failed to prepare Android/ directories";
442             return res;
443         }
444 
445         res = MountUserFuse(user_id, getInternalPath(), label, &fd);
446         if (res != 0) {
447             PLOG(ERROR) << "Failed to mount emulated fuse volume";
448             return res;
449         }
450 
451         mFuseMounted = true;
452         auto fuse_unmounter = [&]() {
453             LOG(INFO) << "fuse_unmounter scope_guard running";
454             fd.reset();
455             if (flags::enhance_fuse_unmount()) {
456                 std::string user_path(StringPrintf("%s/%d", getPath().c_str(), getMountUserId()));
457                 if (UnmountUserFuseEnhanced(user_id, getInternalPath(), label, user_path) != OK) {
458                     PLOG(INFO) << "UnmountUserFuseEnhanced failed on emulated fuse volume";
459                 }
460             } else {
461                 if (UnmountUserFuse(user_id, getInternalPath(), label) != OK) {
462                     PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
463                 }
464             }
465 
466             mFuseMounted = false;
467         };
468         auto fuse_guard = android::base::make_scope_guard(fuse_unmounter);
469 
470         auto callback = getMountCallback();
471         if (callback) {
472             bool is_ready = false;
473             callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready);
474             if (!is_ready) {
475                 return -EIO;
476             }
477         }
478 
479         if (!IsFuseBpfEnabled()) {
480             // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
481             res = mountFuseBindMounts();
482             if (res != OK) {
483                 return res;
484             }
485         }
486 
487         ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, label), 256u);
488 
489         // By default, FUSE has a max_dirty ratio of 1%. This means that out of
490         // all dirty pages in the system, only 1% is allowed to belong to any
491         // FUSE filesystem. The reason this is in place is that FUSE
492         // filesystems shouldn't be trusted by default; a FUSE filesystem could
493         // take up say 100% of dirty pages, and subsequently refuse to write
494         // them back to storage.  The kernel will then apply rate-limiting, and
495         // block other tasks from writing.  For this particular FUSE filesystem
496         // however, we trust the implementation, because it is a part of the
497         // Android platform. So use the default ratio of 100%.
498         //
499         // The reason we're setting this is that there's a suspicion that the
500         // kernel starts rate-limiting the FUSE filesystem under extreme
501         // memory pressure scenarios. While the kernel will only rate limit if
502         // the writeback can't keep up with the write rate, under extreme
503         // memory pressure the write rate may dip as well, in which case FUSE
504         // writes to a 1% max_ratio filesystem are throttled to an extreme amount.
505         //
506         // To prevent this, just give FUSE 40% max_ratio, meaning it can take
507         // up to 40% of all dirty pages in the system.
508         ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, label), 40u);
509 
510         // All mounts where successful, disable scope guards
511         sdcardfs_guard.Disable();
512         fuse_guard.Disable();
513     }
514 
515     return OK;
516 }
517 
doUnmount()518 status_t EmulatedVolume::doUnmount() {
519     int userId = getMountUserId();
520 
521     if (mFuseMounted) {
522         std::string user_path(StringPrintf("%s/%d", getPath().c_str(), getMountUserId()));
523 
524         // We don't kill processes before trying to unmount in case enhance_fuse_unmount enabled
525         // As we make sure to kill processes if needed if unmounting failed
526         if (!flags::enhance_fuse_unmount()) {
527             // Kill all processes using the filesystem before we unmount it. If we
528             // unmount the filesystem first, most file system operations will return
529             // ENOTCONN until the unmount completes. This is an exotic and unusual
530             // error code and might cause broken behaviour in applications.
531             // For FUSE specifically, we have an emulated volume per user, so only kill
532             // processes using files from this particular user.
533             LOG(INFO) << "Killing all processes referencing " << user_path;
534             KillProcessesUsingPath(user_path);
535         }
536 
537         std::string label = getLabel();
538 
539         if (!IsFuseBpfEnabled()) {
540             // Ignoring unmount return status because we do want to try to
541             // unmount the rest cleanly.
542             unmountFuseBindMounts();
543         }
544 
545         if (flags::enhance_fuse_unmount()) {
546             status_t result = UnmountUserFuseEnhanced(userId, getInternalPath(), label, user_path);
547             if (result != OK) {
548                 PLOG(INFO) << "UnmountUserFuseEnhanced failed on emulated fuse volume";
549                 return result;
550             }
551         } else {
552             if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
553                 PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
554                 return -errno;
555             }
556         }
557 
558         mFuseMounted = false;
559     } else {
560         // This branch is needed to help with unmounting private volumes that aren't set to primary
561         // and don't have fuse mounted but have stacked emulated volumes
562         KillProcessesUsingPath(getPath());
563     }
564 
565     return unmountSdcardFs();
566 }
567 
getRootPath() const568 std::string EmulatedVolume::getRootPath() const {
569     int user_id = getMountUserId();
570     std::string volumeRoot = StringPrintf("%s/%d", getInternalPath().c_str(), user_id);
571 
572     return volumeRoot;
573 }
574 
575 }  // namespace vold
576 }  // namespace android
577