Replace mkdirs() with setupAppDir().
vold historically offerred functionality to create directories on behalf
of others. This functionality was purely used to create app-specific
data/obb/media dirs. Make this more explicit by renaming the method to
indicate this.
Additionally, in the past, we never needed to care about the UID set on
these directories, because sdcardfs would take care of that for us
automatically. But with sdcardfs going away, we need to make sure the
UID of the app-specific directories is set correctly. Allow the caller
to pass this in as an argument.
Bug: 146419093
Test: atest FuseDaemonHostTest
Change-Id: Ibeb5fdc91b40d53583bc0960ee11c4d640549c34
diff --git a/Utils.cpp b/Utils.cpp
index d483418..67c48ad 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -55,6 +55,7 @@
using namespace std::chrono_literals;
using android::base::ReadFileToString;
+using android::base::StartsWith;
using android::base::StringPrintf;
namespace android {
@@ -114,6 +115,27 @@
}
}
+int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
+ int ret = 0;
+ if (!StartsWith(path, root)) {
+ return -1;
+ }
+ std::string to_create_from_root = path.substr(root.length());
+
+ size_t pos = 0;
+ while ((pos = to_create_from_root.find('/')) != std::string::npos) {
+ auto component = to_create_from_root.substr(0, pos);
+ to_create_from_root.erase(0, pos + 1);
+ root = root + component + "/";
+ ret = fs_prepare_dir(root.c_str(), mode, uid, gid);
+ if (ret) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
diff --git a/Utils.h b/Utils.h
index 4c0114a..056a635 100644
--- a/Utils.h
+++ b/Utils.h
@@ -48,6 +48,12 @@
status_t CreateDeviceNode(const std::string& path, dev_t dev);
status_t DestroyDeviceNode(const std::string& path);
+/*
+ * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'.
+ * 'path' must start with 'root'
+ */
+int PrepareDirsFromRoot(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);
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index b82ea06..78d7ed3 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -456,12 +456,14 @@
return translate(VolumeManager::Instance()->remountUid(uid, remountMode));
}
-binder::Status VoldNativeService::mkdirs(const std::string& path) {
+binder::Status VoldNativeService::setupAppDir(const std::string& path,
+ const std::string& appDirRoot, int32_t appUid) {
ENFORCE_SYSTEM_OR_ROOT;
CHECK_ARGUMENT_PATH(path);
+ CHECK_ARGUMENT_PATH(appDirRoot);
ACQUIRE_LOCK;
- return translate(VolumeManager::Instance()->mkdirs(path));
+ return translate(VolumeManager::Instance()->setupAppDir(path, appDirRoot, appUid));
}
binder::Status VoldNativeService::createObb(const std::string& sourcePath,
diff --git a/VoldNativeService.h b/VoldNativeService.h
index ebd9041..5753b0b 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -65,7 +65,8 @@
binder::Status remountUid(int32_t uid, int32_t remountMode);
- binder::Status mkdirs(const std::string& path);
+ binder::Status setupAppDir(const std::string& path, const std::string& appDirRoot,
+ int32_t appUid);
binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
int32_t ownerGid, std::string* _aidl_return);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 143f53c..bc843b4 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -81,6 +81,7 @@
using android::vold::CreateDir;
using android::vold::DeleteDirContents;
using android::vold::DeleteDirContentsAndDir;
+using android::vold::PrepareDirsFromRoot;
using android::vold::PrivateVolume;
using android::vold::Symlink;
using android::vold::Unlink;
@@ -806,16 +807,21 @@
return 0;
}
-int VolumeManager::mkdirs(const std::string& path) {
+int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot,
+ int32_t appUid) {
// Only offer to create directories for paths managed by vold
- if (StartsWith(path, "/storage/")) {
- std::string lower_path = "/mnt/runtime/default/" + path.substr(9);
- // fs_mkdirs() does symlink checking and relative path enforcement
- return fs_mkdirs(lower_path.c_str(), 0700);
- } else {
+ if (!StartsWith(path, "/storage/")) {
LOG(ERROR) << "Failed to find mounted volume for " << path;
return -EINVAL;
}
+
+ // First create the root which holds app dirs, if needed.
+ int ret = PrepareDirsFromRoot(appDirRoot, "/storage/", 0771, AID_MEDIA_RW, AID_MEDIA_RW);
+ if (ret != 0) {
+ return ret;
+ }
+ // Then, create app-specific dirs with the correct UID/GID
+ return PrepareDirsFromRoot(path, appDirRoot, 0770, appUid, AID_MEDIA_RW);
}
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
diff --git a/VolumeManager.h b/VolumeManager.h
index fad3c00..db32ecd 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -113,13 +113,30 @@
static VolumeManager* Instance();
/*
- * Ensure that all directories along given path exist, creating parent
- * directories as needed. Validates that given path is absolute and that
- * it contains no relative "." or ".." paths or symlinks. Last path segment
- * is treated as filename and ignored, unless the path ends with "/". Also
- * ensures that path belongs to a volume managed by vold.
+ * Creates a directory 'path' for an application, automatically creating
+ * directories along the given path if they don't exist yet. 'appDirRoot'
+ * is the "root" directory for app-specific directories of this kind;
+ * 'path' must always start with 'appDirRoot'.
+ *
+ * Example:
+ * path = /storage/emulated/0/Android/data/com.foo/files/
+ * appDirRoot = /storage/emulated/0/Android/data/
+ *
+ * This function will set the UID of all app-specific directories below
+ * 'appDirRoot' to the 'appUid' argument. In the given example, the UID
+ * of /storage/emulated/0/Android/data/com.foo and
+ * /storage/emulated/0/Android/data/com.foo/files would be set to 'appUid'.
+ *
+ * The UID of the parent directories will be set according to the
+ * requirements of the underlying filesystem and are of no concern to the
+ * caller.
+ *
+ * Validates that given paths are absolute and that they contain no relative
+ * "." or ".." paths or symlinks. Last path segment is treated as filename
+ * and ignored, unless the path ends with "/". Also ensures that path
+ * belongs to a volume managed by vold.
*/
- int mkdirs(const std::string& path);
+ int setupAppDir(const std::string& path, const std::string& appDirRoot, int32_t appUid);
int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
std::string* outVolId);
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 975d94c..cec38c5 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -54,7 +54,7 @@
void remountUid(int uid, int remountMode);
- void mkdirs(@utf8InCpp String path);
+ void setupAppDir(@utf8InCpp String path, @utf8InCpp String appDirRoot, int appUid);
@utf8InCpp String createObb(@utf8InCpp String sourcePath, @utf8InCpp String sourceKey,
int ownerGid);