On 11/22/2018 7:49 AM, Roberto Sassu wrote:
> Although rootfs (tmpfs) supports xattrs, they are not set due to the
> limitation of the cpio format. A new format called 'newcx' was proposed to
> overcome this limitation.
>
> However, it looks like that adding a new format is not simple: 15 kernel
> patches; user space tools must support the new format; mistakes made in the
> past should be avoided; it is unclear whether the kernel should switch from
> cpio to tar.
>
> The aim of this patch is to provide the same functionality without
> introducing a new format. The value of xattrs is placed in regular files
> having the same file name as the files xattrs are added to, plus a
> separator and the xattr name (<filename>.xattr-<xattr name>).
>
> Example:
>
> '/bin/cat.xattr-security.ima' is the name of a file containing the value of
> the security.ima xattr to be added to /bin/cat.
>
> At kernel initialization time, the kernel iterates over the rootfs
> filesystem, and if it encounters files with the '.xattr-' separator, it
> reads the content and adds the xattr to the file without the suffix.

No.

Really, no.

It would be incredibly easy to use this mechanism to break
into systems.
 

> This proposal requires that LSMs and IMA allow the read and setxattr
> operations. This should not be a concern since: files with xattr values
> are not parsed by the kernel; user space processes are not yet executed.
>
> It would be possible to include all xattrs in the same file, but this
> increases the risk of the kernel being compromised by parsing the content.

The kernel mustn't do this.

>
> Signed-off-by: Roberto Sassu <roberto.sa...@huawei.com>
> ---
>  fs/Makefile        |   2 +-
>  fs/readxattr.c     | 171 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/fs.h |   2 +
>  init/main.c        |   1 +
>  4 files changed, 175 insertions(+), 1 deletion(-)
>  create mode 100644 fs/readxattr.c
>
> diff --git a/fs/Makefile b/fs/Makefile
> index 293733f61594..738e1a4e4aff 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -12,7 +12,7 @@ obj-y :=    open.o read_write.o file_table.o super.o \
>               attr.o bad_inode.o file.o filesystems.o namespace.o \
>               seq_file.o xattr.o libfs.o fs-writeback.o \
>               pnode.o splice.o sync.o utimes.o d_path.o \
> -             stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
> +             stack.o fs_struct.o statfs.o fs_pin.o nsfs.o readxattr.o
>  
>  ifeq ($(CONFIG_BLOCK),y)
>  obj-y +=     buffer.o block_dev.o direct-io.o mpage.o
> diff --git a/fs/readxattr.c b/fs/readxattr.c
> new file mode 100644
> index 000000000000..01838f6f1e92
> --- /dev/null
> +++ b/fs/readxattr.c
> @@ -0,0 +1,171 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018 Huawei Technologies Duesseldorf GmbH
> + *
> + * Author: Roberto Sassu <roberto.sa...@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation, version 2 of the
> + * License.
> + *
> + * File: readxattr.c
> + *      Read extended attributes from regular files in the initial ram disk
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/export.h>
> +#include <linux/xattr.h>
> +#include <linux/file.h>
> +#include <linux/cred.h>
> +#include <linux/namei.h>
> +#include <linux/fs.h>
> +
> +#include "internal.h"
> +
> +#define SETXATTR_FILENAME ".setxattr"
> +#define FILENAME_XATTR_SEP ".xattr-"
> +
> +
> +struct readdir_callback {
> +     struct dir_context ctx;
> +     struct path *path;
> +};
> +
> +LIST_HEAD(dir_list);
> +
> +struct dir_path {
> +     struct list_head next;
> +     struct path path;
> +};
> +
> +static int __init read_set_xattr(struct dir_context *__ctx, const char *name,
> +                              int namelen, loff_t offset, u64 ino,
> +                              unsigned int d_type)
> +{
> +     struct readdir_callback *ctx = container_of(__ctx, typeof(*ctx), ctx);
> +     struct path *dir = ctx->path, source_path, target_path;
> +     char filename[NAME_MAX + 1], *xattrname, *separator;
> +     struct dir_path *subdir;
> +     struct file *file;
> +     void *datap;
> +     loff_t size;
> +     int result;
> +
> +     if (!strcmp(name, ".") || !strcmp(name, ".."))
> +             return 0;
> +
> +     result = vfs_path_lookup(dir->dentry, dir->mnt, name, 0, &source_path);
> +     if (result)
> +             return 0;
> +
> +     size = i_size_read(source_path.dentry->d_inode);
> +     if (size > XATTR_SIZE_MAX)
> +             goto out;
> +
> +     if (source_path.dentry->d_inode->i_sb != dir->dentry->d_inode->i_sb)
> +             goto out;
> +
> +     if (!S_ISREG(source_path.dentry->d_inode->i_mode) &&
> +         !S_ISDIR(source_path.dentry->d_inode->i_mode))
> +             goto out;
> +
> +     if (S_ISREG(source_path.dentry->d_inode->i_mode)) {
> +             separator = strstr(name, FILENAME_XATTR_SEP);
> +             if (!separator)
> +                     goto out;
> +
> +             xattrname = separator + sizeof(FILENAME_XATTR_SEP) - 1;
> +             if (strlen(xattrname) > XATTR_NAME_MAX)
> +                     goto out;
> +     } else {
> +             subdir = kmalloc(sizeof(*subdir), GFP_KERNEL);
> +             if (subdir) {
> +                     subdir->path.dentry = source_path.dentry;
> +                     subdir->path.mnt = source_path.mnt;
> +
> +                     list_add(&subdir->next, &dir_list);
> +             }
> +
> +             return 0;
> +     }
> +
> +     file = dentry_open(&source_path, O_RDONLY, current_cred());
> +     if (IS_ERR(file))
> +             goto out;
> +
> +     result = kernel_read_file(file, &datap, &size, 0, READING_XATTR);
> +     if (result)
> +             goto out_fput;
> +
> +     if (separator != name) {
> +             snprintf(filename, sizeof(filename), "%.*s",
> +                      (int)(namelen - strlen(separator)), name);
> +
> +             result = vfs_path_lookup(dir->dentry, dir->mnt, filename, 0,
> +                                     &target_path);
> +             if (result)
> +                     goto out_vfree;
> +
> +             inode_lock(target_path.dentry->d_inode);
> +     } else {
> +             target_path.dentry = dir->dentry;
> +             target_path.mnt = dir->mnt;
> +     }
> +
> +     __vfs_setxattr_noperm(target_path.dentry, xattrname, datap, size, 0);
> +
> +     if (separator != name) {
> +             inode_unlock(target_path.dentry->d_inode);
> +             path_put(&target_path);
> +     }
> +out_vfree:
> +     vfree(datap);
> +out_fput:
> +     fput(file);
> +out:
> +     path_put(&source_path);
> +     return 0;
> +}
> +
> +void __init set_xattrs_initrd(void)
> +{
> +     struct readdir_callback buf = {
> +             .ctx.actor = read_set_xattr,
> +     };
> +
> +     struct dir_path dir, *cur_dir;
> +     struct path path;
> +     struct file *file;
> +     int result;
> +
> +     result = kern_path(SETXATTR_FILENAME, 0, &path);
> +     if (result)
> +             return;
> +
> +     path_put(&path);
> +
> +     result = kern_path("/", 0, &dir.path);
> +     if (result)
> +             return;
> +
> +     list_add(&dir.next, &dir_list);
> +
> +     while (!list_empty(&dir_list)) {
> +             cur_dir = list_first_entry(&dir_list, typeof(*cur_dir), next);
> +
> +             file = dentry_open(&cur_dir->path, O_RDONLY, current_cred());
> +             if (file) {
> +                     buf.path = &cur_dir->path;
> +                     iterate_dir(file, &buf.ctx);
> +                     fput(file);
> +             }
> +
> +             path_put(&cur_dir->path);
> +             list_del(&cur_dir->next);
> +
> +             if (cur_dir != &dir)
> +                     kfree(cur_dir);
> +     }
> +}
> +EXPORT_SYMBOL_GPL(set_xattrs_initrd);
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index c95c0807471f..b04edc1c32e9 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2894,6 +2894,7 @@ extern int do_pipe_flags(int *, int);
>       id(KEXEC_INITRAMFS, kexec-initramfs)    \
>       id(POLICY, security-policy)             \
>       id(X509_CERTIFICATE, x509-certificate)  \
> +     id(XATTR, xattr)        \
>       id(MAX_ID, )
>  
>  #define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
> @@ -3156,6 +3157,7 @@ const char *simple_get_link(struct dentry *, struct 
> inode *,
>  extern const struct inode_operations simple_symlink_inode_operations;
>  
>  extern int iterate_dir(struct file *, struct dir_context *);
> +extern void set_xattrs_initrd(void);
>  
>  extern int vfs_statx(int, const char __user *, int, struct kstat *, u32);
>  extern int vfs_statx_fd(unsigned int, struct kstat *, u32, unsigned int);
> diff --git a/init/main.c b/init/main.c
> index ee147103ba1b..a2f63bc8f9d4 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -1180,5 +1180,6 @@ static noinline void __init kernel_init_freeable(void)
>        */
>  
>       integrity_load_keys();
> +     set_xattrs_initrd();
>       load_default_modules();
>  }

Reply via email to