OSDN Git Service

Set default ACL on application-specific directories.
authorMartijn Coenen <maco@google.com>
Tue, 11 Feb 2020 11:37:25 +0000 (12:37 +0100)
committerMartijn Coenen <maco@google.com>
Wed, 12 Feb 2020 12:18:44 +0000 (13:18 +0100)
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

index 04a61d0..6894c6c 100644 (file)
--- a/Utils.cpp
+++ b/Utils.cpp
 #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 @@ 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;
 
@@ -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;