From 879fa8015df7092aa8b231fc8a7640b045b44bb5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 11 Feb 2020 12:37:25 +0100 Subject: [PATCH] Set default ACL on application-specific directories. On devices without sdcardfs, application-specific directories have a particular GID that ensure some privileged daemons (like installers) are able to write to them. Android applications however run with a umask of 0077, which means that any subdirectory they create within their app-specific directory has mode 700, which in turn prevents things like DownloadManager from working, since it can be asked to download into a subdir of the app's private storage. To prevent this from happening, set a default 770 ACL on the top-level app-specific directory (eg, /data/media/0/Android/data/com.foo); the effect of that default ACL is that all directories that are created within these directories automatically get a 770 mask, regardless of the umask that the process has. Bug: 146419093 Test: atest FuseDaemonHostTest on cf_x86 (without sdcardfs) Change-Id: I3178694e6d25ce3d04a0918ac66862f644635704 --- Utils.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 04a61d0..6894c6c 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -33,16 +33,18 @@ #include #include #include +#include +#include #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -122,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(size); + + posix_acl_xattr_header* acl_header = reinterpret_cast(buf.get()); + acl_header->a_version = POSIX_ACL_XATTR_VERSION; + + posix_acl_xattr_entry* entry = + reinterpret_cast(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; @@ -232,6 +273,17 @@ int PrepareAppDirFromRoot(std::string path, int appUid) { 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;