[RFC][PATCH] fs: set xattrs in initramfs from regular files

Casey Schaufler casey at schaufler-ca.com
Fri Nov 23 19:03:54 UTC 2018


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.sassu at 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.sassu at 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();
>  }



More information about the Linux-security-module-archive mailing list