[PATCH v3 2/2] initramfs: introduce do_readxattrs()

Roberto Sassu roberto.sassu at huawei.com
Mon May 20 08:47:27 UTC 2019


On 5/17/2019 10:18 PM, hpa at zytor.com wrote:
> On May 17, 2019 9:55:19 AM PDT, Roberto Sassu <roberto.sassu at 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 at 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



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