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
diff --git a/Utils.cpp b/Utils.cpp
index 04a61d0..6894c6c 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -33,16 +33,18 @@
#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>
@@ -122,6 +124,45 @@
}
}
+// 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;
@@ -232,6 +273,17 @@
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;