Merge changes I32bfced0,I3178694e,Icb8911f6

* changes:
  Set quota project ID and inheritance on top-level storage directory.
  Set default ACL on application-specific directories.
  Use a regex to create application directories.
gugelfrei
Martijn Coenen 4 years ago committed by Android (Google) Code Review
commit d0d7640403

@ -62,8 +62,11 @@
using android::base::StringPrintf;
using android::fs_mgr::GetEntryForMountPoint;
using android::vold::BuildDataPath;
using android::vold::IsFilesystemSupported;
using android::vold::kEmptyAuthentication;
using android::vold::KeyBuffer;
using android::vold::SetQuotaInherit;
using android::vold::SetQuotaProjectId;
using android::vold::writeStringToFile;
using namespace android::fscrypt;
@ -783,6 +786,14 @@ bool fscrypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_
if (!prepare_dir(vendor_ce_path, 0771, AID_ROOT, AID_ROOT)) return false;
}
if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
// Setup quota project ID and inheritance policy
if (!IsFilesystemSupported("sdcardfs")) {
if (SetQuotaInherit(media_ce_path) != 0) return false;
if (SetQuotaProjectId(media_ce_path, multiuser_get_uid(user_id, AID_MEDIA_RW)) != 0) {
return false;
}
}
if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
if (fscrypt_is_native()) {

@ -33,20 +33,23 @@
#include <dirent.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <mntent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
#include <list>
#include <mutex>
#include <regex>
#include <thread>
#ifndef UMOUNT_NOFOLLOW
@ -74,6 +77,11 @@ static const char* kKeyPath = "/data/misc/vold";
static const char* kProcFilesystems = "/proc/filesystems";
static const char* kAndroidDir = "/Android/";
static const char* kAppDataDir = "/Android/data/";
static const char* kAppMediaDir = "/Android/media/";
static const char* kAppObbDir = "/Android/obb/";
// Lock used to protect process-level SELinux changes from racing with each
// other between multiple threads.
static std::mutex kSecurityLock;
@ -116,6 +124,45 @@ status_t DestroyDeviceNode(const std::string& path) {
}
}
// Sets a default ACL where the owner and group can read/write/execute.
// Other users aren't allowed anything.
int SetDefault770Acl(const std::string& path, uid_t uid, gid_t gid) {
if (IsFilesystemSupported("sdcardfs")) {
// sdcardfs magically takes care of this
return OK;
}
static constexpr size_t size =
sizeof(posix_acl_xattr_header) + 3 * sizeof(posix_acl_xattr_entry);
auto buf = std::make_unique<uint8_t[]>(size);
posix_acl_xattr_header* acl_header = reinterpret_cast<posix_acl_xattr_header*>(buf.get());
acl_header->a_version = POSIX_ACL_XATTR_VERSION;
posix_acl_xattr_entry* entry =
reinterpret_cast<posix_acl_xattr_entry*>(buf.get() + sizeof(posix_acl_xattr_header));
entry[0].e_tag = ACL_USER_OBJ;
entry[0].e_perm = ACL_READ | ACL_WRITE | ACL_EXECUTE;
entry[0].e_id = uid;
entry[1].e_tag = ACL_GROUP_OBJ;
entry[1].e_perm = ACL_READ | ACL_WRITE | ACL_EXECUTE;
entry[1].e_id = gid;
entry[2].e_tag = ACL_OTHER;
entry[2].e_perm = 0;
entry[2].e_id = 0;
int ret = setxattr(path.c_str(), XATTR_NAME_POSIX_ACL_DEFAULT, acl_header, size, 0);
if (ret != 0) {
PLOG(ERROR) << "Failed to set default ACL on " << path;
}
return ret;
}
int SetQuotaInherit(const std::string& path) {
unsigned long flags;
@ -161,44 +208,92 @@ int SetQuotaProjectId(const std::string& path, long projectId) {
return ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
}
int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
int ret = 0;
bool isCacheDir = false;
if (!StartsWith(path, root)) {
return -1;
int PrepareDirWithProjectId(const std::string& path, mode_t mode, uid_t uid, gid_t gid,
long projectId) {
int ret = fs_prepare_dir(path.c_str(), mode, uid, gid);
if (ret != 0) {
return ret;
}
// Cache directories (eg "/storage/emulated/Android/data/com.foo/cache/") need special treatment
isCacheDir = EndsWith(root, "/Android/data/") && EndsWith(path, "cache/");
std::string to_create_from_root = path.substr(root.length());
if (!IsFilesystemSupported("sdcardfs")) {
ret = SetQuotaProjectId(path, projectId);
}
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;
}
if (!IsFilesystemSupported("sdcardfs")) {
long projectId;
// All app-specific directories share the same project-ID, except
// the cache directory
if (isCacheDir && component == "cache") {
// Note that this also matches paths like:
// /Android/data/com.foo/bar/cache/
// This is currently safe because we're never asked to create
// such directories.
projectId = uid - AID_APP_START + AID_CACHE_GID_START;
} else {
projectId = uid - AID_APP_START + AID_EXT_GID_START;
}
ret = SetQuotaProjectId(root, projectId);
return ret;
}
static gid_t getAppDirGid(const std::string& appDir) {
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 ret;
return gid;
}
int PrepareAppDirFromRoot(std::string path, int appUid) {
int ret = 0;
// Extract various parts of the path to setup correctly
// Sample path:
// /data/media/0/Android/data/com.foo/files
// [1]: path in which to create app-specific dir, eg. /data/media/0/Android/data/
// [2]: the part of [1] starting from /Android, eg. /Android/data/
// [3]: the package name part of the path, eg. com.foo
// [4]: the directory to create within [3], eg files
std::regex re("(^/.*(/Android/(?:data|media|obb|sandbox)/))([^/]+)/([^/]+)?/?");
std::smatch match;
bool is_match = regex_match(path, match, re);
if (!is_match) {
LOG(ERROR) << "Invalid application directory: " << path;
return -EINVAL;
}
uid_t uid = appUid;
gid_t gid = getAppDirGid(match.str(2));
// mode = 770, plus sticky bit on directory to inherit GID when apps
// create subdirs
mode_t mode = S_IRWXU | S_IRWXG | S_ISGID;
long projectId = uid - AID_APP_START + AID_EXT_GID_START;
// First, create the package-path
std::string package_path = match.str(1) + match.str(3);
ret = PrepareDirWithProjectId(package_path, mode, uid, gid, projectId);
if (ret) {
return ret;
}
// Set the default ACL, to ensure that even if applications run with a
// umask of 0077, new directories within these directories will allow the
// GID specified here to write; this is necessary for apps like installers
// and MTP, that require access here.
//
// See man (5) acl for more details.
ret = SetDefault770Acl(package_path, uid, gid);
if (ret) {
return ret;
}
// Next, create the directory within the package, if needed
if (match.size() <= 4) {
return OK;
}
if (match.str(4) == "cache") {
// All dirs use the "app" project ID, except for the cache dir
projectId = uid - AID_APP_START + AID_CACHE_GID_START;
}
return PrepareDirWithProjectId(path.c_str(), mode, uid, gid, projectId);
}
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {

@ -36,11 +36,6 @@ 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;
@ -56,13 +51,13 @@ status_t DestroyDeviceNode(const std::string& path);
int SetQuotaInherit(const std::string& path);
int SetQuotaProjectId(const std::string& path, long projectId);
/*
* Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'.
* 'path' must start with 'root'. Sets up quota project IDs correctly.
* Creates and sets up an application-specific path on external
* storage with the correct ACL and project ID (if needed).
*
* ONLY for use with app-specific data directories on external storage!
* (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.)
*/
int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid);
int PrepareAppDirFromRoot(std::string path, int appUid);
/* 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);

@ -82,7 +82,7 @@ using android::vold::DeleteDirContents;
using android::vold::DeleteDirContentsAndDir;
using android::vold::IsFilesystemSupported;
using android::vold::PrepareAndroidDirs;
using android::vold::PrepareAppDirsFromRoot;
using android::vold::PrepareAppDirFromRoot;
using android::vold::PrivateVolume;
using android::vold::Symlink;
using android::vold::Unlink;
@ -823,29 +823,6 @@ 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
@ -889,19 +866,10 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi
// on /storage/emulated/10 means /mnt/user/0/emulated/10
const std::string lowerPath =
volume->getInternalPath() + path.substr(volume->getPath().length());
const std::string lowerAppDirRoot =
volume->getInternalPath() + appDirRoot.substr(volume->getPath().length());
// 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) {
@ -909,8 +877,8 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi
return ret;
}
gid_t gid = getAppDirGid(relativeAppRoot);
return PrepareAppDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, gid);
// Finally, create the app paths we need
return PrepareAppDirFromRoot(lowerPath, appUid);
}
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,

Loading…
Cancel
Save