diff options
author | Adrien Schildknecht <adriens@google.com> | 2016-11-29 22:01:52 -0800 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-05-23 22:09:54 -0400 |
commit | 1e43f83f7ab338f64f77299031e0b8bf1b43e034 (patch) | |
tree | 65ad9d296b31780cf9010402b2747661fc13eb34 /contrib | |
parent | ed8e189b38a96cf678e0ef901dd9a3fdb6c133d4 (diff) | |
download | e2fsprogs-1e43f83f7ab338f64f77299031e0b8bf1b43e034.tar.gz |
AOSP: e2fsdroid: read and enforce android's permissions
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>
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/android/Android.mk | 15 | ||||
-rw-r--r-- | contrib/android/e2fsdroid.c | 41 | ||||
-rw-r--r-- | contrib/android/perms.c | 299 | ||||
-rw-r--r-- | contrib/android/perms.h | 38 |
4 files changed, 388 insertions, 5 deletions
diff --git a/contrib/android/Android.mk b/contrib/android/Android.mk index 60186959..ac128578 100644 --- a/contrib/android/Android.mk +++ b/contrib/android/Android.mk @@ -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) diff --git a/contrib/android/e2fsdroid.c b/contrib/android/e2fsdroid.c index 46782067..7237030a 100644 --- a/contrib/android/e2fsdroid.c +++ b/contrib/android/e2fsdroid.c @@ -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 index 00000000..6a544189 --- /dev/null +++ b/contrib/android/perms.c @@ -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(¶ms->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, ¶ms); + if (retval) + return retval; + retval = set_timestamp(fs, EXT2_ROOT_INO, ¶ms); + if (retval) + return retval; + + return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir, + ¶ms); +} + +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 index 00000000..6342faf4 --- /dev/null +++ b/contrib/android/perms.h @@ -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 */ |