Add fixupAppDir() API.

This can be used to fixup application directories in case they have been
created by some other entity besides vold; the main use case for this
API right now is OBB directories, which can be created by installers
outside of vold; on devices without sdcardfs, such directories and the
files contained therein are not setup correctly. This API will make sure
everything is setup the way it needs to be setup.

Bug: 146419093
Test: inspect OBB dir after install
Change-Id: I2e35b7ac2992dbb21cc950e53651ffc07cfca907
This commit is contained in:
Martijn Coenen 2020-02-18 15:06:37 +01:00
parent 442bb83828
commit 816f4d94f6
8 changed files with 84 additions and 6 deletions

View file

@ -167,6 +167,7 @@ cc_library_static {
],
whole_static_libs: [
"com.android.sysprop.apex",
"libc++fs"
],
}

View file

@ -47,6 +47,7 @@
#include <sys/xattr.h>
#include <unistd.h>
#include <filesystem>
#include <list>
#include <mutex>
#include <regex>
@ -228,7 +229,40 @@ int PrepareDirWithProjectId(const std::string& path, mode_t mode, uid_t uid, gid
return ret;
}
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid) {
static int FixupAppDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid, long projectId) {
namespace fs = std::filesystem;
// Setup the directory itself correctly
int ret = PrepareDirWithProjectId(path, mode, uid, gid, projectId);
if (ret != OK) {
return ret;
}
// Fixup all of its file entries
for (const auto& itEntry : fs::directory_iterator(path)) {
ret = lchown(itEntry.path().c_str(), uid, gid);
if (ret != 0) {
return ret;
}
ret = chmod(itEntry.path().c_str(), mode);
if (ret != 0) {
return ret;
}
if (!IsFilesystemSupported("sdcardfs")) {
ret = SetQuotaProjectId(itEntry.path(), projectId);
if (ret != 0) {
return ret;
}
}
}
return OK;
}
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
bool fixupExisting) {
long projectId;
size_t pos;
int ret = 0;
@ -302,7 +336,15 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int
} else {
projectId = uid - AID_APP_START + AID_EXT_GID_START;
}
ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) {
// Fixup all files in this existing directory with the correct UID/GID
// and project ID.
ret = FixupAppDir(pathToCreate, mode, uid, gid, projectId);
} else {
ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
}
if (ret != 0) {
return ret;
}

View file

@ -57,7 +57,8 @@ int SetQuotaProjectId(const std::string& path, long projectId);
* ONLY for use with app-specific data directories on external storage!
* (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.)
*/
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid);
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
bool fixupExisting);
/* 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);

View file

@ -466,6 +466,14 @@ binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t a
return translate(VolumeManager::Instance()->setupAppDir(path, appUid));
}
binder::Status VoldNativeService::fixupAppDir(const std::string& path, int32_t appUid) {
ENFORCE_SYSTEM_OR_ROOT;
CHECK_ARGUMENT_PATH(path);
ACQUIRE_LOCK;
return translate(VolumeManager::Instance()->fixupAppDir(path, appUid));
}
binder::Status VoldNativeService::createObb(const std::string& sourcePath,
const std::string& sourceKey, int32_t ownerGid,
std::string* _aidl_return) {

View file

@ -66,6 +66,7 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
binder::Status remountUid(int32_t uid, int32_t remountMode);
binder::Status setupAppDir(const std::string& path, int32_t appUid);
binder::Status fixupAppDir(const std::string& path, int32_t appUid);
binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
int32_t ownerGid, std::string* _aidl_return);

View file

@ -814,7 +814,7 @@ int VolumeManager::unmountAll() {
return 0;
}
int VolumeManager::setupAppDir(const std::string& path, int32_t appUid) {
int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly) {
// Only offer to create directories for paths managed by vold
if (!StartsWith(path, "/storage/")) {
LOG(ERROR) << "Failed to find mounted volume for " << path;
@ -859,8 +859,21 @@ int VolumeManager::setupAppDir(const std::string& path, int32_t appUid) {
const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0
if (fixupExistingOnly && (access(lowerPath.c_str(), F_OK) != 0)) {
// Nothing to fixup
return OK;
}
// Create the app paths we need from the root
return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid);
return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid, fixupExistingOnly);
}
int VolumeManager::fixupAppDir(const std::string& path, int32_t appUid) {
if (IsFilesystemSupported("sdcardfs")) {
//sdcardfs magically does this for us
return OK;
}
return setupAppDir(path, appUid, true /* fixupExistingOnly */);
}
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,

View file

@ -157,12 +157,23 @@ class VolumeManager {
* requirements of the underlying filesystem and are of no concern to the
* caller.
*
* If fixupExistingOnly is set, we make sure to fixup any existing dirs and
* files in the passed in path, but only if that path exists; if it doesn't
* exist, this function doesn't create them.
*
* 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 setupAppDir(const std::string& path, int32_t appUid);
int setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly = false);
/**
* Fixes up an existing application directory, as if it was created with
* setupAppDir() above. This includes fixing up the UID/GID, permissions and
* project IDs of the contained files and directories.
*/
int fixupAppDir(const std::string& path, int32_t appUid);
int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
std::string* outVolId);

View file

@ -55,6 +55,7 @@ interface IVold {
void remountUid(int uid, int remountMode);
void setupAppDir(@utf8InCpp String path, int appUid);
void fixupAppDir(@utf8InCpp String path, int appUid);
@utf8InCpp String createObb(@utf8InCpp String sourcePath, @utf8InCpp String sourceKey,
int ownerGid);