Setup Android/, Android/data and Android/obb dirs correctly.

Normally sdcardfs takes care of setting up these directories on-demand,
for example when an app requests its private data directory to be
created. On devices without sdcardfs however, we ourselves need to make
sure to setup the UID/GID of these directories correctly.

Introduce a new PrepareAndroidDirs() function which sets the dirs up
correctly. On devices without sdcardfs, that means:

Path              UID         GID         mode
/Android          media_rw    media_rw     771
/Android/data     media_rw    ext_data_rw  771
/Android/obb      media_rw    ext_obb_rw   771

Bug: 146419093
Test: wipe Android/, reboot, with and without sdcardfs, verify
      contents

Change-Id: I3a879089422c7fc449b6a3e6f1c4b386b86687a4
This commit is contained in:
Martijn Coenen 2020-01-31 15:23:09 +01:00
parent bff86152e5
commit 62a4b279ab
7 changed files with 106 additions and 22 deletions

View file

@ -134,7 +134,7 @@ int SetQuotaProjectId(std::string path, long projectId) {
return ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
}
int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
int ret = 0;
if (!StartsWith(path, root)) {
return -1;
@ -1164,5 +1164,31 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat
return result;
}
status_t PrepareAndroidDirs(const std::string& volumeRoot) {
std::string androidDir = volumeRoot + kAndroidDir;
std::string androidDataDir = volumeRoot + kAppDataDir;
std::string androidObbDir = volumeRoot + kAppObbDir;
bool useSdcardFs = IsFilesystemSupported("sdcardfs");
if (fs_prepare_dir(androidDir.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
PLOG(ERROR) << "Failed to create " << androidDir;
return -errno;
}
gid_t dataGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_DATA_RW;
if (fs_prepare_dir(androidDataDir.c_str(), 0771, AID_MEDIA_RW, dataGid) != 0) {
PLOG(ERROR) << "Failed to create " << androidDataDir;
return -errno;
}
gid_t obbGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_OBB_RW;
if (fs_prepare_dir(androidObbDir.c_str(), 0771, AID_MEDIA_RW, obbGid) != 0) {
PLOG(ERROR) << "Failed to create " << androidObbDir;
return -errno;
}
return OK;
}
} // namespace vold
} // namespace android

10
Utils.h
View file

@ -36,6 +36,11 @@ namespace vold {
static const char* kPropFuse = "persist.sys.fuse";
static const char* kAndroidDir = "/Android/";
static const char* kAppDataDir = "/Android/data/";
static const char* kAppMediaDir = "/Android/media/";
static const char* kAppObbDir = "/Android/obb/";
/* SELinux contexts used depending on the block device type */
extern security_context_t sBlkidContext;
extern security_context_t sBlkidUntrustedContext;
@ -52,8 +57,10 @@ int SetQuotaProjectId(std::string path, long projectId);
/*
* Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'.
* 'path' must start with 'root'
* ONLY for use with app-specific data directories on external storage!
* (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.)
*/
int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid);
int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid);
/* fs_prepare_dir wrapper that creates with SELinux context */
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
@ -164,6 +171,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
status_t UnmountUserFuse(userid_t userId, const std::string& absolute_lower_path,
const std::string& relative_upper_path);
status_t PrepareAndroidDirs(const std::string& volumeRoot);
} // namespace vold
} // namespace android

View file

@ -81,7 +81,9 @@ using android::vold::BindMount;
using android::vold::CreateDir;
using android::vold::DeleteDirContents;
using android::vold::DeleteDirContentsAndDir;
using android::vold::PrepareDirsFromRoot;
using android::vold::IsFilesystemSupported;
using android::vold::PrepareAndroidDirs;
using android::vold::PrepareAppDirsFromRoot;
using android::vold::PrivateVolume;
using android::vold::Symlink;
using android::vold::Unlink;
@ -822,6 +824,29 @@ int VolumeManager::unmountAll() {
return 0;
}
static gid_t getAppDirGid(const std::string& appDir) {
// Create app-specific dirs with the correct UID/GID
gid_t gid = AID_MEDIA_RW;
if (!IsFilesystemSupported("sdcardfs")) {
if (appDir == android::vold::kAppDataDir) {
gid = AID_EXT_DATA_RW;
} else if (appDir == android::vold::kAppObbDir) {
gid = AID_EXT_OBB_RW;
} else if (appDir == android::vold::kAppMediaDir) {
gid = AID_MEDIA_RW;
} else {
gid = AID_MEDIA_RW;
}
}
return gid;
}
static bool isValidAppDirRoot(const std::string& appDirRoot) {
return appDirRoot == android::vold::kAppDataDir || appDirRoot == android::vold::kAppMediaDir ||
appDirRoot == android::vold::kAppObbDir;
}
int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot,
int32_t appUid) {
// Only offer to create directories for paths managed by vold
@ -868,14 +893,25 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi
const std::string lowerAppDirRoot =
volume->getInternalPath() + appDirRoot.substr(volume->getPath().length());
// First create the root which holds app dirs, if needed.
int ret = PrepareDirsFromRoot(lowerAppDirRoot, volume->getInternalPath(), 0771, AID_MEDIA_RW,
AID_MEDIA_RW);
// Do some sanity checking on the app dir (relative from root)
const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0
// eg, if lowerAppDirRoot = /data/media/0/Android/data, this is /Android/data
const std::string relativeAppRoot = lowerAppDirRoot.substr(volumeRoot.length());
if (!isValidAppDirRoot(relativeAppRoot)) {
LOG(ERROR) << path << " is not a valid application directory.";
return -EINVAL;
}
// Make sure the Android/ directories exist and are setup correctly
int ret = PrepareAndroidDirs(volumeRoot);
if (ret != 0) {
LOG(ERROR) << "Failed to prepare Android/ directories.";
return ret;
}
// Then, create app-specific dirs with the correct UID/GID
return PrepareDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, AID_MEDIA_RW);
gid_t gid = getAppDirGid(relativeAppRoot);
return PrepareAppDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, gid);
}
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,

View file

@ -73,17 +73,8 @@ std::string EmulatedVolume::getLabel() {
}
}
// Creates a bind mount from source to target, creating the source (!) directory
// if not yet present.
// Creates a bind mount from source to target
static status_t doFuseBindMount(const std::string& source, const std::string& target) {
if (access(source.c_str(), F_OK) != 0) {
// Android path may not exist yet if users has just been created; create it on
// the lower fs.
if (fs_prepare_dir(source.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
PLOG(ERROR) << "Failed to create " << source;
return -errno;
}
}
LOG(INFO) << "Bind mounting " << source << " on " << target;
auto status = BindMount(source, target);
if (status != OK) {
@ -232,11 +223,19 @@ status_t EmulatedVolume::doMount() {
LOG(INFO) << "Mounting emulated fuse volume";
android::base::unique_fd fd;
int user_id = getMountUserId();
int result = MountUserFuse(user_id, getInternalPath(), label, &fd);
auto volumeRoot = getRootPath();
if (result != 0) {
// Make sure Android/ dirs exist for bind mounting
status_t res = PrepareAndroidDirs(volumeRoot);
if (res != OK) {
LOG(ERROR) << "Failed to prepare Android/ directories";
return res;
}
res = MountUserFuse(user_id, getInternalPath(), label, &fd);
if (res != 0) {
PLOG(ERROR) << "Failed to mount emulated fuse volume";
return -result;
return res;
}
mFuseMounted = true;
@ -252,7 +251,7 @@ status_t EmulatedVolume::doMount() {
}
// Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
status_t res = mountFuseBindMounts();
res = mountFuseBindMounts();
if (res != OK) {
fd.reset();
doUnmount();
@ -317,5 +316,12 @@ status_t EmulatedVolume::doUnmount() {
return OK;
}
std::string EmulatedVolume::getRootPath() const {
int user_id = getMountUserId();
std::string volumeRoot = StringPrintf("%s/%d", getInternalPath().c_str(), user_id);
return volumeRoot;
}
} // namespace vold
} // namespace android

View file

@ -40,6 +40,7 @@ class EmulatedVolume : public VolumeBase {
explicit EmulatedVolume(const std::string& rawPath, int userId);
EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, int userId);
virtual ~EmulatedVolume();
std::string getRootPath() const override;
protected:
status_t doMount() override;

View file

@ -274,6 +274,11 @@ status_t VolumeBase::doFormat(const std::string& fsType) {
return -ENOTSUP;
}
std::string VolumeBase::getRootPath() const {
// Usually the same as the internal path, except for emulated volumes.
return getInternalPath();
}
std::ostream& VolumeBase::operator<<(std::ostream& stream) const {
return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags
<< ",mountUserId=" << mMountUserId << "}";

View file

@ -110,6 +110,8 @@ class VolumeBase {
status_t unmount();
status_t format(const std::string& fsType);
virtual std::string getRootPath() const;
std::ostream& operator<<(std::ostream& stream) const;
protected: