Linux-Integrity Archive on lore.kernel.org
 help / Atom feed
From: Roberto Sassu <roberto.sassu@huawei.com>
To: <hpa@zytor.com>, <viro@zeniv.linux.org.uk>
Cc: <linux-security-module@vger.kernel.org>,
	<linux-integrity@vger.kernel.org>, <initramfs@vger.kernel.org>,
	<linux-api@vger.kernel.org>, <linux-fsdevel@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <zohar@linux.vnet.ibm.com>,
	<silviu.vlasceanu@huawei.com>, <dmitry.kasatkin@huawei.com>,
	<takondra@cisco.com>, <kamensky@cisco.com>, <arnd@arndb.de>,
	<rob@landley.net>, <james.w.mcmechan@gmail.com>,
	<niveditas98@gmail.com>
Subject: Re: [PATCH v3 2/2] initramfs: introduce do_readxattrs()
Date: Mon, 20 May 2019 10:47:27 +0200
Message-ID: <2fbe55dc-2f4a-e476-79d0-06931b4f1dee@huawei.com> (raw)
In-Reply-To: <CD9A4F89-7CA5-4329-A06A-F8DEB87905A5@zytor.com>

On 5/17/2019 10:18 PM, hpa@zytor.com wrote:
> On May 17, 2019 9:55:19 AM PDT, Roberto Sassu <roberto.sassu@huawei.com> wrote:
>> This patch adds support for an alternative method to add xattrs to
>> files in
>> the rootfs filesystem. Instead of extracting them directly from the ram
>> disk image, they are extracted from a regular file called .xattr-list,
>> that
>> can be added by any ram disk generator available today. The file format
>> is:
>>
>> <file #N data len (ASCII, 10 chars)><file #N path>\0
>> <xattr #N data len (ASCII, 8 chars)><xattr #N name>\0<xattr #N value>
>>
>> .xattr-list can be generated by executing:
>>
>> $ getfattr --absolute-names -d -h -R -e hex -m - \
>>       <file list> | xattr.awk -b > ${initdir}/.xattr-list
>>
>> where the content of the xattr.awk script is:
>>
>> #! /usr/bin/awk -f
>> {
>>   if (!length($0)) {
>>     printf("%.10x%s\0", len, file);
>>     for (x in xattr) {
>>       printf("%.8x%s\0", xattr_len[x], x);
>>       for (i = 0; i < length(xattr[x]) / 2; i++) {
>>         printf("%c", strtonum("0x"substr(xattr[x], i * 2 + 1, 2)));
>>       }
>>     }
>>     i = 0;
>>     delete xattr;
>>     delete xattr_len;
>>     next;
>>   };
>>   if (i == 0) {
>>     file=$3;
>>     len=length(file) + 8 + 1;
>>   }
>>   if (i > 0) {
>>     split($0, a, "=");
>>     xattr[a[1]]=substr(a[2], 3);
>>     xattr_len[a[1]]=length(a[1]) + 1 + 8 + length(xattr[a[1]]) / 2;
>>     len+=xattr_len[a[1]];
>>   };
>>   i++;
>> }
>>
>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>> ---
>> init/initramfs.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 99 insertions(+)
>>
>> diff --git a/init/initramfs.c b/init/initramfs.c
>> index 0c6dd1d5d3f6..6ec018c6279a 100644
>> --- a/init/initramfs.c
>> +++ b/init/initramfs.c
>> @@ -13,6 +13,8 @@
>> #include <linux/namei.h>
>> #include <linux/xattr.h>
>>
>> +#define XATTR_LIST_FILENAME ".xattr-list"
>> +
>> static ssize_t __init xwrite(int fd, const char *p, size_t count)
>> {
>> 	ssize_t out = 0;
>> @@ -382,6 +384,97 @@ static int __init __maybe_unused do_setxattrs(char
>> *pathname)
>> 	return 0;
>> }
>>
>> +struct path_hdr {
>> +	char p_size[10]; /* total size including p_size field */
>> +	char p_data[];   /* <path>\0<xattrs> */
>> +};
>> +
>> +static int __init do_readxattrs(void)
>> +{
>> +	struct path_hdr hdr;
>> +	char *path = NULL;
>> +	char str[sizeof(hdr.p_size) + 1];
>> +	unsigned long file_entry_size;
>> +	size_t size, path_size, total_size;
>> +	struct kstat st;
>> +	struct file *file;
>> +	loff_t pos;
>> +	int ret;
>> +
>> +	ret = vfs_lstat(XATTR_LIST_FILENAME, &st);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	total_size = st.size;
>> +
>> +	file = filp_open(XATTR_LIST_FILENAME, O_RDONLY, 0);
>> +	if (IS_ERR(file))
>> +		return PTR_ERR(file);
>> +
>> +	pos = file->f_pos;
>> +
>> +	while (total_size) {
>> +		size = kernel_read(file, (char *)&hdr, sizeof(hdr), &pos);
>> +		if (size != sizeof(hdr)) {
>> +			ret = -EIO;
>> +			goto out;
>> +		}
>> +
>> +		total_size -= size;
>> +
>> +		str[sizeof(hdr.p_size)] = 0;
>> +		memcpy(str, hdr.p_size, sizeof(hdr.p_size));
>> +		ret = kstrtoul(str, 16, &file_entry_size);
>> +		if (ret < 0)
>> +			goto out;
>> +
>> +		file_entry_size -= sizeof(sizeof(hdr.p_size));
>> +		if (file_entry_size > total_size) {
>> +			ret = -EINVAL;
>> +			goto out;
>> +		}
>> +
>> +		path = vmalloc(file_entry_size);
>> +		if (!path) {
>> +			ret = -ENOMEM;
>> +			goto out;
>> +		}
>> +
>> +		size = kernel_read(file, path, file_entry_size, &pos);
>> +		if (size != file_entry_size) {
>> +			ret = -EIO;
>> +			goto out_free;
>> +		}
>> +
>> +		total_size -= size;
>> +
>> +		path_size = strnlen(path, file_entry_size);
>> +		if (path_size == file_entry_size) {
>> +			ret = -EINVAL;
>> +			goto out_free;
>> +		}
>> +
>> +		xattr_buf = path + path_size + 1;
>> +		xattr_len = file_entry_size - path_size - 1;
>> +
>> +		ret = do_setxattrs(path);
>> +		vfree(path);
>> +		path = NULL;
>> +
>> +		if (ret < 0)
>> +			break;
>> +	}
>> +out_free:
>> +	vfree(path);
>> +out:
>> +	fput(file);
>> +
>> +	if (ret < 0)
>> +		error("Unable to parse xattrs");
>> +
>> +	return ret;
>> +}
>> +
>> static __initdata int wfd;
>>
>> static int __init do_name(void)
>> @@ -391,6 +484,11 @@ static int __init do_name(void)
>> 	if (strcmp(collected, "TRAILER!!!") == 0) {
>> 		free_hash();
>> 		return 0;
>> +	} else if (strcmp(collected, XATTR_LIST_FILENAME) == 0) {
>> +		struct kstat st;
>> +
>> +		if (!vfs_lstat(collected, &st))
>> +			do_readxattrs();
>> 	}
>> 	clean_path(collected, mode);
>> 	if (S_ISREG(mode)) {
>> @@ -562,6 +660,7 @@ static char * __init unpack_to_rootfs(char *buf,
>> unsigned long len)
>> 		buf += my_inptr;
>> 		len -= my_inptr;
>> 	}
>> +	do_readxattrs();
>> 	dir_utime();
>> 	kfree(name_buf);
>> 	kfree(symlink_buf);
> 
> Ok... I just realized this does not work for a modular initramfs, composed at load time from multiple files, which is a very real problem. Should be easy enough to deal with: instead of one large file, use one companion file per source file, perhaps something like filename..xattrs (suggesting double dots to make it less likely to conflict with a "real" file.) No leading dot, as it makes it more likely that archivers will sort them before the file proper.

Version 1 of the patch set worked exactly in this way. However, Rob
pointed out that this would be a problem if file names plus the suffix
exceed 255 characters.

Roberto

-- 
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Bo PENG, Jian LI, Yanli SHI

  parent reply index

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-17 16:55 [PATCH v3 0/2] initramfs: add support for xattrs in the initial ram disk Roberto Sassu
2019-05-17 16:55 ` [PATCH v3 1/2] initramfs: set extended attributes Roberto Sassu
2019-05-17 16:55 ` [PATCH v3 2/2] initramfs: introduce do_readxattrs() Roberto Sassu
2019-05-17 20:18   ` hpa
2019-05-17 21:02     ` Arvind Sankar
2019-05-17 21:10       ` Arvind Sankar
2019-05-20  8:16         ` Roberto Sassu
2019-05-17 21:47       ` H. Peter Anvin
2019-05-17 22:17         ` Arvind Sankar
2019-05-20  9:39           ` Roberto Sassu
2019-05-22 16:17             ` hpa
2019-05-22 17:22               ` Roberto Sassu
2019-05-22 19:26               ` Rob Landley
2019-05-22 20:21                 ` Taras Kondratiuk
2019-05-17 21:17     ` Rob Landley
2019-05-17 21:41     ` H. Peter Anvin
2019-05-18  2:16       ` Rob Landley
2019-05-22 16:18         ` hpa
2019-05-20  8:47     ` Roberto Sassu [this message]
2019-05-17 23:09   ` kbuild test robot
2019-05-18  1:02   ` kbuild test robot
2019-05-18  5:49   ` kbuild test robot

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2fbe55dc-2f4a-e476-79d0-06931b4f1dee@huawei.com \
    --to=roberto.sassu@huawei.com \
    --cc=arnd@arndb.de \
    --cc=dmitry.kasatkin@huawei.com \
    --cc=hpa@zytor.com \
    --cc=initramfs@vger.kernel.org \
    --cc=james.w.mcmechan@gmail.com \
    --cc=kamensky@cisco.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=niveditas98@gmail.com \
    --cc=rob@landley.net \
    --cc=silviu.vlasceanu@huawei.com \
    --cc=takondra@cisco.com \
    --cc=viro@zeniv.linux.org.uk \
    --cc=zohar@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-Integrity Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-integrity/0 linux-integrity/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-integrity linux-integrity/ https://lore.kernel.org/linux-integrity \
		linux-integrity@vger.kernel.org linux-integrity@archiver.kernel.org
	public-inbox-index linux-integrity


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-integrity


AGPL code for this site: git clone https://public-inbox.org/ public-inbox