]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
AOSP: e2fsdroid: read and enforce android's permissions
authorAdrien Schildknecht <adriens@google.com>
Wed, 30 Nov 2016 06:01:52 +0000 (22:01 -0800)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 24 May 2017 02:09:54 +0000 (22:09 -0400)
Set the permissions and the extended attributes as defined by fs_config
and selinux.

Test: create an image with make_ext4 and with mke2fs + e2fsdroid
      Compare the output of:
      for f in `find . | sort`; do
          xattr -l "$f"; md5sum "$f" ls -lah "$f"
      done

Change-Id: I64c97f81c7f5e2bcf3cee3431e410d064cf0735a
From AOSP commit: 4c1e1f46301b3ff7f60be1d8e943ecc23b917ca7

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
contrib/android/Android.mk
contrib/android/e2fsdroid.c
contrib/android/perms.c [new file with mode: 0644]
contrib/android/perms.h [new file with mode: 0644]

index 60186959a8ecdd4ba713b8c377d683b438176e10..ac1285787cbf1243df9c2fb6efc9daec9b2e290a 100644 (file)
@@ -4,13 +4,18 @@ e2fsdroid_src := e2fsdroid.c \
     block_range.c \
     fsmap.c \
     block_list.c \
-    base_fs.c
+    base_fs.c \
+    perms.c
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(e2fsdroid_src)
 LOCAL_MODULE := e2fsdroid
 LOCAL_SHARED_LIBRARIES := libext2fs-host \
-    libext2_com_err-host
+    libext2_com_err-host \
+    libcutils \
+    libbase \
+    libselinux \
+    libcrypto
 include $(BUILD_HOST_EXECUTABLE)
 
 
@@ -18,5 +23,9 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(e2fsdroid_src)
 LOCAL_MODULE := e2fsdroid
 LOCAL_SHARED_LIBRARIES := libext2fs \
-    libext2_com_err
+    libext2_com_err \
+    libcutils \
+    libbase \
+    libselinux \
+    libcrypto
 include $(BUILD_EXECUTABLE)
index 467820672264402d45cd40617f24632117e1abe8..7237030a301efc953d838236181a9c56f22fb428 100644 (file)
@@ -5,6 +5,7 @@
 #include <limits.h>
 #include <ext2fs/ext2fs.h>
 
+#include "perms.h"
 #include "base_fs.h"
 #include "block_list.h"
 
@@ -13,11 +14,18 @@ const char *in_file;
 const char *block_list;
 const char *basefs_out;
 const char *mountpoint = "";
+static time_t fixed_time;
+static char *fs_config_file;
+static char *file_contexts;
+static char *product_out;
+static int android_configure;
 int android_sparse_file = 1;
 
 static void usage(int ret)
 {
-       fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-e] image\n",
+       fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-T timestamp]\n"
+                       "\t[-C fs_config] [-S file_contexts] [-p product_out]\n"
+                       "\t[-a mountpoint] [-e] image\n",
                 prog_name);
        exit(ret);
 }
@@ -40,6 +48,7 @@ static char *absolute_path(const char *file)
 int main(int argc, char *argv[])
 {
        int c;
+        char *p;
        int flags = EXT2_FLAG_RW;
        errcode_t retval;
        io_manager io_mgr;
@@ -47,8 +56,26 @@ int main(int argc, char *argv[])
 
        add_error_table(&et_ext2_error_table);
 
-       while ((c = getopt (argc, argv, "D:B:e")) != EOF) {
+       while ((c = getopt (argc, argv, "T:C:S:p:a:D:B:e")) != EOF) {
                switch (c) {
+               case 'T':
+                       fixed_time = strtoul(optarg, &p, 0);
+                       android_configure = 1;
+                       break;
+               case 'C':
+                       fs_config_file = absolute_path(optarg);
+                       android_configure = 1;
+                       break;
+               case 'S':
+                       file_contexts = absolute_path(optarg);
+                       android_configure = 1;
+                       break;
+               case 'p':
+                       product_out = strdup(optarg);
+                       break;
+               case 'a':
+                       mountpoint = strdup(optarg);
+                       break;
                case 'D':
                        basefs_out = absolute_path(optarg);
                        break;
@@ -75,6 +102,16 @@ int main(int argc, char *argv[])
                return retval;
        }
 
+       if (android_configure) {
+               retval = android_configure_fs(fs, product_out, mountpoint,
+                       file_contexts, fs_config_file, fixed_time);
+               if (retval) {
+                       com_err(prog_name, retval, "%s",
+                               "while configuring the file system");
+                       exit(1);
+               }
+       }
+
        if (block_list) {
                retval = fsmap_iter_filsys(fs, &block_list_format, block_list,
                                           mountpoint);
diff --git a/contrib/android/perms.c b/contrib/android/perms.c
new file mode 100644 (file)
index 0000000..6a54418
--- /dev/null
@@ -0,0 +1,299 @@
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE //asprintf
+#endif
+#include "perms.h"
+#include "support/nls-enable.h"
+#include <time.h>
+#include <sys/stat.h>
+
+#ifndef XATTR_SELINUX_SUFFIX
+# define XATTR_SELINUX_SUFFIX  "selinux"
+#endif
+#ifndef XATTR_CAPS_SUFFIX
+# define XATTR_CAPS_SUFFIX     "capability"
+#endif
+
+struct inode_params {
+       ext2_filsys fs;
+       char *path;
+       char *filename;
+       char *target_out;
+       fs_config_f fs_config_func;
+       struct selabel_handle *sehnd;
+       time_t fixed_time;
+};
+
+static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
+                              const void *value, int value_len)
+{
+       errcode_t retval, close_retval;
+       struct ext2_xattr_handle *xhandle;
+
+       retval = ext2fs_xattrs_open(fs, ino, &xhandle);
+       if (retval) {
+               com_err(__func__, retval, _("while opening inode %u"), ino);
+               return retval;
+       }
+       retval = ext2fs_xattrs_read(xhandle);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while reading xattrs of inode %u"), ino);
+               goto xattrs_close;
+       }
+       retval = ext2fs_xattr_set(xhandle, name, value, value_len);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while setting xattrs of inode %u"), ino);
+               goto xattrs_close;
+       }
+       retval = ext2fs_xattrs_write(xhandle);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while writting xattrs of inode %u"), ino);
+               goto xattrs_close;
+       }
+xattrs_close:
+       close_retval = ext2fs_xattrs_close(&xhandle);
+       if (close_retval) {
+               com_err(__func__, close_retval,
+                       _("while closing xattrs of inode %u"), ino);
+               return retval ? retval : close_retval;
+       }
+       return retval;
+}
+
+static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
+                                  struct inode_params *params)
+{
+       errcode_t retval;
+       char *secontext = NULL;
+       struct ext2_inode inode;
+
+       if (params->sehnd == NULL)
+               return 0;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while reading inode %u"), ino);
+               return retval;
+       }
+
+       retval = selabel_lookup(params->sehnd, &secontext, params->filename,
+                               inode.i_mode);
+       if (retval < 0) {
+               com_err(__func__, retval,
+                       _("searching for label \"%s\""), params->filename);
+               return retval;
+       }
+
+       retval = ino_add_xattr(fs, ino,  "security." XATTR_SELINUX_SUFFIX,
+                              secontext, strlen(secontext) + 1);
+
+       freecon(secontext);
+       return retval;
+}
+
+static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
+                                   struct inode_params *params)
+{
+       errcode_t retval;
+       uint64_t capabilities = 0;
+       struct ext2_inode inode;
+       struct vfs_cap_data cap_data;
+       unsigned int uid = 0, gid = 0, imode = 0;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval, _("while reading inode %u"), ino);
+               return retval;
+       }
+
+       /* Permissions */
+       if (params->fs_config_func != NULL) {
+               params->fs_config_func(params->filename, S_ISDIR(inode.i_mode),
+                                      params->target_out, &uid, &gid, &imode,
+                                      &capabilities);
+               inode.i_uid = uid & 0xffff;
+               inode.i_gid = gid & 0xffff;
+               inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
+               retval = ext2fs_write_inode(fs, ino, &inode);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while writting inode %u"), ino);
+                       return retval;
+               }
+       }
+
+       /* Capabilities */
+       if (!capabilities)
+               return 0;
+       memset(&cap_data, 0, sizeof(cap_data));
+       cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+       cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
+       cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
+       return ino_add_xattr(fs, ino,  "security." XATTR_CAPS_SUFFIX,
+                            &cap_data, sizeof(cap_data));
+}
+
+static errcode_t set_timestamp(ext2_filsys fs, ext2_ino_t ino,
+                              struct inode_params *params)
+{
+       errcode_t retval;
+       struct ext2_inode inode;
+
+       if (params->fixed_time != -1) {
+               retval = ext2fs_read_inode(fs, ino, &inode);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while reading inode %u"), ino);
+                       return retval;
+               }
+               inode.i_atime = 0;
+               inode.i_mtime = inode.i_ctime = params->fixed_time;
+               retval = ext2fs_write_inode(fs, ino, &inode);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while writting inode %u"), ino);
+                       return retval;
+               }
+       }
+
+       return 0;
+}
+
+static int is_dir(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_inode inode;
+
+       if (ext2fs_read_inode(fs, ino, &inode))
+               return 0;
+       return S_ISDIR(inode.i_mode);
+}
+
+static errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
+                                 struct inode_params *params)
+{
+       errcode_t retval;
+
+       retval = set_timestamp(fs, ino, params);
+       if (retval)
+               return retval;
+
+       retval = set_selinux_xattr(fs, ino, params);
+       if (retval)
+               return retval;
+
+       return set_perms_and_caps(fs, ino, params);
+}
+
+static int walk_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
+                   int flags EXT2FS_ATTR((unused)),
+                   struct ext2_dir_entry *de,
+                   int offset EXT2FS_ATTR((unused)),
+                   int blocksize EXT2FS_ATTR((unused)),
+                   char *buf EXT2FS_ATTR((unused)), void *priv_data)
+{
+       __u16 name_len;
+       errcode_t retval;
+       struct inode_params *params = (struct inode_params *)priv_data;
+
+       name_len = de->name_len & 0xff;
+       if (!strncmp(de->name, ".", name_len)
+           || (!strncmp(de->name, "..", name_len)))
+               return 0;
+
+       if (asprintf(&params->filename, "%s/%.*s", params->path, name_len,
+                    de->name) < 0)
+               return -ENOMEM;
+
+       if (!strncmp(de->name, "lost+found", 10)) {
+               retval = set_selinux_xattr(params->fs, de->inode, params);
+               if (retval)
+                       goto end;
+       } else {
+               retval = androidify_inode(params->fs, de->inode, params);
+               if (retval)
+                       goto end;
+               if (is_dir(params->fs, de->inode)) {
+                       char *cur_path = params->path;
+                       char *cur_filename = params->filename;
+                       params->path = params->filename;
+                       ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
+                                           walk_dir, params);
+                       params->path = cur_path;
+                       params->filename = cur_filename;
+               }
+       }
+
+end:
+       free(params->filename);
+       return retval;
+}
+
+errcode_t __android_configure_fs(ext2_filsys fs, char *target_out,
+                                char *mountpoint,
+                                fs_config_f fs_config_func,
+                                struct selabel_handle *sehnd,
+                                time_t fixed_time)
+{
+       errcode_t retval;
+       struct inode_params params = {
+               .fs = fs,
+               .target_out = target_out,
+               .fs_config_func = fs_config_func,
+               .sehnd = sehnd,
+               .fixed_time = fixed_time,
+               .path = mountpoint,
+                .filename = mountpoint,
+       };
+
+       retval = set_selinux_xattr(fs, EXT2_ROOT_INO, &params);
+       if (retval)
+               return retval;
+       retval = set_timestamp(fs, EXT2_ROOT_INO, &params);
+       if (retval)
+               return retval;
+
+       return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
+                                  &params);
+}
+
+errcode_t android_configure_fs(ext2_filsys fs, char *target_out,
+                              char *mountpoint,
+                              char *file_contexts,
+                              char *fs_config_file, time_t fixed_time)
+{
+       errcode_t retval;
+       fs_config_f fs_config_func = NULL;
+       struct selabel_handle *sehnd = NULL;
+
+       /* Retrieve file contexts */
+       if (file_contexts) {
+               struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
+               seopts[0].value = file_contexts;
+               sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+               if (!sehnd) {
+                       com_err(__func__, -EINVAL,
+                               _("while opening file contexts \"%s\""),
+                               seopts[0].value);
+                       return -EINVAL;
+               }
+       }
+
+       /* Load the FS config */
+       if (fs_config_file) {
+               retval = load_canned_fs_config(fs_config_file);
+               if (retval < 0) {
+                       com_err(__func__, retval,
+                               _("while loading fs_config \"%s\""),
+                               fs_config_file);
+                       return retval;
+               }
+               fs_config_func = canned_fs_config;
+       } else if (mountpoint)
+               fs_config_func = fs_config;
+
+       return __android_configure_fs(fs, target_out, mountpoint,
+                                     fs_config_func, sehnd, fixed_time);
+}
diff --git a/contrib/android/perms.h b/contrib/android/perms.h
new file mode 100644 (file)
index 0000000..6342faf
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef ANDROID_PERMS_H
+# define ANDROID_PERMS_H
+
+# include "config.h"
+# include <ext2fs/ext2fs.h>
+
+typedef void (*fs_config_f)(const char *path, int dir,
+                           const char *target_out_path,
+                           unsigned *uid, unsigned *gid,
+                           unsigned *mode, uint64_t *capabilities);
+
+# ifdef _WIN32
+struct selabel_handle;
+static inline errcode_t android_configure_fs(ext2_filsys fs,
+                                            char *target_out,
+                                            char *mountpoint,
+                                            char *file_contexts,
+                                            char *fs_config_file,
+                                            time_t fixed_time)
+{
+       return 0;
+}
+# else
+#  include <selinux/selinux.h>
+#  include <selinux/label.h>
+#  if !defined(HOST)
+#   include <selinux/android.h>
+#  endif
+#  include <private/android_filesystem_config.h>
+#  include <private/canned_fs_config.h>
+
+errcode_t android_configure_fs(ext2_filsys fs, char *target_out,
+                              char *mountpoint,
+                              char *file_contexts,
+                              char *fs_config_file, time_t fixed_time);
+
+# endif
+#endif /* !ANDROID_PERMS_H */